can anybody tell me why this works
<g:each var="n" in="${com.pp.News.list()}">
<h2>${n.t}</h2>
<p>${n.tx}</p>
</g:each>
but this doesn't ?
<g:set var="news" value="${com.pp.News.findAllByShow(true,[sort:'prio', order:'desc',max:5])}" />
<g:each var="n" in="news">
<h2>${n.t}</h2>
<p>${n.tx}</p>
</g:each>
Part of the exception is
Exception Message: No such property: t for class: java.lang.String
How can I make it work?
Thanks
Change
<g:each var="n" in="news">
to
<g:each var="n" in="${news}">
You are iterating over "news" instead of the returned result in the news var.
You should make it work by putting non-UI code in the controller or a service, and passing the data to the views in the model. It's a really bad idea to do database work or other business logic in a GSP/JSP/etc. MVC is about separating concerns.
Related
I have a simple domain something like this:
class Family {
String name_en
String name_fr
}
In a controller I retrieve all the records in that domain with an executiveQuery like this:
def family =Family.executeQuery("select new Map(name_en as name_en, name_fr as name_fr) from Family")
I'm simplify the actual code for the sake of clarity. Then I have a GSP page that show this data, but I want to show based on the language.
So generally I get the language with this code:
<g:set var="lang" value="${org.springframework.web.servlet.support.RequestContextUtils.getLocale(request).getLanguage()}"/>
but how can I select the name based on the language, here I got the en
<g:each in="${family}" status="index" var="record">
${record?.name_en}
</g:each>
I thought I could do something like this, but of course it doesn't work:
${record?.name_`lang`}
I think it would be easiest to use a dynamically generated property name in this case:
${record?."name_${lang}"}
One of the great things about GString & Groovy.
You will need a bunch of if-then-else.
<g:each in="${family}" status="index" var="record">
<g:if test="${lang == 'en'}">
${record?.name_en}
</g:if>
<g:elseif test="${lang == 'fr'}">
${record?.name_fr}
</g:elseif>
</g:each>
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]"
Where the server is sending the client a complex object and the goal is to transition from C#'s 'foreach' to KnockoutJS's 'data-bind="foreach: ' consider this code that populates a shopping cart with various pieces of info:
#{
foreach (var item in GetItems(Model))
{
<dt>
<input type="radio" id='mode_#(item.ID)' name="mode" value="#item.ID" />
#item.Label - $#item.PriceToAdd
</dt>
<dd>
#Html.Raw(item.Explanation) </dd>
}
}
}
Should the server's code be adjusted to flatten out the object before rendering the View or can KnockoutJS deal with unwrapping it? Would it get easier if the server sends JSON?
FOLLOWING UP:
It becomes clear the question boils down to mapping plugin and mfanto's first answer gets me part the way there:
self.items = ko.mapping.fromJS(#Html.Raw(JsonConvert.SerializeObject(Model.Items)));
firebug shows me output of:
self.items = ko.mapping.fromJS([{"ID":60},{"ID":62},{"ID":63},{"ID":64},{"ID":9}]);
Perhaps mapper fails because one of my Items (id=9) has different elements than the rest.
Probably I need to research one of the more advances usages of mapper?
FORMATTED OUTPUT COMPARES VALUES RETURNED BY JsonConvert vs. JavaScriptSerializer
...
self.itemsJSON = ko.mapping.fromJS(#Html.Raw(JsonConvert.SerializeObject(Model.Items)));
self.items = #Html.Raw(new JavaScriptSerializer().Serialize(Model.Items));
when the above code renders to a breakpoint in Firebug:
self.itemsJSON = ko.mapping.fromJS([{"ID":60},{"ID":62},{"ID":63},{"ID":64},{"ID":9}]);
self.items = [ //line breaks inserted for clarity
{"Explanation":"Item1's text.","Label":"Item1's Label","MsgConfirm":null,"PriceToAdd":1255,"TaxExempt":false,"PercentToAdd":0,"SortOrder":1,"ID":60},
{"Explanation":"Item2's text.","Label":"Item2's Label","MsgConfirm":null,"PriceToAdd":1255,"TaxExempt":false,"PercentToAdd":0,"SortOrder":2,"ID":62},
{"Explanation":"Item3's text.","Label":"Item3's Label","MsgConfirm":null,"PriceToAdd":295,"TaxExempt":false,"PercentToAdd":0,"SortOrder":3,"ID":63},
{"Explanation":"Item4's text.","Label":"Item4's Label","MsgConfirm":null,"PriceToAdd":395,"TaxExempt":false,"PercentToAdd":0,"SortOrder":4,"ID":64},
{"Explanation":null,"Label":"[foo]","MsgConfirm":null,"PriceToAdd":150,"TaxExempt":false,"PercentToAdd":0,"SortOrder":99,"ID":9}
];
thx
You don't need to flatten the object before you use Knockout. The ko.mapping plugin will create viewmodels with observable properties, and can handle complex nested objects.
To use it with an ASP.NET MVC model, use #Html.Raw() and a Json serializer (in this case Json.NET:
function AppViewModel() {
var self = this;
self.items = ko.mapping.fromJS(#Html.Raw(JsonConvert.SerializeObject(Model.Items)));
}
ko.applyBindings(new AppViewModel());
From there, you can use foreach:
<table>
<tbody data-bind="foreach: items">
<tr>
<td data-bind="text: PriceToAdd()"></td>
</tr>
</tbody>
</table>
You can go either way with this. Render it on the server with Razor or render it on the client with knockout... The more fundamental question is where do you want to render it. There is no right or wrong answer here.
If you go with knockout, you need to deal with more than just having the server possibly flatten out your model. Knockout will require ajax requests to both read and then save your data and this is where the two solutions fundamentally differ I don't see any JavaScript as part of your solution and without that component, providing a ko solution is pretty impossible.
If you are thinking about using knockout simply as a client side templating engine, then something like jsrender is likely a better solution.
I have a list of domain objects in GSP view and would like to check if any of them are of particular type:
Class Equipment {}
Class Loader extends Equipment {}
... in view:
<g:each in="${Equipment.list()}" var="e">
... check if e is a Loader....
</g:each>
I'm trying to do the check if a GSP fragment to build a nav menu and wonder if this even the right spot to do the check in.
If you're making the logic in a GSP complex like that you should consider creating a taglib instead. It'll be easy to test too - GSPs need to be tested with functional tests and a running web server, but you can test taglibs with integration tests.
You can try:
<g:each in="${Equipment.list()}" var="e">
<g:if test="${e instanceof your.package.Loader}">Do anything</g:if>
</g:each>
Is there a way to break out of a <g:each>? I have a page wherein I'm iterating through a list and I have to make sure that a checkbox is checked if that was the value stored in DB.
To make it a little clearer, please consider something like:
<g:each in=${list1}>
<g:each in=${list2}>
<g:if test="${list1.id == list2.id}">
<input type="checkbox" ... checked="checked" />
</if>
</g:each>
...
</g:each>
where list1 is, say Domain1.list() (i.e. ALL possible values) and list2 is Domain2.find(...) (i.e. SELECTED values)
In the g:each, I need to display ALL of list1 (hence, the "..." after the inner each) with a checkbox but I need to make sure that those in list2 (user-selected items that were saved to DB) should be checked accordingly (if statement).
Now, if the checked status was changed on the first iteration, i need to get out of the inner each... any way to do this?
Thanks!
Nope, not with the each clause.
I'd just write my own taglib that takes list1 and list2 and does the iteration for you, yielding back to the
<g:eachCheckedItem list1="${list1}" list2="${list2}">
<input type="checkbox" ... checked="checked"/>
</g:eachCheckedItem>
And in your taglib class:
def eachCheckedItem = { attrs, body ->
def list1 = attrs.list1
def list2 = attrs.list2
list1.findAll { list2.contains(it) }.each {
out << body(listItem: it) // access to listItem variable inside gsp
}
}
Something like that (tuned to your specific problem) is easy to write, and also cleans up your gsp file quite a bit. I use these kinds of custom iterators all the time in my taglibs.
If I understood you correctly, you need something like this:
<g:each var="elem1" in="${list1}">
<g:if test="${list2.any{it.id==elem1.id}}">
<input type="checkbox" checked="checked" />
</g:if>
...
</g:each>
There is no g:any tag, but as Ted pointed out, it would be easy to write one (left as an exercise to the reader). Then you could simplify the the inner tag to something like this:
<g:any test="${it.id==elem1.id}" in="${list2}">...</g:any>
You should do this in the model, so you then only have a simple loop in the view. Then it's just a matter of making the controller call Domain.findMyList() or whatever.
For the googlers looking for an answer to the original poster's question, there isn't a break command in gsp. There are some better responses here, the best one of which in my opinion is try and make use of .findAll { .. } to find only the set you would expect to work on prior to a 'break'.
http://markmail.org/message/tt2einl3ntwgzdep#query:grails%20gsp%20break%20out%20of%20loop+page:1+mid:nzhgwdsgkrwkurt4+state:results