ui:repeat添加新项目在第一个元素中不起作用

时间:2019-02-19 16:49:03

标签: jsf primefaces jsf-2.2 mojarra

我目前正在尝试通过添加/删除素数p:commandButton来简化输入列表。

我在 Glassfish 4.1.1 Mojarra 2.2.12 上使用 PrimeFaces 6.2

ExampleBean.java

package /* myPackage */;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javafx.util.Pair;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

@Named(value = "exampleBean")
@SessionScoped
public class ExampleBean implements Serializable {

    private List<Pair<Integer, Integer>> list;

    @PostConstruct
    public void init() {
        list = new ArrayList<>();
        addNewItem();
    }

    public void addNewItem() {
        list.add(new Pair<>(1, 300));
    }

    public List<Pair<Integer, Integer>> getList() {
        return list;
    }

    public void setList(List<Pair<Integer, Integer>> list) {
        this.list = list;
    }
}

example.xhtml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html" 
      xmlns:ui="http://java.sun.com/jsf/facelets" 
      xmlns:p="http://primefaces.org/ui" 
      xmlns:jsf="http://xmlns.jcp.org/jsf">

    <h:head>
        <title>Example</title>
        <meta charset="utf-8" />
    </h:head>

    <h:body>
        <h:form id="example-form">
            <div jsf:id="example-container">
                <ui:repeat value="#{exampleBean.list}" var="item" varStatus="status">
                    <div>
                        <p:inputText value="#{item.key}" />
                        <p:inputText value="#{item.value}" />

                        <p:commandButton 
                            value="Delete" 
                            actionListener="#{exampleBean.list.remove(item)}" 
                            process="@this" 
                            update="example-form:example-container" 
                            rendered="#{!status.first}" />

                        <p:commandButton 
                            value="Add" 
                            actionListener="#{exampleBean.addNewItem()}" 
                            process="@this" 
                            update="example-form:example-container" 
                            rendered="#{status.first}" />
                    </div>

                </ui:repeat>
            </div>
        </h:form>
    </h:body>
</html>

使用每个rendered的{​​{1}}属性,我只想在第一项上显示添加按钮,并在除第一项之外的所有项目上显示删除按钮(使其无法删除)

我在这里的问题是,在添加按钮上使用p:commandButton会使整个系统无法正常工作。

rendered="#{status.first}"

使用<p:commandButton ... rendered="#{status.last}" /> <!-- actionListener called --> <p:commandButton ... rendered="#{true}" /> <!-- actionListener called --> <p:commandButton ... rendered="#{status.first}" /> <!-- actionListener NOT called --> 时,单击按钮不会调用rendered="#{status.first}"而是触发actionListener

我不知道在第一个项目而不是其他项目或最后一个项目中显示会发生什么变化。

1 个答案:

答案 0 :(得分:0)

我认为这与<ui:repeat>标志有关,并且为命令按钮生成了唯一的ID。该视图可能会混淆。添加其他按钮时,生成的ID会更改。另外,引入rendered属性还改变了组件处理方式。

因此,要解决此问题,我认为您需要重新处理ui:repeat组件和命令按钮才能获得有效的操作URL。解决方法很简单-删除process="@this"

我用一个可行的解决方案调整了您的示例(该示例使用了Lombok);

@Data @Named @ViewScoped
public class ExampleBean implements Serializable {

    private List<IntegerPair> list;

    @PostConstruct
    private void init() {
        list = new ArrayList<>();
        addNewItem();
    }

    public void addNewItem() {
        list.add(new IntegerPair(1, 300));
    }

    @Data
    @AllArgsConstructor
    public class IntegerPair {
        private int key, value;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" 
      xmlns:ui="http://java.sun.com/jsf/facelets"  xmlns:p="http://primefaces.org/ui" 
      xmlns:jsf="http://xmlns.jcp.org/jsf">

    <h:head>
        <title>Example</title>
        <meta charset="utf-8" />
    </h:head>

    <h:body>
        Test!
        <h:form id="example-form">
            <div jsf:id="example-container">
                <ui:repeat value="#{exampleBean.list}" var="item" varStatus="status">
                    <div>
                        <p:inputText value="#{item.key}" />
                        <p:inputText value="#{item.value}" />

                        <p:commandButton 
                            value="Delete" 
                            actionListener="#{exampleBean.list.remove(item)}" 
                            update="example-form:example-container" 
                            rendered="#{!status.first}" />

                        <p:commandButton 
                            value="Add" 
                            actionListener="#{exampleBean.addNewItem}" 
                            update="example-form:example-container" 
                            rendered="#{status.first}" />
                    </div>

                </ui:repeat>
            </div>
        </h:form>
    </h:body>
</html>

注意IntegerPair类吗?我之所以必须介绍一下,是因为JavaFX中定义的Pair<>类没有可写键属性-JSF在处理输入组件的后备bean值时需要可写属性。

坦率地说,由于您面临的问题是由<ui:repeat>组件/标签引起的,因此在命令按钮上执行process="example-form:example-container"也可以正常工作-只要确保已包含<ui:repeat>在处理阶段。