H: inputText values ​​inside ui: repeat are not processed

I want to process this form (valueChangueListener is not valid in the real case).

This is the flip side of the bean:

public class TestBean extends PrivateBaseBean implements Serializable { private List<String> strings; @PostConstruct public void init() { strings = new ArrayList<String>(); strings.add(""); strings.add(""); strings.add(""); } public void saveAction(ActionEvent event) { StringBuilder textToShowInMessage = new StringBuilder(); for (String string : strings) { textToShowInMessage.append(string); textToShowInMessage.append("; "); } FacesMessage msg = new FacesMessage(super.getBundle().getString( textToShowInMessage.toString()), ""); FacesContext.getCurrentInstance().addMessage(null, msg); } getters... setters... 

View:

 .... <h:form> <ui:repeat var="string" value="#{testBean.strings}"> <h:inputText value="#{string}" /> <br /> </ui:repeat> <p:commandButton value="#{msg.save}" actionListener="#{testBean.saveAction}" icon="ui-icon-disk" update="@form" /> </h:form> ... 

When a form is processed in a back bean, the list of lines is always empty.

How to handle an intput form inside an iteration without a value listener?

There are some screenshots: Debug code

Form in browser

The same thing happens with an action or action.

+6
source share
2 answers

Your problem is not with the behavior of PrimeFaces <p:commandButton> , but rather with the task of determining the scope, which is implicilty, created using the <ui:repeat> .

First of all, let go of your example. Basically, you have

 <ui:repeat value="#{bean.strings}" var="s"> <h:inputText value="#{s}"/> </ui:repeat> 

with support for List<String> strings .

The culprit is here: value="#{s}" . The exported variable <ui:repeat> s displayed only inside its loop and is not tied to any managed bean property, but only to a local variable. Put it another way, s not bound / equal to bean.strings[index] , as you would expect, and, as we see where it came from, has no knowledge. So, basically, you are disconnected with one-way communication: the value from the bean is printed on your input correctly, but the opposite does not happen.

Workarounds

Workaround # 1: wrapper classes / model objects

The situation can be overcome by using a wrapper object for your class. In the case of a string, it could be a “simple mutable string,” as shown below:

 public class MString { private String string;//getter+setter+constructor } 

In this case, the iteration will work as predicted:

 <ui:repeat value="#{bean.mstrings}" var="ms"> <h:inputText value="#{ms.string}"/> </ui:repeat> 

with support for List<MString> mstrings .

Note that if you have a model class, such as User , and change its properties in <ui:repeat> , the class itself will effectively be a wrapper, so the properties will be set accordingly.

Workaround # 2: Access to the Access Chain

Another workaround is to access an element of your collection directly from the <h:inputText> . Thus, any such property will be set by accessing the bean, then the collection, and then setting the property with the desired index. Too long, but like that. Regarding the question of how <ui:repeat> provides the exported current iteration status variable, varStatus , which will be used to access the array / collection in a managed bean.

In this case, the iteration will work as predicted:

 <ui:repeat value="#{bean.strings}" var="s" varStatus="status"> <h:inputText value="#{bean.strings[status.index]}"/> </ui:repeat> 

with normal List<String> strings support.

+11
source

My workaround solution takes the value directly from the page:

 <ui:repeat id="repeat" value="#{bean.strings}" var="s" varStatus="status"> <h:inputText id="x" value="#{s.field}"/> <h:commandLink style="margin: .5em 0" styleClass="commandLink" actionListener="#{bean.save(status.index)}" value="#{bundle.Send}"/> </ui:repeat> 

Save method:

 public void save(String rowid) { String jsParam = Util.getJsParam("repeat:" + rowid + ":x"); System.out.println("jsParam: " + jsParam); //persist... } 

GetJsParam method:

 public static String getJsParam(String paramName) { javax.faces.context.FacesContext jsf = javax.faces.context.FacesContext.getCurrentInstance(); Map<String, String> requestParameterMap = jsf.getExternalContext().getRequestParameterMap(); String paramValue = requestParameterMap.get(paramName); if (paramValue != null) { paramValue = paramValue.trim(); if (paramValue.length() == 0) { paramValue = null; } } return paramValue; } 
+2
source

Source: https://habr.com/ru/post/944985/


All Articles