Grails <g:if> in <g:select> - grails

I have this <g:select> in a .gsp file. But unlike any ordinary <g:select>'s this one would have the attribute disabled="" if a certain condition is met.
Following the code:
<g:select name="test"
from="${["foo1","foo2"]}"
<g:if test="${true}">disabled=""</g:if> />
It returned an error: Grails tag [g:select] was not closed
But when I change it into this:
<g:select name="test"
from="${["mu1","mu2","mu3"]}"
${ if(true) { println "disabled=\"\"" } }/>
It returned this error: Attribute value must be quoted.
Both of the error message are under the exception, org.codehaus.groovy.grails.web.taglib.exceptions.GrailsTagException
The question is how could we make this work? Is there a possible answer without using a custom TagLib?

The GSP form field tags treat disabled as a boolean property, so you can say
<g:select .... disabled="${true}" />
Generally you should be able to use any expression under the usual Groovy-truth rules but I believe it makes a special case for the strings "true" and "false" (the latter would normally be considered true under Groovy-truth rules as a non-empty string). If in doubt you can always say
disabled="${(someExpression) as boolean}"

No need to use the println, try this
<g:select .... ${(conditional)?"disabled":""} ... />

<g:select disabled="${true}"...
is fine but when you submit and it is a required field the value will not be submitted so use this jQuery code to enable the field when pressing the submit button
$(function() {
$('form').on('submit', function() {
$(this).find(':disabled').removeAttr('disabled');
});
});

Related

Is there a way to update textarea 2 simultaneously while typing text in text area 1 using JSF ajax features? [duplicate]

I am trying to implement jQuery with PrimeFaces and JSF components, but it's not working properly. When I tried to do the same with HTML tags it;s working properly.
Here is the code with HTML tags which works properly with jQuery:
<input type="checkbox" id="check2"></input>
<h:outputText value="Check the box, if your permanent address is as same as current address."></h:outputText>
<h:message for="checkbox" style="color:red" />
with
$("#check2").change(function() {
if ($("#check2").is(":checked")) {
$("#p2").hide();
} else {
$("#p2").show();
}
});
Here is the code with PrimeFaces/JSF which doesn't work properly with jQuery:
<p:selectManyCheckbox >
<f:selectItem itemLabel="1" value="one" id="rad" ></f:selectItem>
</p:selectManyCheckbox>
with
$("#rad").change(function() {
if ($("#rad:checked").val() == "one") {
$("#p2").hide();
} else {
$("#p2").show();
}
});
You should realize that jQuery works with the HTML DOM tree in the client side. jQuery doesn't work directly on JSF components as you've written in the JSF source code, but jQuery works directly with the HTML DOM tree which is generated by those JSF components. You need to open the page in webbrowser and rightclick and then View Source. You'll see that JSF prepends the ID of the generated HTML input elements with the IDs of all parent NamingContainer components (such as <h:form>, <h:dataTable>, etc) with : as default separator character. So for example
<h:form id="foo">
<p:selectManyCheckbox id="bar" />
...
will end up in generated HTML as
<form id="foo" name="foo">
<input type="checkbox" id="foo:bar" name="foo:bar" />
...
You need to select elements by exactly that ID instead. The : is however a special character in CSS identifiers representing a pseudo selector. To select an element with a : in the ID using CSS selectors in jQuery, you need to either escape it by backslash or to use the [id=...] attribute selector or just use the old getElementById():
var $element1 = $("#foo\\:bar");
// or
var $element2 = $("[id='foo:bar']");
// or
var $element3 = $(document.getElementById("foo:bar"));
If you see an autogenerated j_idXXX part in the ID where XXX represents an incremental number, then you must give the particular component a fixed ID, because the incremental number is dynamic and is subject to changes depending on component's physical position in the tree.
As an alternative, you can also just use a class name:
<x:someInputComponent styleClass="someClassName" />
which ends up in HTML as
<input type="..." class="someClassName" />
so that you can get it as
var $elements = $(".someClassName");
This allows for better abstraction and reusability. Surely those kind of elements are not unique. Only the main layout elements like header, menu, content and footer are really unique, but they are in turn usually not in a NamingContainer already.
As again another alternative, you could just pass the HTML DOM element itself into the function:
<x:someComponent onclick="someFunction(this)" />
function someFunction(element) {
var $element = $(element);
// ...
}
See also:
How can I know the id of a JSF component so I can use in Javascript
How to use JSF generated HTML element ID with colon ":" in CSS selectors?
By default, JSF generates unusable IDs, which are incompatible with the CSS part of web standards
Integrate JavaScript in JSF composite component, the clean way
You also can use the jQuery "Attribute Contains Selector" (here is the url http://api.jquery.com/attribute-contains-selector/)
For example If you have a
<p:spinner id="quantity" value="#{toBuyBean.quantityToAdd}" min="0"/>
and you want to do something on its object you can select it with
jQuery('input[id*="quantity"]')
and if you want to print its value you can do this
alert(jQuery('input[id*="quantity"]').val());
In order to know the real html tag of the element you can always look at the real html element (in this case spinner was translated into input) using firebug or ie developer tools or view source...
Daniel.
If you're using RichFaces you can check rich:jQuery comonent. It allows you to specify server side id for jQuery component. For example, you have component with specified server id, then you can apply any jQuery related stuff to in next way:
<rich:jQuery selector="#<server-side-component-id>" query="find('.some-child').removeProp('style')"/>
For more info, please check doumentation.
Hope it helps.
look this will help you when i select experience=Yes my dialoguebox which id is dlg3 is popup.and if value is No it will not open

Browser always sends the "noSelection" value of the Grails <g:select> tag library

I have this select input in my gsp:
<g:select id="whitelistId" name="whitelistId" noSelection="${['nx':'-Select whitelist-']}" from="${Whitelist.list()}" optionValue="description" optionKey="id" />
Even if I change to another item in the dropdown, "nx" value is being sent as params value. If I omit noSelection attribute, it works as expected.
This is the generated html code when "My whitelist" item is selected:
<select id="whitelistId" name="whitelistId">
<option value="nx">-Select whitelist-</option>
<option value="6118854">My whitelist</option>
</select>
I'm using Grails 2.2.0
Any tips?
Thanks
ref-doc states:
Typically this will be blank - but you can also use 'null' in the case that you're passing the ID of an object
so, it's better to use
noSelection="${['':'-Select whitelist-']}"
or
noSelection="${[null:'-Select whitelist-']}"

All radioButtons are false at the view

#Html.RadioButton("smth",true)
This row at the page looks like UNCHECKED radioButton. Why?
You should use
HtmlHelper.RadioButton(string name, object value, bool isChecked)
extension method.
First argument is the name of the form field which is input field generated by html helper.
Second argument is the value of input element. If this radio is selected when the postback to server happens, this value is used.
Third argument is what you are looking for. If it is true it makes radio button selected.
For instance,
#Html.RadioButton("Name", "Value" ,true)
would generate an input element which looks like following,
<input checked="checked" id="Name" name="Name" type="radio" value="Value" />
You need to use something of the form
#Html.RadioButton(id,value,checked (bool true/false))
So
#Html.RadioButton("A","B",true)
For example would produce:
<input checked="checked" id="A" name="A" type="radio" value="B" />
The documentation for this is here
In your previous query, you got this answer.
You asked the same query in it's comment section. The problem was that the second line of code was missing one parameter.
Please check below details....
Parameter Details
Razor Syntax
#Html.RadioButton("smth", "smth", true)
#Html.RadioButtonFor( m => m.Prop, true, new { id = "rdBtn" } )

How to find indication of a Validation error (required="true") while doing ajax command

I have a form inside a dialog which I close by clicking on commandbutton with ajax ,
like this
<h:commandButton value="Add" action="#{myBean.addSomething(false)}"
id="add_something_id" >
<f:ajax render="#form someTable" execute="#form"
onevent="closeAddNewSomethingDialogIfSucceeded"></f:ajax>
</h:commandButton>
and here is the js code for closing the dialog
function closeAddNewSomethingDialogIfSucceeded(data) {
if(data.status === 'success') {
$("#dialog_id").dialog("close");
}
}
No problems till here...
Now I changed some of the dialog form fields into required="true" and now I want to prevent the closing of the dialog of i got validation errors...
But the ajax data.status still reaches its success state , and I can't figure out what indication of validation failure I can hook on...
any ideas?
Thanks to BalusC answer I did the following:
in JSF , added :
<h:panelGroup id="global_flag_validation_failed_render">
<h:outputText id="global_flag_validation_failed" value="true"
rendered="#{facesContext.validationFailed}"/>
</h:panelGroup>
the f:ajax was changed into
<f:ajax render="#form someTable global_flag_validation_failed_render"
and in js added the following check
if(data.status === 'success') {
if($("#global_flag_validation_failed").length === 0){
$("#dialog_id").dialog("close");
}
}
Not specifically for required="true", but you can check by #{facesContext.validationFailed} if validation has failed in general. If you combine this with checking if the button in question is pressed by #{not empty param[buttonClientId]}, then you can put it together in the rendered attribute of the <h:outputScript> as follows:
<h:commandButton id="add_something_id" binding="#{add}" value="Add" action="#{myBean.addSomething(false)}">
<f:ajax execute="#form" render="#form someTable" />
</h:commandButton>
<h:outputScript rendered="#{not empty param[add.clientId] and not facesContext.validationFailed}">
$("#dialog_id").dialog("close");
</h:outputScript>
(note that you need to make sure that the script is also re-rendered by f:ajax)
A bit hacky, but it's not possible to handle it in the onevent function as the standard JSF implementation doesn't provide any information about the validation status in the ajax response.
If you happen to use RichFaces, then you could just use EL in the oncomplete attribute of the <a4j:xxx> command button/link. They are namely evaluated on a per-request basis instead of on a per-view basis as in standard JSF and PrimeFaces:
<a4j:commandButton ... oncomplete="if (#{!facesContext.validationFailed}) $('#dialog_id').dialog('close')" />
Or if you happen to use PrimeFaces, then you could take advantage of the fact that PrimeFaces extends the ajax response with an additional args.validationFailed attribute which is injected straight in the JavaScript scope of the oncomplete attribute:
<p:commandButton ... oncomplete="if (args && !args.validationFailed) $('#dialog_id').dialog('close')" />
(note that & is been used instead of &, because & is a special character in XML/XHTML)
Or you could use the PrimeFaces' RequestContext API in the bean's action method to programmatically execute JavaScript in the rendered view.
RequestContext.getCurrentInstance().execute("$('#dialog_id').dialog('close')");
No conditional checks are necessary as the bean's action method won't be invoked anyway when the validation has failed.
Two things
1) Checking for an error in the 'onevent' function
Surely you have a message tag for the mandatory field?
<h:message id="m-my-field-id" for="my-field-id" errorClass="error-class"/>
So you can check for the error-class something like
var message = $('#m-my-field-id');
if(message.hasClass('error-class'){
//do this
}
else{
//do that
}
2) The DOM isn't up to date on success
Yes, I can see the message on the page in Firefox, yet jQuery tells me it is not there.
I have found that using the smallest possible timeout is sufficient to fix this
setTimeout(
function(){
setErrorStyle(source.attr('id'));
},
1
);
I think you should take a look at PrimeFaces' RequestContext. This would help you trigger client-side code on the server side.
#BalusC
in your example code the clientId of the button is not set as a param because it is a AJAX request. So
not empty param[add.clientId] is always false.
But this works:
param['javax.faces.source'] eq add.clientId
(tested with jsf-impl-2.2.12.redhat-1)
regards

translate a HTML select element in Grails

thought this would be easier.... imagine a <g:select /> like this:
<g:select name="type.id" from="${Type.list()}"
value="${domainInstance?.type?.id}" />
with two domain classes like this (please forgive me if these artificial classes are not error free)
class Domain {
Type type
}
class Type {
String name
}
I would now like to translate the entries of the select element. The following code first looked good:
<g:select name="type.id" from="${Type.list()}"
valueMessagePrefix="type.name"
value="${domainInstance?.type?.id}" />
with entries in the messagebundle like this:
type.name.type1 = red
type.name.type2 = green
Problem: not only the text was translated, but the option keys, too!
So I tried to add a optionKey='id':
<g:select name="type.id" from="${Type.list()}"
valueMessagePrefix="type.name"
value="${domainInstance?.type?.id}"
optionKey='id' />
This switched the keys to the id - great, but the text switched to the id, too :-(
Any idea how to solve this?
thanx to grails beeing open source, I just checked the code: http://grails.org/doc/latest/ref/Tags/select.html#select
It seems that valueMessagePrefix is ignored as soon as you use optionKey or optionValue. But optionValue can take a closure:
<g:select name="type.id" from="${Type.list()}"
value="${domainInstance?.type?.id}"
optionKey="id"
optionValue="${ {name->g.message(code:'type.name'+name) } }"/>
at least, this works.
Can't you just add an optionValue?
<g:select name="type.id" from="${Type.list()}"
valueMessagePrefix="type.name"
value="${domainInstance?.type?.id}"
optionKey='id'
optionValue='name'/>
Sorry I haven't had a chance to test this exact code, but have done similar things like this with no problems.

Resources