h:selectBooleanCheckbox not getting set with correct value - jsf-2

Versions :
Aapche MyFaces 2.1.14
RichFaces 4.3.5
Issue :
I am facing very strange issue for JSF2.1
As shown in code snippet at the end , boolean check box is disabled based on boolean variable #{bean.disabled}.
The issue is below :
1)First #{bean.disabled} evaluates to false so checkbox is enabled.
User clicks the checkbox and submits the form (form is not shown here )
2)The action method sets the disabled = true and required= true and same page is rendered again
3)At this stage , UI has check box clicked and disabled. When at this stage , form is
submitted again , bean.setRequired method is called with setter value as FALSE whereas it should set it with value as TRUE
4)When I made disabled="#{false}" , this issue vanished and bean.setRequired method is called with setter value as TRUE
So question is why is the behaviour in step 3 observed even though UI is showing check box in clicked condition (meaning it has a value as TRUE , i also printed the
bean.required value and is evaluating to TRUE only
Code :
<h:panelGroup>
<h:selectBooleanCheckbox id="invite" disabled="#{bean.disabled}" value="#{bean.required}" />
<h:outputText value="Do Update"/>
</h:panelGroup>

Make sure the backing property bound to #{bean.disabled} is a boolean and not a string for which values "TRUE" and "FALSE" are being set.
Also, the behavior you described in step 3 is expected. When the checkbox is disabled, the value submitted will always be false since browsers normally ignore disabled fields during form submit. To make sure you get the right value, maintain a hidden field alongside the checkbox, keep both of them in sync and use the value of the hidden field instead to test if the checkbox is checked or unchecked. Something like below:
<h:selectBooleanCheckbox id="invite" disabled="#{bean.disabled}" value="#{bean.required}" />
<h:inputHidden id="inviteHidden" value="#{bean.requiredHidden}" />
// While setting values, set values for both fields inside the action method
bean.setRequired(true); // ..or false
bean.setRequiredHidden(true); // ..or false
// And to test whether checkbox is checked, do...
if(bean.isRequiredHidden()) {
....
}
Unrelated to your question, if you're using the <c:set/> for conditional rendering, consider using <a4j:outputPanel rendered = "#{someCondition}"/> instead and on your form submit update it (if it is an AJAX submit.

Related

valuechangelistener getting called multiple time

I'm working on icefaces upgrade from 1.8 to 3.3 as well as jsf from 1.2 to 2.0.
I have used this link as reference for icefaces upgrade
I'm using ice:datatable in which I have column of checkbox which is grouped for single worker.Check picture which is of before upgrade.
ISSUE 1:
Now Problem faced after migration is that the valuechangelistener of ice:selectbooleancheckbox works fine when I check then uncheck the checkbox of a single worker. But when I do following steps:
Check first worker (This updates the Assigned door column ).
Then check other worker . This unchecks the previous checked worker and also unchecks currently checked worker.
To analyse if there is any issue in phase I used balus C blog to check phase of icefaces when it hits valuechangelistner . Then I found on my second check 2 or more valuechangelistner are called one for previous worker other for current worker(Sometimes twice) this all happens in same invoke application phase.
ISSUE 2:
ValueChangeListener gets called even after Clicking "OK" button or "CANCEL".
Fixed it by adding f:param in ice:commandButton and checking for the param in valuechangelistener method.
Tried:
To change all ice tags in the page to ace tags(Related to datatable i.e datable ,row and column).
Result : Same issue with ace valuechangelistener as well as distorted style. Maybe because I could not find ice:rowHeader equivalent in ace tags and also much more.
Changed only checkbox column to ace:column. Valuechangelistener worked fine but issue with "groupOn" attribute so changed it to "groupBy" and condition="group" still may be it did not work because I used ice:datatable which doesn't support it.
Then I tried to implement groupOn functionality manually. Using rowspan and rendering single checkbox for single worker . But rowspan didn't work. Also when I tried to render checkbox, its style is not exactly same as I need. Check this hattp://postimg.org/image/ih2mgoh7d/ remove 'a' from 'hattp'.
<ace:column groupBy ="#{item.workerName} + #{item.workerId}" rowspan="2"
styleClass= "alignSBChbx" >
<ice:setEventPhase events="ValueChangeEvent"
phase="INVOKE_APPLICATION">
<ice:selectBooleanCheckbox id="dwaCheckbox" value="#{item.select}"
style=" width:'#{appViewSettings.checkboxSize}';
height:'#{appViewSettings.checkboxSize}';"
valueChangeListener="#{dockWorkerAssignmentBean.doorAssignmentChange}"
partialSubmit="true" immediate="true"
disabled="#{!empty dockWorkerAssignmentBean.errorMap['dockWorkersAssignmentPopup:assignmentErrorField']}"
rendered="#{item.visible}">
<f:attribute name="workerIdSelected" value="#{item.workerId}" />
<f:attribute name="assignmentIdSelected" value="#{item.assignmentId}" />
</ice:selectBooleanCheckbox>
</ice:setEventPhase>
</ace:column>
backend
public final void doorAssignmentChange(final ValueChangeEvent event) {
System.out.println("inside door Assignment...");
final String workerIdSelected = (String) event.getComponent().getAttributes().get(
"workerIdSelected");
// unrelevant code
}
}

How to reset input value if a condition fails Primefaces3.5

I have a problem. I am trying to save a information into the database, and before that I check some conditions like if-else like:
if(condition){
//Some Action
}else{
getFacesContext().addMessage(null,MessageFactory.getMessage(ResourceBundle.FACES_BUNDLE.getName(), FacesBundle.LANDLINE_NUMBER_SHOULD_BE_TEN.getName()));
getExternalContext().getFlash().setKeepMessages(true);
return;
}
and When the condition does not match I would like to restore the previous values of the input field.
In that case, it was 22 in place of ss. but the field does not take input except numbers. So the validation fails and shows an message Invalid Input via growl.
How can I also reset the value of the field ss to 22 in java?
Please suggest!
You can use default validator that comes with JSF
<p:inputText id="number" value="" label="Number">
<f:validateDoubleRange minimum="0" maximum="99" />
</p:inputText>
<p:message for="number" />
But if you reset the filed with old value, user may not know what he's entered. However you will not submit until validation success.
Since the input text component implements EditableValueHolder you can call EditableValueHolder.resetValue() on the input component (or call the more convenient RequestContext.getCurrentInstance().reset(inputTextId)) and then re-render it by calling RequestContext.getCurrentInstance().update(inputTextId) if it isn't already being re-rendered through the update attribute of p:ajax.

p:selectBooleanButton doesn't render preselected value

I been reading / trying examples for hours, and I can't make it work. I'm using Primefaces 4.0
I just need a way to select/unselect and assign those values to a Map
The xhtml looks like this.
<p:selectBooleanButton value="#{presupuestoBean.itemsCambiar[itemPresupuesto.id]}"
onLabel="Yes" offLabel="No" onIcon="ui-icon-check" offIcon="ui-icon-close">
<p:ajax listener="#{presupuestoBean.updateItemPresupuestoAsignado(itemPresupuesto.id,0)}"/>
</p:selectBooleanButton>
Init Method (reset to False just in case, and then assign the true values)
for (ItemPresupuesto itemsPresupuestoDefault : itemsPresupuestoDefaults) {
itemsCambiar.put(itemsPresupuestoDefault.getId(),Boolean.FALSE);
}
assign TRUE values
if (itemPresupuestoAsignado.isCambiar()) {
itemsCambiar.put(itemPresupuestoAsignado.getId(), Boolean.TRUE);
}
and
public Map<Long, Boolean> getItemsCambiar() {
return itemsCambiar;
}
My expected behavior is when the itemsCambiar has some item 'TRUE', the onIcon should be displayed. But it's not happening, all p:selectBooleanButton are displaying as offIcon.
I notice a couple of things while debugging.
The Boolean value assigned at Init, is properly assigned.
If I change the selectBooleanButton for an outputLabel, is showing 'true' (which is correct)
When I change the selectBooleanButton, and the event is fired, I can see that the 'true' value in the HashMap is not a java.lang.Boolean but a java.lang.String (attachment)
So maybe, this problem is related a cast problem, but I'm putting Boolean.TRUE in the map, so ...
any ideas?
Finally I fixed changing ui:repeat to h:datatable, (I don't know why is working).
I have created another question to request some help about it ui:repeat vs h:datatable behavior
Thanks,

How to submit a form with disabled input that got a conversion error

I have the following page/bean structure (using myfaces 2.0.11 + tomcat 6)
I have one checkbox that when checked the h:inputtext (which is connected to an Integer variable in my bean) next to him is enabled and when the checkbox is unchecked the input is disabled, and I have a submit button that submits them both (entire form)
here is the code
<h:form prependId="false">
<h:selectBooleanCheckbox id="my_len" value="#{myBean.myLenBool}">
<f:ajax render="my_len_input_wrapper"/>
</h:selectBooleanCheckbox>
<h:panelGroup id="my_len_input_wrapper">
<h:inputText value="#{myBean.myLen}" id="my_len_input"
disabled="#{not myBean.myLenBool}" required="#{myBean.myLenBool}">
<f:validateLongRange minimum="1"/>
</h:inputText>
<h:message for="my_len_input"/>
</h:panelGroup>
<h:commandButton action="#{myBean.submit}" value="submit">
<f:ajax render="#form" execute="#form"></f:ajax>
</h:commandButton>
</h:form>
Bean code
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class myBean {
Integer myLen;
boolean myLenBool;
public Integer getMyLen() {
return myLen;
}
public void setMyLen(Integer myLen) {
this.myLen = myLen;
}
public boolean isMyLenBool() {
return myLenBool;
}
public void setMyLenBool(boolean myLenBool) {
this.myLenBool = myLenBool;
}
public void submit() {
// submit
}
}
The scenario is as following
1) check the checkbox (the input will be enabled)
2) enter an invalid value (for example 0.5) , its invalid cause myLen is a Integer
3) hit submit -> a error message will be shown in h:message cause of conversion error
4) uncheck the checkbox (it will disable the inputtext)
5) hit submit <--- form is not being submitted cause of the conversion error?!?!
So the question is: how can I submit the form with disabled input that got conversion error???
The only solution I found so far is writing my own custom converter that ignores conversion if the field is disabled
#FacesConverter("APCustomConverter")
public class APCustomConverter extends IntegerConverter{
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (component.getAttributes().get("disabled") != null && component.getAttributes().get("disabled").equals(true)) {
return null;
}
Object retValue = super.getAsObject(context, component, value);
return retValue;
}
}
Was hoping for a better solution than mine (using CustomConverter),
A bit off/not so off topic:
This conversion error eventually had lead me to a really annoying scenario in which: when I used discard button with only render="#form" the state of the checkbox and the input went so wrong that after clicking discard -> the checkbox remained checked (although it shouldn't cause form wasn't really submitted) and the input was disabled and not readonly cause the real checkbox value was false, AND when i hit submit again the checkbox became really checked but the input got himself a null value (all this cause null pointers exception on server), so eventually I had to use <f:actionListener type="org.omnifaces.eventlistener.ResetInputAjaxActionListener" /> by omnifaces in the discard button.
Tested with Mojarra 2.1.26 and MyFaces 2.0.11. When unchecking the checkbox, Mojarra updates the h:inputText and leaves it blank, which is the expected behaviour because the value has never reached the model (validation error). However, MyFaces only updates it to disable mode, leaving the old input value there.
That seems like a MyFaces issue, not solved even in the latest (2.1.12-2.0.18) branch versions. In fact, if you want to skip some element's conversion/validation depending on its state, writing a custom converter/validator is the way to go, but in your case the issue is tied to MyFaces' ajax cycle, which should work as Mojarra's one does.
As a solution you have three possible choices:
Switch to Mojarra implementation if possible, that would make the issue disappear.
Write some JS code in order to reset the input value when the checkbox is unselected.
Go with your current solution, which skips element conversion at server side in case of being disabled.

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