Values of h:inputText inside ui:repeat are not processed

后端 未结 2 446
礼貌的吻别
礼貌的吻别 2020-12-14 13:04

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

This is the back bean:

public class TestBean extends PrivateBaseBean im         


        
相关标签:
2条回答
  • 2020-12-14 14:05

    Your problem is not connected with PrimeFaces <p:commandButton>'s behaviour, but rather with a scoping problem that is implicilty created when using the <ui:repeat> tag.

    First of all, let's depart from your example. Basically, you've got

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

    with the backing List<String> strings.

    The culprit is here: value="#{s}". The exported by <ui:repeat> variable s is visible only within its loop and it is not bound to any managed bean's property, but instead only to a local variable. Put it differently, s is not bound/equal to bean.strings[index] as one would expect and has no knowledge, as we see, where it originated from. So basically, you're off with a unilateral relationship: value from the bean is printed in your input properly, but the reverse is not happening.

    The workarounds

    Workaround #1: wrapper classes / model objects

    The situation can be overcome by using a wrapper object for your class. In case of a string it could be a 'simple mutable string', like below:

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

    In this case the iteration will be working as predicted:

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

    with the backing List<MString> mstrings.

    Note that if you have your model class, like User, and will change its properties within <ui:repeat> the class itself will be effectively a wrapper, so that the properties will be set appropriately.

    Workaround #2: chained property access

    Another workaround consists of accessing an element of your collection directly from within a <h:inputText> tag. This way, any such property will be set by accessing the bean, then collection, then setting the property at the desired index. Excessively long, but that's how it is. As to the how question, <ui:repeat> provides for an exported current iteration status variable, varStatus, that will be used to access the array/collection in the managed bean.

    In this case the iteration will also be working as predicted:

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

    with the ordinary backing List<String> strings.

    0 讨论(0)
  • 2020-12-14 14:07

    My workaround solution take 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>
    

    The save method:

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

    The 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;
    }
    
    0 讨论(0)
提交回复
热议问题