Grails 2.0 update select with submitToRemote and render - grails

I face a problem using Grails 2 submitToRemote tag.
The following code is what I use in the controller:
def getProposal = {
def layouts = importService.getLayoutsFor(params.product as int)
render(contentType: "text/xml") {
for (layout in layouts) {
option("${layout}")
}
}
}
and in the GSP:
<g:submitToRemote action="getProposal" update="layouts"
onLoading="showProgress();" onComplete="hideProgress();"
value="Do It" />
<select id="layouts" name="layout" required="">
</select>
Using jquery this results in:
showProgress();;jQuery.ajax({type:'POST',data:jQuery(this).parents('form:first').serialize(), url:'/app/controller/getProposal',success:function(data,textStatus){jQuery('#layouts').html(data);},error:function(XMLHttpRequest,textStatus,errorThrown){},complete:function(XMLHttpRequest,textStatus){hideProgress();}});return false
which not works and returns am error:
Node cannot be inserted at the specified point in the hierarchy
But if I use another render method like:
render(status: 0, text: "<option value='1'>Layout 1</option>")
it works.
In both cases the expected answer is transmitted back.
I did not understand why it will not work with the first nicer method. Could anyone explain what I do wrong?
Thx
Edit:
I noted that if I use render(contentType: "text/text") instead it will work. May be it has something to do, that the xml is not properly formatted (no root node?). But why does it work in Grails 1.3.7?

Grails 1.3.7 had a different default javascript provider (prototype). The jquery ajax call trys to infer the type of the response based on what it receives

Related

withForm causing 'Too Many Redirect' error on Grails 2.2.4

I can not get withForm to work, and it has me stumped. I am using grails 2.2.4 (we won't be upgrading to a higher version for several months, but I'd like to add useToken="true" to my forms.
Here is my simple working method:
def browse () {
def model =[:]
model += [ attr1: "attr1", attr2: "attr2"]
}
In the gsp, I simply print out the values of the attributes:
<g:form name='filterForm' action="browse" id='filterForm' method="post"
useToken="true">
browse.gsp values:
${attr1.toString()}
${attr2.toString()}
</g:form>
The above gsp prints out:
browse.gsp values: attr1 attr2
Now, when I add a withForm into the controller method:
def browse () {
withForm {
def model =[:]
model += [ attr1: "attr1", attr2: "attr2"]
}.invalidToken{ response.status = 405}
}
I get a 'too many redirects' error.
The page does not require authentication, the only mapping it would fall under is the generic
"/$controller/$action?/$id?" {
constraints {
// apply constraints here
}
}
The controller has no before or after interceptor set up.
This is happening on my local system where I am using GGTS as the IDE.
I have the same problem on Chromium and Firefox
Actually, this is not the problem. Apparently in creating a trimmed down example, I caused another issue. I then thought the redirects were the root cause, but after more debugging I see that it is not related.
My original problem was that withForm was not returning any data from the model to the gsp, which was causing the gsp generation to fail. I am not sure what is causing my stripped down version to get too many redirects, but it doesn't really matter at this point.
So, I've opened a new question with my real problem, and am just answering this one so that folks don't spend a lot of time on this issue.

MVC Razor conditional code causing error?

I have the following code in a Razor view where I want to only display an address if the first piece is available.
#if (!string.IsNullOrWhiteSpace(Model.Address1))
{
#Model.Address1<br />
#Model.Address2<br />
#Model.City, #Model.State #Model.Zip
}
However, it's giving me a design time error saying "Can not use local variable 'Model' before it is declared".
I've done some searching on the syntax and as far as I can tell it looks correct but obviously I'm missing something. Can anyone see why this would work?
UPDATE
It's a little clunky looking but this is what I ended up with.
#if (!string.IsNullOrWhiteSpace(Model.Address1))
{
#:#Model.Address1<br />
if (!string.IsNullOrWhiteSpace(Model.Address2))
{
#:#Model.Address2<br />
}
#:#Model.City, #Model.State #Model.Zip
}
You're writing HTML which is being parsed as C# code, with confusing results.
The contents of a code block (such as #if) are parsed as code, not HTML.
Therefore, #Model.City, #Model.State #Model.Zip becomes a malformed variable declaration.
You need to wrap it in an HTML tag or <text>, or prefix each line with #:.

grails current page highlight

In grails I have a menu. I'm trying to highlight the menu item for the active page:
link1
link2 (show as bold if the controller action partially matches this gsp name)
link3
I have working code but it seems like there would be a better way.
Taglib works fine:
def active = { attrs, body ->
for (page in attrs.check) {
if (params.action.startsWith(page)) {
out << "current"
break
}
}
}
This option works fine, but seems wordy:
<li>Contact Info</li>
<li>About You</li>
This blows up:
<g:link action='myProfile' class="${<xyz:active check='${['myControllerAction']}'/>}">My Profile</g:link>
I don't believe you can pass a taglib as a parameter to g:link
I also have the requirement that multiple gsps/actions would cause a link to be active because of how they are named:
aboutYouLocation
aboutYouBackground
aboutYouEducation
all make this link the active one:
About You
I can do a partial match, but I've also got some actions/gsps that begin with aboutYour (extra R) resulting in my use of the array being passed into my taglib.
There's a standard way of doing that with the Platform Core plugin. It will provide you a Navigation API:
grails-app/conf/AppNavigation.groovy
navigation = {
// Declare the "app" scope, used by default in tags
app {
contact(action: 'contactInfo')
about(action: 'aboutYouFamily')
}
}
*grails-app/view/_menu.gsp* (template that you can use in your layout or GSP's)
<nav:menu scope="app" id="navigation" />
You can also customize the html generated for your menu, check the custom item rendering.

Grails "bean:input" (bean fields) showing the wrong bean property

Since we've updated to grails 2.0.1 (from 2.0.0) all of our beans shown via bean fields are incorrectly displayed as the first property of that "withBean" field. In the example I've posted below, all of [firstName, lastName, dateOfBirth, contactNumber] are shown as just 'firstName' (we know it's not just the messages which are wrong because otherwise the 3rd property (dateOfBirth) would be a date picker, not just a text field).
Any potential workarounds or suggestions?
(plugins.bean-fields=1.0-RC3)
I encountered the same problem, and have a work-around.
I has customised beanfield templates extracted into a gsp template called /shared/_beanfieldConfig.gsp , which I then included by rendering before calling any beans tags. e.g.
<g:render template="/shared/beanFieldConfig" />
<bean:withBean beanName='command'>
<bean:input property='username' />
This worked nicely in 1.3.7, and meant I could share beanFieldConfig between views.
When upgrading to 2.0.3, I enountered the same issue as the original question. I've found I can work around this by inlining the content of my _beanFieldConfig in each view.
Yuk, but at least it means I don't need rewrite all my views to use the replacement plugin (yet).
(edit)
Interestingly, although beanField config in a render'd template doesn't work, sticking it in a taglib DOES.
so, while previously I had in beanFieldConfig
<bean:inputTemplate>
<div class='input ${errors ? 'errors' : '' }'>
${label}
${field}
<g:if test="${errors}">
${errors}
</g:if>
</div>
</bean:inputTemplate>
If I define the equivalent tag -
def beanFieldConfig = {
bean.inputTemplate { m ->
m.with {
""" <div class='input ${errors ? 'errors' : '' }'>
${label}
${field}
${errors ?: ''}
</div>"""}
}
}
and then in my gsp replace <g:render template="/shared/beanFieldConfig" /> with <g:beanFieldConfig/>, it works.

Grails: checkbox not being set back to false

I am developing a Grails (1.0.4) app where I want to edit a collection of collections on a single page in a grid view. I got it to work quite well depending only on the indexed parameter handling of Spring MVC, except for one thing:
boolean (or, for that matter, Boolean) values in the grid can be set via checkbox, but not unset, i.e. when I check the checkbox and update, the value is set to true, but afterwards when I edit again, uncheck the checkbox and update, it remains true.
This is the GSP code of the checkbox:
<g:checkBox name="tage[${indexTag}].zuweisungen[${indexMitarb}].fixiert" value="${z.fixiert}" />
And this is the HTML that is generated:
<input type="hidden" name="tage[0].zuweisungen[0]._fixiert" />
<input type="checkbox" name="tage[0].zuweisungen[0].fixiert" checked="checked" id="tage[0].zuweisungen[0].fixiert" />
I've found a Grails bug that describes exactly this effect, but it's marked as fixed in 1.0.2, and the problem mechanism described there (underscore in hidden field name is put in the wrong place) is not present in my case.
Any ideas what could be the reason?
This is the solution a guy named Julius Huang proposed on the grails-user mailing list. It's reusable but relies on JavaScript to populate a hidden field with the "false" response for an unchecked checkbox that HTML unfortunately does not send.
I hack GSP to send "false" when
uncheck the box (true -> false) with
custom TagLib.
By default checkBox send nothing when
uncheck, so I use the checkBox as
event handler but send hidden field
instead.
"params" in Controller can handle
"false" -> "true" without any
modification. eg. Everything remain
same in Controller.
The Custom Tag Usage in GSP (sample usedfunc_F is "true"),
<jh:checkBox name="surveyList[${i}].usedfunc_F" value="${survey.usedfunc_F}"></jh:checkBox>
Here is what the Tag generate,
<input type="hidden" name="surveyList[#{i}].usedfunc_F" id="surveyList[#{i}].usedfunc_F" value="false" />
<input type="checkbox" onclick="jhtoggle('surveyList[#{i}].usedfunc_F')" checked="checked" />
The Javascript
<script type="text/javascript">
function jhtoggle(obj) {
var jht = document.getElementById(obj);
jht.value = (jht.value !='true' ? 'true' : 'false');
}
</script>
This is my own solution, basically a workaround that manually does what the grails data binding should be doing (but doesn't):
Map<String,String> checkboxes = params.findAll{def i = it.key.endsWith("._fixiert")} // all checkboxes
checkboxes.each{
String key = it.key.substring(0, it.key.indexOf("._fixiert"))
int tagIdx = Integer.parseInt(key.substring(key.indexOf('[')+1, key.indexOf(']')))
int zuwIdx = Integer.parseInt(key.substring(key.lastIndexOf('[')+1, key.lastIndexOf(']')))
if(params.get(key+".fixiert"))
{
dienstplanInstance.tage[tagIdx].zuweisungen[zuwIdx].fixiert = true
}
else
{
dienstplanInstance.tage[tagIdx].zuweisungen[zuwIdx].fixiert = false
}
}
Works, requires no change in grails itself, but isn't reusable (probably could be made so with some extra work).
I think that the simplest workaround would be to attach a debugger and see why Grails is failing to populate the value. Considering Grails is open source you'll be able to access the source code and once you figure out the solution for it you can patch your version.
I have also found this other bug GRAILS-2861 which mentions the issue related to binding to booleans (see Marc's comment in the thread). I guess that is exactly the problem you are describing.
I would create a small sample app that demonstrates the problem and attach it to the Grails bug (or create a new one). Someone here may be able to debug your sample app or you'll have shown the bug isn't really fixed.
Try this out, set the logs to DEBUG, frist try the first 3 if they don't show the problem up, flip them all to DEBUG:
codehaus.groovy.grails.web.servlet="error" // controllers
codehaus.groovy.grails.web.pages="error" // GSP
codehaus.groovy.grails.web.sitemesh="error" // layouts
codehaus.groovy.grails."web.mapping.filter"="error" // URL mapping
codehaus.groovy.grails."web.mapping"="error" // URL mapping
codehaus.groovy.grails.commons="info" // core / classloading
codehaus.groovy.grails.plugins="error" // plugins
codehaus.groovy.grails.orm.hibernate="error" // hibernate integration
This should allow you to see exactly when and how the parameters setting is failing and probably figure out a work around.

Resources