Grails pass parameter from loop to controller - grails

In Grails I'm trying to delete a record from a (HTML) table, I want to achieve this by passing the ID of the object to the controller. So there is a table in HTML and the user clicks "delete" and the item is deleted from the database. (This logic works according to the unit tests, the problem is passing the ID from view -> controller)
I have tried several solutions found on here such as
<g:each in="${recipe}" var="item">
<tr>
<td>
${item.recipeName}
</td>
<td>
${item.people}
</td>
<td>
<g:link controller="UserRecipe" action="delete" params="[id: '${item.id}']" class="class">Info to Display</g:link></tr>
</g:each>
Which doesn't crash but calls the controller correctly, though the value of the id = null. When I manually edit the url and add /4 for example, the ID will be four. Several solutions on here showed how to pass parameters, but the error arrises when I try to pass a parameter which I access using the ${} notation with these solutions, e.g. using createLink and a params list, it will crash the application because it's a nested ${${}} it seems.

You need to change your params to:
params="[id: item.id]"

Related

Asp.Net MVC validation & knockout foreach

I have a MVC 4 validation & Knockout issue.
I tried this solution :
Translate knockout into razor to keep it's validation working
But i have the same problem as listed in comment of the valid answer => the validation works only for the first element.
After several searches, i found this article on model binding to a list :
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
I am wondering how to merge those two solutions.
Sample with validation working only for the first element :
Dim dummy As ViewModels.ObjectViewModel = Model.MyObjects.FirstOrDefault
#<tbody data-bind='foreach: MyObjects'>
<td>
#Html.TextBoxFor(Function(model) dummy.Label, New With {.data_bind = "value: Label"})
</td>
</tbody>
Sample with validation working, but without the knockout foreach, i can't add items dynamically
<tbody>
#Code
Dim i As Integer = 0
For Each object In Model.MyObjects
#<tr>
<td>
#Html.TextBoxFor(Function(m) Model.MyObjects(i).Label)
</td>
</tr>
i+= 1
Next
End Code
</tbody>
Maybe something with knockout variable : $index() ?
In the past I’ve tried to force combining razor and knockout. But more recently I just opt to go one way or the other. If I’m going to render something on the client side, then I’ll just go ahead and define everything in terms of HTML directly instead of going through razor.
Probably your best bet here is to just define the HTML elements directly. If you need to have validation on place, then just make sure of two things:
Set the corresponding jquery validate attributes (e.g. data-val-true) so that the form validates on the client side.
If you’re submitting data to an ASP.NET MVC Controller make sure the elements have the same name/id as needed by the controller so that the binding takes place on the controller method parameters.
So, after many searches and tests, i have found the solution :
1° Step is to put a correct name for the validation.
Razor View Code :
Dim dummy As ViewModels.ObjectViewModel = Model.MyObjects.FirstOrDefault
<tbody data-bind='foreach: MyObjects'>
<td>
#Html.TextBoxFor(Function(model) dummy.Label, New With {.data_bind = "value: Label, attr: { name: 'MyObjects[' + $index() + '].Label'}"})
</td>
</tbody>
You get this HTML for the first item : name="MyObjects[0].Label"
Which is cool and makes validation work.
But if you add an item dynamically, the validation won't work for the new item.
2° Step is to make the unobstrusive validation re parse your form.
JavaScript
viewModel.addObject = function () {
viewModel.MyObjects.push(new object())
$("form").data("validator", null);
$.validator.unobtrusive.parse($("form"));
};
Those two answers helped me a lot :
Knockout MVC with existing C# code - looping
MVC Model Validation on a dynamic form?

ASP.net MVC DisplayNameFor nested model in view

I have a view in my ASP.net MVC project which is associated to a controller (SubmissionController) and class (Submission).
In the view, I am displaying some values from the class using:
#Html.DisplayFor(Function(model) model.Created)
This works perfectly, but what I want to achieve now, is to be able to get the display name of a Collection nested within the model I reference above.
To make that clearer; I am viewing a single Submission of many Submissions in the view (using the Details function of the SubmissionController). Each submission has many Photos, and it is these photos I want to display in the Submission details view along with the submission details themselves.
To display the photos, I have the following piece of code creating a table of photos...
<tbody>
#For Each item In Model.Photos
Dim currentItem = item
#<tr>
<td>
#Html.DisplayFor(Function(modelItem) currentItem.Photo_ID)
</td>
<td>
#Html.DisplayFor(Function(modelItem) currentItem.Photo_Status1.Value)
</td>
<td>
#Html.DisplayFor(Function(modelItem) currentItem.Photo_Size)
</td>
<td>
#Html.DisplayFor(Function(modelItem) currentItem.Photo_Taken)
</td>
</tr>
Next
</tbody>
Whilst untested, I believe the above code should work just fine.
With this in mind, How on earth do I get the DisplayNameFor values for Photo fields/properties?
This apparently, does not work!
#Html.DisplayNameFor(Function(model) model.Photos.Photo_Size)
By the way, I don't want to write in the header names manually, they must come from the model.
Answer
DigitalD's answer was almost there, here is the solution.
#Dim photoModel = New Photo()
#Html.DisplayNameFor(Function(photoModelx) photoModel.Photo_ID)
#Html.DisplayNameFor(Function(model) model.Photos.Photo_Size) won't work because model.Photos is likely an IEnumerable and doesn't have a Photo_Size property. You might get away with passing in an empty model item like so:
#Dim displayModel = new Photo()
#Html.DisplayNameFor(Function(displayModel) displayModel.Photo_Size)
etc.
If I am understanding correctly, you are trying to get the name of the field you are showing ("Photo Taken", "Photo Size", etc)? If this is the case, I would suggest using DataAnnotations and LabelFor(item=>item.Field). This will give you what you are looking for I believe.

Struts 2: s:if inside s:iterator not working

I have a question regarding struts 2 and s:if tags. As per described on the documentation of s:if the following example was supposed to work:
...
<s:iterator value="questao.alternativas" status="alternativa">
<tr>
<td>
<s:if test="#alternativa.correta == true">Correta!</s:if>
</td>
</tr>
</s:iterator>
...
But this is not working on my case, could you please help? More details:
questao.alternativas is found on the action and it works fine, all "alternativas" are "iterated"!
the getCorreta() method is never call on the example described above.
when using the value true is printed.
Any ideas??
Thanks!
Specifying status in iterator tag will push an instance of IteratorStatus on value stack. You need to consult the documentation of IteratorStatus for valid attributes to use and correta is not a valid attribute. If you want to access the current iteration's object specify a var attribute instead.
Edit for comment:
That's right as Quaternion said you don't need to specify var for accessing current iteration's object. It's already on top of value stack.
Quickly looking at your code I see that you are referencing the status in your conditional(if) statement. Your conditional should directly reference the accessor method of the object in the list your are iterating through, for example:
<s:iterator value="questao.alternativas" status="stat">
<tr>
<td>
// If correta is a boolean value, there is not need to use an
// == operator at all
<s:if test="%{correta}">
Correta!
</s:if>
</td>
</tr>
</s:iterator>
When an iterator traverses a supplied list, assuming questao.alternativas is a list of objects with accessor methods, you directly reference the methods inside your iterator.
The status in an iterator gives you access to the iterator's position. For example, if you want to determine if your loop is at the last element in the list to perform something special you would do something like:
<s:if test="%{#stat.last}">--- END OF LIST ---</s:if>
Or to get the indexed position of the current element in your array or list:
<s:property value=%{#stat.index} />

Razor syntax inside attributes of html elements (ASP MVC 3)

I have a table with repeating customer rows, I would like to add the customer ID to the ID attribute of my table rows like this:
<tr id="row<customer id>"></tr>
I try adding this code:
#foreach(var c in Model) {
<tr id="row#c.id"></tr>
}
Which gives me the following output:
<tr id="row#c.id"></tr>
<tr id="row#c.id"></tr>
etc.
But I would like it to be:
<tr id="row1"></tr>
<tr id="row2"></tr>
etc.
I also tried to add <tr>row#{c.id}</tr> but it did not work..
have you tried <tr>row#(c.id)</tr>?
The actual reason why this doesn't work is because your row#c.id matches the regex for an email address. So the parser assumes it's an email and not actually an attempt to call code. The reason row#{c.id} doesn't work is because the #{} doesn't output and is meant to contain blocks of code.
When in doubt you should use #() as it will force what's contained between the () to be parsed as code.

Parsing Form Post Values From a Table in ASP.NET MVC?

Ok, I'm an MVC newbie coming from a webforms background, so please excuse any ignorance here. Here is my scenario. I've got a table consisting of a list of applications and associated permissions. Each table row consists of 3 pieces of information: a checkbox, some text describing the row, and a dropdown list allowing the user to select the appropriate permission for the application. I want to post this data and only work with the rows in the table which were checked (the id of the row is embedded as the checkbox name). From there, I want to grab the selected value from the DropDownList, and call the necessary code to update the DB. Here is my View page's code:
<%foreach (var app in newApps)
{ %>
<tr>
<td><input type="checkbox" name="AddApps" value="<%=app.ApplicationId %>" /></td>
<td><%=Html.Encode(app.ApplicationName)%></td>
<td><%=Html.DropDownList("AppRole", new SelectList(app.Roles, "RoleId", "RoleDescription"))%></td>
</tr>
<%} %>
How would I retrieve the appropriate values from the FormCollection when I get to the controller on form post? I have done this in the past when I only had checkbox values to retrieve by just calling Request.Form["CheckBoxName"] and parsing the string.
Or am I going about this entirely wrong?
You are halfway right in order to post your data that the controller can read the info it must be inside a form as so :
<% using(Html.BeginForm("Retrieve", "Home")) %>//Retrieve is the name of the action while Home is the name of the controller
<% { %>
<%foreach (var app in newApps) { %>
<tr>
<td><%=Html.CheckBox(""+app.ApplicationId )%></td>
<td><%=Html.Encode(app.ApplicationName)%></td>
<td><%=Html.DropDownList("AppRole", new SelectList(app.Roles, "RoleId", "RoleDescription"))%></td>
</tr>
<%} %>
<input type"submit"/>
<% } %>
and on your controller :
public ActionResult Retrieve()
{
//since all variables are dynamically bound you must load your DB into strings in a for loop as so:
List<app>=newApps;
for(int i=0; i<app.Count;i++)
{
var checkobx=Request.Form[""+app[i].ApplicationId];
// the reason you check for false because the Html checkbox helper does some kind of freaky thing for value true: it makes the string read "true, false"
if(checkbox!="false")
{
//etc...almost same for other parameters you want that are in thr form
}
}
//of course return your view
return View("Index");//this vaires by the name of your view ex: if Index.aspx
}
This site gives more details on how to handle the dropdownlist helper:
http://quickstarts.asp.net/previews/mvc/mvc_HowToRenderFormUsingHtmlHelpers.htm
Request.Form will still work, except that your checkboxes all have the same name.
So one way would be to give the checkboxes distinct names, e.g. "AddApps-app.id", and use Request.Form.
However, a more elegant and testable way is to use list binding.
In this model, you give your form elements a certain structured name, and the default model binder will wrap each set of form elements into a list of typed records in the controller. This is fully explained in this blog post.
The advantage here is that your controller deals only with instances of the application type, and hence has no implicit dependency on the way the view is structured. Therefore, it is very easy to unit test.

Resources