首页 文章

不处理ui:repeat中h:inputText的值

提问于
浏览
6

我想处理这个表单(valueChangueListener在实际情况下无效) .

这是后 beans :

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...

一个观点:

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

在后面的bean字符串列表中处理表单时,始终为空 .

如何处理表单intput的内部迭代,没有任何值的changue监听器?

有一些截图:
Debug code

Form in browser

action或actionListener on会出现同样的问题

2 回答

  • 11

    您的问题与PrimeFaces <p:commandButton> 的行为无关,而是与使用 <ui:repeat> 标记时隐含的范围问题有关 .

    首先,让我们离开你的榜样 . 基本上,你有

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

    支持 List<String> strings .

    罪魁祸首在这里: value="#" . 由 <ui:repeat> 变量 s 导出的内容仅在其循环中可见,并且不绑定到任何托管bean的属性,而是仅绑定到局部变量 . 换句话说, s 并不像人们所期望的那样绑定/等于 bean.strings[index] ,并且我们看不出它来自何处 . 所以基本上,你处于单边关系之中:来自bean的值正确地打印在你的输入中,但反过来却没有发生 .

    解决方法

    Workaround #1: wrapper classes / model objects

    通过为您的类使用包装器对象可以克服这种情况 . 如果是字符串,它可能是一个'简单的可变字符串',如下所示:

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

    在这种情况下,迭代将按预期工作:

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

    支持 List<MString> mstrings .

    请注意,如果您拥有模型类,如 User ,并且将在 <ui:repeat> 中更改其属性,则类本身将实际上是一个包装器,以便适当地设置属性 .

    Workaround #2: chained property access

    另一种解决方法是直接从 <h:inputText> 标记中访问集合的元素 . 这样,任何此类属性都将通过访问bean,然后集合,然后在所需索引处设置属性来设置 . 过长,但就是这样 . 至于如何提问, <ui:repeat> 提供了一个导出的当前迭代状态变量 varStatus ,它将用于访问托管bean中的数组/集合 .

    在这种情况下,迭代也将按预期工作:

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

    与普通的支持 List<String> strings .

  • 2

    我的解决方案解决方案直接从页面获取值:

    <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>
    

    保存方法:

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

    getJsParam方法:

    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;
    }
    

相关问题