p:selectBooleanButton doesn't render preselected value - jsf-2

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,

Related

h:selectBooleanCheckbox not getting set with correct value

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.

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.

Expanding behavior of Richfaces Collapsible Panel

So, I have recently started working on a JSF page using richfaces 4, in which I have a rich:collapsiblePanel. I face a problem however, I am using the collapsiblePanel within a rich:dataGrid, which renders the collapsiblePanels by iterating though a list recieved from the server. There is a link to 'sort' the collapsiblePanels according to the data in the panel header (in the backing bean of course). When any of the collapsiblePanels are expanded, and the sort link is clicked, all of them are expanded, whilst all are expanded, if one is closed, and the link clicked again, all of them close.
Things I have tried:
Changing the switchType to any other than client (i.e ajax and server)
Adding a constant boolean in the backing bean to force the expand attribute to false on reload (although it is not even affected by the backing bean at all)
Sample code of what it looks like at the moment:
<h:panelGrid id="SomePanelGrid">
<rich:dataGrid id="SomeDataGrid" value="bean.listValues" var="values"
iterationStatusVar="counter" elements="10">
<rich:collapsiblePanel switchType="client" expanded="#{bean.expanded}">
Layouts and what not (not in relation to this)
</rich:collapsiblePanel>
</rich:dataGrid>
</h:panelGrid>
The link simply calls a method in the backing bean which does the sorting.
I have found a similar problem, involving a dataTable instead of a dataGrid, although no answers have been given, but only links that lead to more dead ends. This can be found at: https://community.jboss.org/message/819938
Any help would be greatly appreciated. Unfortunately I do not have alot of time to answer alot of other questions at the moment, but I will be checking back a bit later.
Thanks in advance.
You have many syntax flaws inside your code, here is how it should looks like :
<h:panelGrid id="SomePanelGrid">
<rich:dataGrid id="SomeDataGrid" value="#{bean.listValues}" var="values"
iterationStatusVar="counter" elements="10">
<rich:collapsiblePanel switchType="client" expanded="#{bean.expanded}">
Layouts and what not (not in relation to this)
</rich:collapsiblePanel>
</rich:dataGrid>
</h:panelGrid>
You are probably experiencing only one collapsiblePanel in your example, this code modified and tested work properly.
Now if you want to save collapsiblePanels expanded state when refreshing your dataGrid by AJAX, you need to add some stuff.
First, you need to add one property to your objects you are iterating on, to save the state of each panels.
public class Item
{
private boolean expanded;
public void setExpanded(boolean expanded)
{
this.exanded = expanded;
}
public boolean getExpanded()
{
return this.expanded;
}
// Your other stuff
}
Second, you need to add a listener in your bean to know when user changes the state of a panel, note the attribute to get back which item is related to this panel.
#ManagedBean
#ViewScope
public class Bean
{
private List<Item> listValues;
#PostConstruct
void init()
{
listValues = //... Some initialization to your list
}
public List<Item> getListValues()
{
return this.listValues;
}
public void toggle(PanelToggleEvent event)
{
// Take the current item
Item item = (Item)event.getComponent().getAttributes().get("item");
// Save the current state in the item
item.setExpanded(event.getExpanded());
}
}
Finally, you need to change your switchType to AJAX and add the listener in your code without forgetting the attribute that need to be passed in the listener.
<h:form>
<rich:dataGrid id="SomeDataGrid" value="#{bean.listValues}" var="item"
iterationStatusVar="counter" elements="10">
<rich:collapsiblePanel switchType="ajax" expanded="#{item.expanded}">
<f:attribute name="item" value="#{item}" />
Layouts and what not (not in relation to this)
</rich:collapsiblePanel>
</rich:dataGrid>
</h:form>

How to detect a field value change in a JSF 2.0 page

I am using JSF 2.0 to develop a pretty big and complex page which contains numerous fields. Thre would be quit command button at the buttom of the page and when ever user selects the quit option I need to detect whether user has entered any value on one of the fields of the page.
I am using the null check of each field values in the backing bean to do that now, but that's a very tedious and repeative job. I was wondering is there any smart solution for that ?? Any help will be highly appreciated.
Thanks in advance.
For that the valueChangeListener attribute is meant to be used.
<h:inputText ... valueChangeListener="#{bean.changed}" />
with
public void changed(ValueChangeEvent event) {
this.changed = true;
}
Your field-values are probably linked to properties of the backing-bean. When the value is changed, the setter is invoked. Inside the setter you could set a boolean field of the bean to true, if the value actually changed.
public void setPropertyX(Type newValue) {
if(!newValue.equals(this.X)) {
this.X = newValue;
this.fieldChanged = true;
}
}
For this to work, you backing-bean should be at least in #ViewScope.

Value not retained for action parameter when inside ui:repeat

Below is my Code:
<ui:repeat var="status" value="#{showUpdatedAction.statusUpdates}">
<h:panelGroup>
#{status.content}
<h:form>
<h:commandLink value="Like" action="#{statusAction.likeStatus(status.id,1)}" />
</h:form>
</h:panelGroup>
<ui:repeat>
#{status.content} shows correct values. When I print id of status using #{status.id}, it also gives correct value. But when I click the command link, value passed is always 0 for status.id.
Can someone tell me why this happens and how can I avoid this?
Thank you.
Edit 1
Interestingly, when instead of passing the parameter in function, I pass it using <f:param>, it works perfectly. Can anyone comment on that?
I think you should try using <c:forEach> instead of <ui:repeat>.
I can't tell you exactly, why status.id is 0 in your case but you can directly pass the whole status object in your EL expression. Like so:
<h:commandAction value="Like" action="#{statusAction.likeStatus(status)}" />
Then in your likeStatus you simply do a int statusId = status.getId() or similar and you have what you want.
As an addition: Using <c:forEach> should actually be just a fallback, because people say you shouldn't mix JSTL with JSF for whatsoever reasons.
Your code in the JSF page is just fine, just checked it... (generated the beans at my side too : showUpdatedAction, statusAction , and a simple class Status)
public void likeStatus(String id,long someVal){
System.out.println(id+"___"+someVal);
}
which prints the ids just fine
id1___1
id4___1
Maybe its something to do with the type of the id or something with your beans?

Resources