Populating View fields from Controller in Grails - grails

I am trying to load a value into a field on a view from the action on a controller. How do I reference the specific field I want to load? In .NET it would be something like: in the button click event, this.txtName.Text = "John". I don't understand how to do that from a controller and specifically how to reference the view field. I have tried using the params object but it is coming null. I know I am getting to the action based on println statements that I have used.
Here are the relevant code snippets:
from the view:
<td valign="top" class="value ${hasErrors(bean: planetInstance, field: 'name', 'errors')}">
<g:textField name="name" value="${planetInstance?.name}"/>
</td>
<td class="load">
<g:actionSubmit value="Load" action="nameLoad"/>
</td>
from the controller:
def nameLoad = {
// I want to reference and load the "name" textField from the view
}
Any help would be appreciated.

I cannot tell from your code, but you may have forgotten to map the variable name in your controller action nameLoad:
class YourController{
def nameLoad = {
def name = Planet.get(params.id).name //This can be whatever you need it to be to get the correct value assigned to the "name" variable. Here I assume you have a domain class called "Planet" which may or may not be the case.
return [name:name] //This is where you map key/value pairs. The name of the key is what you will type to access the value in your view. The value is the name of the variable you are dealing with, in this case "name".
}
}
With the way the code above is set up Grails will assume there is a view called nameLoad in the folder YourController. So the URL will be something like:
http://localhost:8080/yourapp/yourcontroller/nameload
In that view you will access name like this:
${name}
Which could be used in any number of tags, like the <g:select> tag for instance:
<g:select from="${name}" />

You should be able to access the value of the text field with params.name. If that's not working, you may have a problem with your view. Are the g:textField and g:actionSubmit tags enclosed in a form or g:form?

Related

Assign an object in a form

I have a form which should print questions dynamically. Foo has a Field object and a Field Definition object. I want the Field to have its fieldDefinition assigned by the form. All of the behind the scenes stuff works fine.
The below code works with assigning Strings and Longs in other scenarios.
Here's the line that's causing trouble:
<input th:type="hidden" th:field="*{fields[__${iterationStatus.index}__].fieldDefinition}" th:value="${fooViewModel.fields[__${iterationStatus.index}__].fieldDefinition}"/>
This is what it looks like when it renders in html:
<input type="hidden" value="com.blah.domain.FieldDefinition#fbb2e392" id="fields0.fieldDefinition" name="fields[0].fieldDefinition">
When I submit the form, no controller action is invoked, and the app simply redirects to the error page.
If it's impossible to actually do the assignment that way, please suggest other methods. The only way I came up with is to have Foo use the FieldDefinitionService to do the assignment after being passed an ID. I don't that Domain class to have access to another Domain object's Service.
Thanks
Just an example: when you need to iterate a form inside an element that has a th:each attribute, you can use the following structure (so far, it's the only way that's working for me).
<tr th:each="rank, stat : ${ranks}">
<td th:text="${rank.name}">This is static</td>
<td th:text="${rank.description}">This is static</td>
<td>
<form th:action="#{/user/ranks/delete}" method="post">
<input type="hidden" id="id" name="id" th:value="${rank.id}"></input>
<button class="btn btn-danger" type="submit">
<span>Delete</span>
</button>
</form>
</td>
</tr>
Here ranks is a list of entities that have to be displayed on a table and, for each entity, there is a delete button associated to a form.
The controller method should be similar to the following fragment, the parameter is availabled with the name id:
#RequestMapping(path = "/delete", method = RequestMethod.POST)
public View deleteRank(Model model, #RequestParam(name = "id") String rankId,
#ModelAttribute("user") User user)
{
Long id = Long.parseLong(rankId);
// delete ...
RedirectView redirectView = new RedirectView("/user/ranks");
return redirectView;
}

How to Send a Javascript Variable to a Grails Controller to Query Neo4J

I'm a newbie trying to find uses for Neo4J on Grails.
Basically, I've made 20 grocery item nodes through the Neo4J browser and I want to create a simple Grails site that will let users search a grocery item and visually show the items related to it.
My index.gsp has:
<input id="item" />
My viz.js has:
$('#item').keyup(function() {
var item = $('#item').val();
My Item Domain class has
class Item {
static mapWith = "neo4j"
String name
My ItemController class has:
def index() {
def item = Item.list() [item:item] //No idea, just trying out whatever i find :(
and a query with something like:
def query = Item.cypherStatic ("""start n=node({Item}) match (n)-[r]->(x) where r='partner' return n, x)
Questions:
How can I properly send the JS 'item' variable into the ItemController?
How can I use the 'item' variable to properly query the node names which have a 'partner' relationship with the item?
in addition to Motilals answers, you definetly need a wrapping form with an action that points your controller
like
<g:form controller="itemController" action="index" >
<input type="text" id="item" name="item" value="" />
<input type="submit" value="submit" >
</g:form>
then on clicking submit the for will call your index action and there you could parse the value with
def item = params.item
but it looks more like you want some asynchronous stuff right after keyup-function, therefore you could do sth like this :
$('#item').keyup(function() {
var item = $('#item').val();
$.ajax({
url: "${createLink(controller:'itemController', action:'index')}",
data:"&item="+item
})
.done(function( data ) {
console.log(data)
});
});
in this case, you need to pay attention what your index-action is returning, so you can do in the .done() whatever you want with the response.
also note, that when you name an action "index" it will be available at
.../myproject/item/index
or, and thats important
.../myproject/item/
so if your index method requires the data from the input, it will miss them if a user has gone straight to that url
so your index action would rather render the page with the input
and you define another action for executing your query based on input and returning data
set the item to hidden field and then you can access it directly in your controller using params
here you go:
//in index.gsp add below hidden field and set the hidden filed in your js code
<g:hiddenField name="item" value="" />
$('#item').keyup(function() {
var item = $('#item').val();
//in your controller
def index() {
def item = params.item
print item // you see the value for item
//do your stuff
}
once you have item value you could directly use HQL query or use the domain instance
hope this helps you
Regards
Motilal

Grails - communicating between controllers and views

I'm wondering how I can populate a text box in my view from a list in my controller, I have been searching for examples for awhile, but haven't really found anything. I'm uncertain on how to access the text field from the view exactly, where as in Java you could do something as simple as jTextField.getText(). I'm also wondering on how to grab the text in my text box as well.
Below I'll post some example code of what I'm doing.
Controller:
def loadFile = {
def propFile = "c:/props.txt"
def propMap = [:]
def propList = []
new File(propFile).eachLine { line ->
def (key,value) = line.split(':').collect { it.trim() }
propMap."$key" = "$value"
if(propMap) {
propList << propMap
propMap = [:]
}
}
}
def saveFile = {
//get contents of text box
//over-write props.txt with new information
}
View:
<g:textField name="properties"/>
<span class="menuButton"/><g:link action="loadFile" controller="myController">Load File</g:link>
<span class="menuButton"/><g:link action="saveFile" controller="myController">Save File</g:link>
So, my question seems relatively straight forward, how do I access the text box when I want to populate it and save the data from it?
.
.
.
EDIT
After checking out some of the examples submitted by you guys, I have one last question.
Why does the following code act different when clicking the Load File button?
<g:form controller="drive">
<g:textArea name="properties" value="${params.param1}" rows="50" cols="6"/>
<br/>
<g:submitButton name="loadFile" value="Load File"/>
<g:submitButton name="saveFile" value="Save File"/>
</g:form>
<span class="menuButton"/><g:link action="loadFile" controller="drive">Load File</g:link>
When clicking the g:submitButton dealing with loadFile it redirects me to the list gsp. However, when I click the menuButton it loads the textArea with the text from the file. The reason I ask is because with the second option, the button isn't located where I would like it to be.
Wrap your text field in form tag. This way, when you submit it, you can access your field in controller.
<g:form controller="myController" action="saveFile">
<g:textField name="properties"/>
<g:submitButton name="saveFile" value="Save File" />
</g:form>
Then, you can access your properties field in controller:
def saveFile = {
def properties = params.properties
// do whatever you need
}
EDIT:
To address some of the issues that came up later in comments, I'll try to provide some more insight.
Let's assume that your controller is called Drive and view (the form to submit properties) is drive/properties.gsp. If want your load button to load your properties into the text area, you can do something like this:
def loadFile = {
// your code here
render(view: 'properties.gsp', model=[properties:propList])
}
And in your view:
<g:form controller="drive">
<g:textArea name="properties" value="${properties?.join("\n")}" rows="50" cols="6"/>
<br/>
<g:actionSubmit name="loadFile" action="loadFile" value="Load File"/>
<g:actionSubmit name="saveFile" action="saveFile" value="Save File"/>
</g:form>
This should render your form with values from your file, each property in new line. But I didn't test it.
jjczopek's answer shows how to get access to the data in the controller after it has been submitted from the view.
You can pass a default value through from the controller to the view by setting a parameter in the controller eg...
params.param1 ='value to pass'
render(view:"testView")
Then in your view you can retrieve it again with...
<g:textField name="text1" value="${params.param1}"/>
You may also find this question and these docs useful.
If want to pass domain objects through then one of the following specific render methods might be better...
Grails Controller - Render

ASP.NET MVC View Messages

I am using FluentValidation to validate my models, and it works awesome.
One question I have though is how do you handle messages that are not attached to a property?
Example: A customer login view. When the login is invalid I want to display a simple message.
What I did was add a property to the model, Message, and then created a validation message for that property on the view.
It works, but was looking to see what others are doing.
Update
So for simplicity, consider the following:
View Model
'Uses a FluentValidation Validator
Public Class LogonViewModel
Public Property UserName AS String<br>
Public Property Password AS String
End Class
View
<div id="GenericMessage">--Generic Messages Go Here--</div>
#<table border="0" cellpadding="2" cellspacing="0">
<tr>
<td>User Name:</td>
<td>#Html.EditorFor(Function(x) x.UserName) #Html.ValidationMessageFor(Function(x) x.UserName)</td>
</tr>
<tr>
<td>Password:</td>
<td>#Html.EditorFor(Function(x) x.Password) #Html.ValidationMessageFor(Function(x) x.Password)</td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Logon" /></td>
</tr>
</table>
What I want to do is have a generic message div that I can display messages in, like "Invalid Login". My question is where to I put that in the model? Do I create a property and then set it in the controller ModelState? Or should I be using ViewData?
Any reason you aren't using the ModelState for your errors?
For example, if your view model has a datetime property and a user enters something like "blah", the ModelState will automatically have that error returned when you render the view again.
That error can be retrieved in the Validation Summary...
<%: Html.ValidationSummary() %>
Or you can bind it to specific form elements.
<%: Html.ValidationMessageFor(m => m.Birthdate) %>
You can also manually add error messages to the ModelState in your controller.
// for a specific property
ModelState.AddModelError("Birthdate", "You can't use this date!")
// to show in summary
ModelState.AddModelError("", "Dates are too close!")
If you are just after a way to communicate things from your controller to your view (other than errors), then I think it's fine to add a property to your viewModel, assign it a value in your controller, and then access it in your view.
And I don't see anything wrong with doing this for errors if ModelState isn't meeting your needs.
One question I have though is how do you handle messages that are not attached to a property?
As far as I understood from that question is you do not give any hint to framework to validate the input. right? if so, do it that way.
put the following code on your view;
#Html.ValidationSummary()
and validate your input inside the post action method. if it is not valid, add the error message to view state. here is an example;
if (captchaValid == false) {
ModelState.AddModelError("recaptcha", "Invalid characters on securty code! Please try it again");
return View(model);
}
Although I think I like better the Modelstate answers what I usually do is to define things like this in my _Layout.cshtml:
#if(TempData["Error"]!=null)
{
<div class="error">#TempData["Error"]</div>
}
#if(TempData["Warning"]!=null)
{
<div class="warning">#TempData["Warning"]</div>
}
then I only have to assign TempData["Error"] or TempData["Warning"] in my controller.

Checkbox HTML Helper

I've been working on an ASP.net MVC project that uses checkbox HTML Helpers in one of the views. The problem I'm trying to resolve is maintaining the checkbox state on a page refresh or when a user hits to he back button on their browser. I'm trying to use the HTML helper as a start, but I lack a complete understanding of how it works. I'm stuck on the third parameter that asks for HTML attributes. A snippet from a form that I have is as follows:
<tr>
<td><label for="Name">Name</label></td>
<td><%= Html.Encode(entity.CONTACT_NAME)%></td>
<td><input type="checkbox" name="Name" value="<%= Html.Encode(entity.CONTACT_NAME)%>"/> </td>
<td><%= Html.CheckBox("Name", false, new {#name = Html.Encode(entity.CONTACT_NAME)}) %></td>
</tr>
To avoid confusion, I have an object called entity that I declare before my form, that has several string values, one of which is CONTACT_NAME. I have a separate, standard, html checkbox right above the HTML Helper for testing purposes. When my form POSTs, I get the value if I select the standard checkbox, if I select the helper I get only true.
What I want to know is, how I can get
the value like I do when I select the
standard checkbox?
And how can I
maintain the checkbox state on page
refresh??
Any help is appreciated, thanks.
UPDATE:
#NickLarsen - Looked at the HTML code that was generated, the value is "false"
Made changes as per anthonyv's and JonoW's suggestions, my View is now as follows:
<tr>
<td><label for="Name">Name</label></td>
<td><%= Html.Encode(entity.CONTACT_NAME)%></td>
<td><%= Html.CheckBox("Name", false, new {#value = Html.Encode(entity.CONTACT_NAME)}) %></td>
</tr>
But the generated HTMl still shows the value as a boolean "false" instead of the actual CONTACT_NAME.
As per NickLarsen's suggestion, here is the code in my controller that checks the values.
public ActionResult ProcessRequest(Request request, FormCollection form)
{
var aChangeRequest = new ChangeRequest();
TryUpdateModel(aChangeRequest, new string[] { "Name" },form.ToValueProvider());
//Way more follows
}
should "#name" be "#value"? It looks like you are trying to set the name twice...
I'm pretty sure you want to have the following:
<%= Html.CheckBox("Name", false, new {#value = Html.Encode(entity.CONTACT_NAME)}) %>
If you have 2 inputs with the same name, they will be posted as a list of values (which MVC is going to try convert to a boolean value). So it's probably going to distort your test by having 2 elements with the same name, would suggest changing one of the names.

Resources