【问题标题】:JSF Primefaces datatable in cell editMode not sending the edited value to the managed bean单元格editMode中的JSF Primefaces数据表未将编辑的值发送到托管bean
【发布时间】:2014-07-17 19:41:50
【问题描述】:

我有两个 primefaces 数据表。第一个显示 MainEntity 的实例。 第二个显示与第一个数据表上选定的 MainEntity 关联的单词列表(只是字符串)。

打印屏幕说明了我的意思。

我的问题是,当我在单词列表上编辑一个字符串时,我的侦听器方法不会接收到新值。事实上,当我调用event.getNewValue() 方法时,我得到的是旧值。

我错过了什么?

我正在使用 JavaServer Faces 2.2、Primefaces 5.0 和 Spring Framework 4.0.3。

提前感谢您的帮助。

xhtml、托管bean和MainEntity的代码如下:

mainEntity.xhtml:

<h:body>
    <h:form id="mainEntityForm">
        <p:panelGrid columns="1" fullPage="true" id="dashboard">
            <f:facet name="header">
                <h2>MainEntity Table</h2>
            </f:facet>
            <p:panel>
                <f:facet name="header">
                    MainEntity List
                    <p:commandButton value="New MainEntity"
                        actionListener="#{mainEntityController.createMainEntityDialog}"
                        styleClass="header-button">
                        <p:ajax event="dialogReturn" update=":mainEntityForm:mainEntityTable" />
                    </p:commandButton>
                </f:facet>
                <p:dataTable id="mainEntityTable" var="mainEntity" value="#{mainEntityController.mainEntities}"
                    editable="true" editMode="cell" widgetVar="cellMainEntity"
                    selectionMode="single" selection="#{mainEntityController.selectedMainEntity}"
                    rowKey="#{mainEntity.id}" tableStyle="width:auto">

                    <p:ajax event="rowSelect" update=":mainEntityForm:stringGrid :mainEntityForm:entityAGrid :mainEntityForm:entityBGrid" />
                    <p:ajax event="cellEdit" listener="#{mainEntityController.onEditMainEntity}" update=":mainEntityForm:mainEntityTable" />

                    <p:column headerText="ID">
                        <h:outputText value="#{mainEntity.id}" />
                    </p:column>
                    <p:column headerText="Name">
                        <p:cellEditor>
                            <f:facet name="output">
                                <h:outputText id="nameOutput" value="#{mainEntity.name}" />
                            </f:facet>
                            <f:facet name="input">
                                <h:inputText id="atyInput" value="#{mainEntity.qty}" />
                            </f:facet>
                        </p:cellEditor>
                    </p:column>
                    <p:column headerText="Commands">
                        <p:commandButton title="Remove MainEntity" icon="ui-icon-trash"
                            actionListener="#{mainEntityController.deleteMainEntity(mainEntity)}"
                            update=":mainEntityForm:mainEntityTable" />
                    </p:column>
                </p:dataTable>
            </p:panel>
            <p:panelGrid fullPage="true" id="mainEntityDetail">
                <f:facet name="header">
                    <p:row>
                        <p:column colspan="4">
                            <h2>MainEntity Detail</h2>
                        </p:column>
                    </p:row>
                </f:facet>
                <p:row>
                    <p:column>
                        <p:panel>
                            <f:facet name="header">
                                Word List
                                <p:commandButton value="New Word"
                                        actionListener="#{mainEntityController.addNewWord()}"
                                        styleClass="header-button"
                                        update=":mainEntityForm:wordGrid">
                                </p:commandButton>
                            </f:facet>
                            <p:dataTable id="wordGrid" var="word"
                                value="#{mainEntityController.selectedMainEntity.wordList}"
                                tableStyle="width:auto" editable="true" editMode="cell" widgetVar="cellWord">

                                <p:ajax event="cellEdit" listener="#{mainEntityController.onEditWord}" />

                                <p:column headerText="Word">
                                    <p:cellEditor>
                                        <f:facet name="output">
                                            <h:outputText id="wordOutput" value="#{word}" />
                                        </f:facet>
                                        <f:facet name="input">
                                            <h:inputText id="wordInput" value="#{word}" />
                                        </f:facet>
                                    </p:cellEditor>
                                </p:column>
                                <p:column headerText="Commands">
                                    <p:commandButton title="Remove Word"
                                        icon="ui-icon-trash"
                                        actionListener="#{mainEntityController.removeWord(word)}"
                                        update=":mainEntityForm:wordGrid" />
                                </p:column>
                            </p:dataTable>
                        </p:panel>
                    </p:column>
                </p:row>
            </p:panelGrid>
        </p:panelGrid>
    </h:form>
</h:body>

MainEntityController.java(托管 bean):

@ManagedBean
@SessionScoped
public class MainEntityController {

    //...

    private MainEntity selectedMainEntity;

    public List<MainEntity> mainEntities;

    //...

    public MainEntity getSelectedMainEntity(){
        return selectedMainEntity;
    }

    public void setSelectedMainEntity(MainEntity mainEntity){
        this.selectedMainEntity = mainEntity;
    }

    //...

    public void onEditWord(CellEditEvent event) {
        Object oldValue = event.getOldValue();
        Object newValue = event.getNewValue();

        if(newValue != null && !newValue.equals(oldValue)) {

            // THE PROBLEM IS HERE
            // I NEVER ACTUALLY REACH THIS CODE
            // newValue is always equal to oldValue!

            FacesContext context = FacesContext.getCurrentInstance();
            String word = context.getApplication().evaluateExpressionGet(context, "#{word}", String.class);
            System.out.println(newValue);
            System.out.println(word);

            FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Word Changed", "Old: " + oldValue + ", New:" + newValue);
            FacesContext.getCurrentInstance().addMessage(null, msg);
        }
    }
}

MainEntity.java:

@Entity
public class MainEntity {

    @Id
    private String id;

    @ElementCollection(fetch=FetchType.EAGER)
    @CollectionTable(
                name="MainEntity_Word",
                joinColumns = @JoinColumn(name = "id", referencedColumnName="id")
            )
    @Column(name = "word")
    private Set<String> wordList;

    //...

    public void addWord(String word) {
        this.wordList.add(word);
    }

    public void removeWord(String word) {
        this.wordList.remove(word);
    }

    public Set<String> getWordList() {
        return wordList;
    }

    public void setWordList(Set<String> wordList) {
        this.wordList = wordList;
    }
}

【问题讨论】:

  • 尝试 implements Serializable 到您的实体类和会话 bean。当您必须通过网络传递和检索对象时,您需要序列化它们。
  • @Tiny 抱歉打错了。它实际上是 JSF。我刚刚更正了问题标题。感谢您的警告。
  • @Sujan 再次感谢您的帮助。我会尝试一下,然后返回结果。
  • @Sujan 没用。不过还是感谢您的帮助。
  • @mateuscpf 你做了什么?

标签: jsf primefaces


【解决方案1】:

改变

<h:inputText id="wordInput" value="#{word}" />

<p:inputText id="wordInput" value="#{word}" />

<h:inputText id="wordInput" value="#{word}" >
<p:ajax event="change" process="@this"/>
</h:inputText>

你需要ajaxify输入组件,最后更新outputText组件。

已编辑

更改此列:

<p:column headerText="Word" >
<p:cellEditor>
<f:facet name="output">
<h:outputText id="wordOutput" value="#{word}" />
</f:facet>
<f:facet name="input">
<h:inputText id="wordInput" value="#{word}" />
</f:facet>
</p:cellEditor>
</p:column>

<p:column headerText="Word" >
<p:cellEditor>
<f:facet name="output">
<h:outputText id="wordOutput" value="#{word}" />
</f:facet>
<f:facet name="input">
<p:inputText id="wordInput" value="#{word}" >
<p:ajax event="change" update="wordOutput" />
</p:inputText>
</f:facet>
</p:cellEditor>
</p:column>

编辑 2

来自Chapter 24 Introduction to the Java Persistence API

如果一个实体实例作为一个分离的对象通过值传递,例如 通过会话 bean 的远程业务接口,该类必须 实现 Serializable 接口。

【讨论】:

  • 我尝试了您提出的两种解决方案,但仍然无法正常工作。不过还是谢谢。
  • 再次感谢 Sujan,但它仍然无法正常工作。我看到你做了什么。您有点合并了您之前提出的两个解决方案,并将update="wordOutput" 添加到p:ajax 标记中。我实际上已经尝试过的合并,但是我没有想到更新属性(我尝试过,正如你所建议的那样)。反正还是不行。
  • 我没有想到更新属性是什么意思?您是否尝试在 ajax cellEdit 事件之后进行更新? &lt;p:ajax event="cellEdit" listener="#{mainEntityController.onEditWord}" update="wordGrid" /&gt;
  • 对不起,如果我不清楚。我的意思是在你建议之前我没有尝试过。是的,我确实尝试过,但它也不起作用。再次抱歉。
  • 对不起,我似乎无法发现错误,这让我很困惑。可能是由于未序列化的实体吗?可能是。
【解决方案2】:

我终于搞定了。

我怀疑 String 不可变的性质,我所做的就是将“单词”封装在一个类中,如下所示:

public class Word {
    private String word;

    Word (String word) {
        this.setWord(word);
    }

    public String getWord() {
        return this.word;
    }

    public void setWord(String word) {
        this.word = word;
    }
}

之后,我还必须在托管 bean(控制器)中创建一个集合来保存单词集,例如“private Set managedWordList;”。

我还在托管 bean 中更改了列表的 getter,以从 String 集转换为 Word 集,例如:

public Set<Word> getWordList() {
    if (this.selectedMainEntity != null){
        this.wordList = new HashSet<Word>();
        for (String word : this.selectedMainEntity.getWordList()) {
            this.wordList.add(new Word(word));
        }
    }
    return this.wordList;
}

最后,我更改了 dataTable 以引用新的集合。来自:

<p:dataTable ... value="#{mainEntityController.selectedMainEntity.wordList}"... />

收件人:

<p:dataTable ... value="#{mainEntityController.wordList}"... />

然后我才让它按预期工作。

【讨论】:

  • 我认为 应该是
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-22
  • 1970-01-01
  • 2023-03-22
相关资源
最近更新 更多