Checkbox inside ui:repeat not refreshed by Ajax - jsf-2

I work with Mojarra 2.1.3.
When the user click on button "refresh don't work", it refresh the content of the ui:repeat.I expect the checkbox to be checked, just as at the initialization.
What I've found: If I remove h:head in the facelet "refresh don't work" works... Any idea ?
The facelet:
<h:head></h:head>
<h:body>
<h:form id="myForm" >
<h:panelGroup id="panelToRefreshOutsideRepeat">
<ui:repeat value="#{sandbox.columns}" var="column">
<h:panelGroup id="panelToRefreshInsideRepeat">
<h2>composite onlyCheckbox:</h2>
<trc:onlyCheckbox value="#{column.value}" />
<br />
<h2>composite onlyInputText:</h2>
<trc:onlyInputText value="#{column.value}" />
<br />
<br/>
<h:commandButton value="Refresh don't work" >
<f:ajax render="panelToRefreshInsideRepeat" />
</h:commandButton>
<h:commandButton value="Refresh work" >
<f:ajax render=":myForm:panelToRefreshOutsideRepeat" />
</h:commandButton>
</h:panelGroup>
<br/>
</ui:repeat>
</h:panelGroup>
The composite for onlyCheckbox and onlyInputText:
<composite:interface>
<composite:attribute name="value"
type="boolean"/>
</composite:interface>
<composite:implementation>
boolean: <h:selectBooleanCheckbox value="#{cc.attrs.value}" />
<!-- for onlyInputText h:inputText instead of h:selectBooleanCheckbox -->
boolean value: #{cc.attrs.value}
</composite:implementation>
and the backing bean:
#ManagedBean
#RequestScoped
public class Sandbox {
public List<Column> columns = Arrays.asList(new Column(true));
public List<Column> getColumns() {
return columns;
}
public void setColumns(List<Column> columns) {
this.columns = columns;
}
public class Column {
private boolean value;
public Column(boolean value) {
this.value = value;
}
public void setValue(boolean value) {
this.value = value;
}
public boolean getValue() {
return this.value;
}
}
}

I can reproduce your problem even on latest Mojarra 2.1.4. It works fine if the checkbox is not inside a composite. This is a bug in Mojarra's <ui:repeat>. It is totally broken in Mojarra. It works perfectly fine on MyFaces 2.1.3.
You have 2 options:
Replace Mojarra by MyFaces.
Use an UIData component instead of <ui:repeat>, e.g. <h:dataTable>, <t:dataList>, <p:dataList>, etc.

Related

why action in <h:commandLink> doesn't work inside a composite component

I have a very simple JSF 2/Facelets page that looks like this:
<ui:repeat value="#{myBean.names}" var="_name">
<h:commandLink value="#{_name}" action="#{myBean.sayHello(_name)}">
<f:ajax execute="#this"/>
</h:commandLink>
<br/>
</ui:repeat>
The backing bean provides a java.util.List<String> with names and the action-method just prints a "hello <name>" message to standard output.
This works fine. I get a list of names in the browser and a click fires the action-method that says hello to the specified name.
The Problem arises, when I want to put this code in a composite component that does the iteration and renders the actual link via a facet:
<ui:component xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:cc="http://xmlns.jcp.org/jsf/composite">
<cc:interface>
<cc:attribute name="value" type="java.util.List" required="true" />
<cc:facet name="content" />
</cc:interface>
<cc:implementation>
<ui:repeat value="#{cc.attrs.value}" var="_name">
<cc:renderFacet name="content"/>
</ui:repeat>
</cc:implementation>
</ui:component>
I use the composite component like this:
<my:myComp value="#{bean.names}">
<f:facet name="content">
<h:commandLink value="#{_name}" action="#{bean.sayHello(_name)}">
<f:ajax execute="#this"/>
</h:commandLink>
<br/>
</f:facet>
</my:myComp>
In the browser I get a list of names that looks exactly like before. But clicking a link now renders a "hello null" message. So _name is resolved correctly in the value attribute of <h:commandLink> but not in the action attribute.
I also tried using actionListener instead of action or the listener attribute from the <f:ajax> tag with no difference.
Could anybody shade some light on this issue?
My environment:
WildFly 8.1 with
JSF 2.2.6 (Mojarra)
The issue has to do with the scope of the variable in this case _name which is evaluated once when the <ui:repeat/> is being processed. In my case, I ran your code and it produced Hello John even though their were other names in my list. To get around this, I introduced a <f:param/> that would contain the value of the _name, and modified your code as follows:
<h:form>
<my:myComp value="#{bean.names}">
<f:facet name="content">
<h:commandLink value="#{_name}" action="#{bean.sayHello()}">
<f:param name="name_" value="#{_name}"/>
<f:ajax execute="#this"/>
</h:commandLink>
<br/>
</f:facet>
</my:myComp>
</h:form>
I also modified the sayHello() method as follows for a #RequestScoped bean:
#ManagedProperty(value = "#{facesContext}")
private FacesContext facesContext;
public void setFacesContext(FacesContext facesContext) {
this.facesContext = facesContext;
}
public void sayHello() {
Map<String, String> params = facesContext.getExternalContext()
.getRequestParameterMap();
String name = params.get("name_");
System.out.println("Hello " + name);
}
You could change this to something shorter in a #ViewScoped bean to:
public void sayHello() {
Map<String, String> params = FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap();
String name = params.get("name_");
System.out.println("Hello " + name);
}
The final result is that it prints out the names correctly.

validator for custom components in JSF fails

In my custom component, I have
<composite:interface>
<composite:editableValueHolder name="val_pwd" targets="form:pwd"/>
<composite:attribute name="name" required="true"/>
.....
</composite:interface>
<composite:implementation>
<h:form id="form">
<h:panelGrid columns="3">
<h:outputText value="#{cc.attrs.namePrompt}" />
<h:inputText value="#{cc.attrs.name}" id="name"/>
<h:outputText value="#{cc.attrs.passwordPrompt}" />
<h:inputSecret value="#{cc.attrs.pwd}" id="pwd"/>
<h:commandButton value="#{cc.attrs.submitButtonValue}" action="#{cc.attrs.actionMethod}"/>
</h:panelGrid>
</h:form>
</composite:implementation>
I have a validator,
#FacesValidator("passwordVal")
public class PasswordValidator implements Validator {
public PasswordValidator() {
super();
}
#Override
public void validate(FacesContext facesContext, UIComponent uIComponent, Object object) throws ValidatorException {
if(object instanceof String){
String s = (String) object;
if(s.contains("#"))
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error","Password cannot have #"));
}
}
}
In my JSF page, I have
<h:body>
<util:ccwithcustomval namePrompt="r_Name" passwordPrompt="r_pwd" name="#{person.name}"
pwd="#{person.pwd}" actionMethod="#{person.action}" submitButtonValue="r_submit">
<f:validateLength for="val_name" maximum="5"/>
<f:validator validatorId="passwordVal" for="val_pwd" />
</util:ccwithcustomval>
</h:body>
However, it fails with exception
InputComponent.xhtml #12,60 <f:validator> ADF_FACES-60085:Parent not an instance of
EditableValueHolder: javax.faces.component.UINamingContainer#4e18afaa
The problem is with my validator, if I comment it out the page displays

JSF 2: Ajax not firing in nested composite components

I have the main page with includes testcomponent1 which inturn includes testcomponent2. Ajax call is in testcomponent2. The call is intiated in the javascript but never hits the controller. If the ajax call is moved into testcomponent1, it triggers the call and makes it to the controller. I am including the test code for your reference.
TESTCONTROLLER:
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.AjaxBehaviorEvent;
#ManagedBean
#ViewScoped
public class TestController implements Serializable {
/** <code>serialVersionUID</code> */
private static final long serialVersionUID = -999213365169849345L;
private int customerkey;
private String customerName;
public void processKeyChange(AjaxBehaviorEvent e){
System.out.println("I am in the Ajax method and my value is: " + customerkey);
}
//GETTERS AND SETTERS
public int getCustomerkey() {
return customerkey;
}
public void setCustomerkey(int customerkey) {
this.customerkey = customerkey;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
}
testPage.xhtml
<ui:define name="searchCriteria">
<h:form id="orderHeaderForm" prependId="false">
<h:panelGroup id="orderDiv" layout="block">
<com:testcomponent1 id="testComponent1"
customerKey="#{testController.customerkey}"
customerName="#{testController.customerName}"/>
</h:panelGroup>
</h:form>
</ui:define>
</ui:composition>
testcomponent1.xhtml
<cc:interface>
<cc:attribute name="customerKey" type="java.lang.Integer" />
<cc:attribute name="customerName" type="java.lang.String" />
</cc:interface>
<cc:implementation>
<h:panelGroup id="#{cc.clientId}" layout="block">
<com:testcomponent2 id="testcomponent2"
key="#{cc.attrs.customerKey}"
name="#{cc.attrs.customerName}" />
</h:panelGroup>
</cc:implementation>
testcomponent2.xhtml
<cc:implementation>
<h:panelGrid id="#{cc.clientId}" columns="2" border="0" cellspacing="0" cellpadding="0">
<h:outputLabel id="customerid" for="txtcustomerKey"/>
<h:inputText id="txtcustomerKey" value="#{cc.attrs.key}" onchange="alert (document.getElementById(this.id).value)">
<f:ajax event="change" listener="#{testController.processKeyChange}" execute="#this" render="txtCustomerName" />
</h:inputText>
<h:outputLabel id="customerName" for="txtCustomerName"/>
<h:outputText value="#{cc.attrs.name}" id="txtCustomerName" />
</h:panelGrid>
</cc:implementation>
thanks
I think the problem is in <h:panelGrid id="#{cc.clientId}"...>. By default, a composite component is an instance of UINamingContainer, so instead do that, you can set an id with any name and use it. A good practice is avoid EL expressions in id field.
You shouldn't reassign #{cc.clientId} as ID of JSF components, but instead as ID of plain vanilla HTML elements such as <span> or <div>.
<span id="#{cc.clientId}">
or
<div id="#{cc.clientId}">

javax.el.ELException: Can't set property 'propertyName' on class 'com.example.MrBean' to value 'null'

In my .xhtml file, I have the following SelectOneMenu component:
<ui:define name="formContent">
<h:selectOneMenu value="#{mrBean.itemCategoryID}">
<f:ajax render="abc def" execute="#this" listener="#{mrBean.getListOfItems}"></f:ajax>
<f:selectItem itemLabel="Choose one .." itemValue="0" noSelectionOption="true" />
<f:selectItems value="#{mrBean.itemCategories}" var="ic"
itemLabel="#{ic.name}" itemValue="#{ic.id}" />
</h:selectOneMenu>
<h:panelGrid id="abc" columns="3" border="1">
<h:outputText style="font-weight: bold" value="Name"/>
<h:outputText style="font-weight: bold" value="Producer" />
<h:outputText />
</h:panelGrid>
<h:panelGroup id="def" >
<ui:repeat value="#{mrBean.items}" var="i">
<h:form id="BuyItemForm">
<h:panelGrid columns="3" border="1">
<h:outputText style="font-weight: normal" value="#{i.name}" />
<h:outputText style="font-weight: normal" value="#{i.producer.name}" />
<h:commandButton value="Buy" actionListener="#{mrBean.buyItem}" >
<f:param name="itemID" value="#{i.id}" />
</h:commandButton>
</h:panelGrid>
</h:form>
</ui:repeat>
</h:panelGroup>
</ui:define>
When I open the page, it can load normally with the menu populated properly. However, when I choose 1 of the option, I ran into the following error:
SEVERE: javax.faces.component.UpdateModelException: javax.el.ELException: /partner/BuyItem.xhtml #53,81 value="#{mrBean.itemCategoryID}": Can't set property 'itemCategoryID' on class 'managedBean.MrBean' to value 'null'.
...
Caused by: javax.el.ELException: /partner/BuyItem.xhtml #53,81 value="#{mrBean.itemCategoryID}": Can't set property 'itemCategoryID' on class 'managedBean.MrBean' to value 'null'.
at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:139)
at javax.faces.component.UIInput.updateModel(UIInput.java:818)
... 47 more
Caused by: java.lang.IllegalArgumentException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javax.el.BeanELResolver.setValue(BeanELResolver.java:381)
at com.sun.faces.el.DemuxCompositeELResolver._setValue(DemuxCompositeELResolver.java:255)
at com.sun.faces.el.DemuxCompositeELResolver.setValue(DemuxCompositeELResolver.java:281)
at com.sun.el.parser.AstValue.setValue(AstValue.java:197)
at com.sun.el.ValueExpressionImpl.setValue(ValueExpressionImpl.java:286)
at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:131)
... 48 more
EDIT: this is my bean with getListOfItems function:
#ManagedBean
#ViewScoped
public class MrBean {
#EJB
private PartnerBeanLocal partnerBean;
#ManagedProperty(value="0")
private long itemCategoryID;
private List<ItemState> items;
...
public void getListOfItems() {
try {
System.out.println(itemCategoryID); // I never saw this line printed out
ArrayList data = partnerBean.getInfo(Constants.GET_LIST_OF_ITEMS, itemCategoryID);
int result = ((Integer) data.get(0)).intValue();
if (result == Constants.STATUS_SUCCESSFUL) items = (List<ItemState>) data.get(1);
else if (result == Constants.STATUS_NOT_FOUND) FacesContext.getCurrentInstance().getExternalContext().redirect("HomePage.xhtml");
} catch (IOException ex) {
Logger.getLogger(MrBean.class.getName()).log(Level.SEVERE, null, ex);
}
}
...
// Getters and Setters
...
public long getItemCategoryID() {
return itemCategoryID;
}
public void setItemCategoryID(long itemCategoryID) {
this.itemCategoryID = itemCategoryID;
}
public List<ItemState> getItems() {
return items;
}
public List<ItemState> setItems(List<ItemState> items) {
this.items = items;
}
...
}
I'd be very grateful if someone could give me an advice on how to tackle this problem.
EDIT 2: Thanks everyone for helping me! The problem was that I stupidly forgot to put the <f:ajax> tag inside a <h:form> tag.
Here is what I tried:
#ManagedBean
#ViewScoped
public class MrBean implements Serializable {
#ManagedProperty(value="0")
private long itemCategoryID;
private List<ItemCategory> itemCategories;
#PostConstruct
public void init() {
this.itemCategories = new ArrayList<ItemCategory>();
this.itemCategories.add(new ItemCategory("Item1", 1));
this.itemCategories.add(new ItemCategory("Item2", 2));
this.itemCategories.add(new ItemCategory("Item3", 3));
}
public void getListOfItems() {
System.out.println(Thread.currentThread().getStackTrace()[1]);
System.out.println("itemCategoryID: " + this.itemCategoryID);
}
public List<ItemCategory> getItemCategories() {
return itemCategories;
}
public void setItemCategories(List<ItemCategory> itemCategories) {
this.itemCategories = itemCategories;
}
public long getItemCategoryID() {
return itemCategoryID;
}
public void setItemCategoryID(long itemCategoryID) {
this.itemCategoryID = itemCategoryID;
}
}
with:
<h:form>
<h:selectOneMenu value="#{mrBean.itemCategoryID}">
<f:ajax execute="#this" listener="#{mrBean.getListOfItems}"></f:ajax>
<f:selectItem itemLabel="Choose one .." itemValue="0" noSelectionOption="true" />
<f:selectItems value="#{mrBean.itemCategories}" var="ic"
itemLabel="#{ic.name}" itemValue="#{ic.id}" />
</h:selectOneMenu>
</h:form>
And it works without any problem.
Might be the version of JSF (EL) you have, or you have problem somewhere else.
The <f:ajax> tag need to be wrapped inside a <h:form> tag.
Seems like some of your item values are null. If you want to accept null, use Long instead of long.
I had the same issue and it was resolved by changing my variable type boolean to Boolean

When adding a faces message in JSF my actions aren't performed?

I have the following backing bean:
#ViewScoped
#ManagedBean
public class WeighFamilyBacking2 implements Serializable {
private static final long serialVersionUID = 1L;
private String[] children = new String[] { "Child1", "Child2", "Child3" };
private HashMap<String, Integer> newWeights;
public WeighFamilyBacking2() {
newWeights = new HashMap<String, Integer>();
for (String s : getChildren())
newWeights.put(s, new Integer(0));
}
public void distributeWeightsWithoutMessage(ActionEvent event) {
for (String s : newWeights.keySet()) {
newWeights.put(s, newWeights.get(s) + 1);
}
}
public void distributeWeights(ActionEvent event) {
for (String s : newWeights.keySet()) {
newWeights.put(s, newWeights.get(s) + 1);
}
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("Succesful", "Weights redistributed."));
}
public HashMap<String, Integer> getNewWeights() {
return newWeights;
}
public List<String> getChildren() {
return Arrays.asList(children);
}
}
... And the following xhtml page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
<h:form>
<ui:repeat var="child" value="#{weighFamilyBacking2.children}">
<h:outputText value="#{child}" />
<h:outputText value="#{weighFamilyBacking2.newWeights[child]}" /> -
<h:outputText value="#{weighFamilyBacking2.newWeights[child]}" /> -
<h:inputText id="oz" value="#{weighFamilyBacking2.newWeights[child]}" />
<h:inputText id="lbs"
value="#{weighFamilyBacking2.newWeights[child]}" />
<br />
</ui:repeat>
<h:commandButton
actionListener="#{weighFamilyBacking2.distributeWeights}"
value="Redistribute" />
<h:commandButton
actionListener="#{weighFamilyBacking2.distributeWeightsWithoutMessage}"
value="Redistribute Without Message" />
</h:form>
</h:body>
</html>
This is a simple reproducible test case. When you click on the redistribute without message, things work as expected. When you click on the redistribute button it displays the success message but the input fields are not updated. However, the text output field is updated just one time.
I have tried using immediate=true on both buttons and that doesn't affect this. This is a very simple case, I can't understand why it doesn't work.
I have tried this with all recent versions of Mojarra including 2.1.3.
This is another <ui:repeat> anomaly. I haven't nail down the exact root cause yet so that I can check if this is already reported to the JSF guys and if necessary report it, but I can tell that it works when I replace the <ui:repeat> by a <h:dataTable>.
<h:dataTable var="child" value="#{weighFamilyBacking2.children}">
<h:column>
<h:outputText value="#{child}" />
<h:outputText value="#{weighFamilyBacking2.newWeights[child]}" /> -
<h:outputText value="#{weighFamilyBacking2.newWeights[child]}" /> -
<h:inputText id="oz" value="#{weighFamilyBacking2.newWeights[child]}" />
<h:inputText id="lbs"
value="#{weighFamilyBacking2.newWeights[child]}" />
</h:column>
</h:dataTable>
Maybe a <table> is not semantically correct for you. If this is really undesireable, you might want to check if it works without problems with Tomahawk's <t:dataList>, RichFaces' <rich:dataList>, PrimeFaces' <p:dataList>, etc each which supports rendering the children without additional markup.
Update: I reported it as issue 2157.

Resources