创建主从表和对话框,如何重复使用同一个对话框进行创建和编辑。

3
我正在尝试创建一个对话框,旨在同时创建对象和更新对象。因此,如果我单击“新建”按钮,则会出现一个包含空字段的对话框以供填写;如果我单击某个条目的编辑按钮,则该条目的数据将呈现在对话框中以进行更新。
按照Primefaces 5.2版本展示的示例,我可以使用只读outputText表单呈现数据,但是当我将其更改为inputText时,字段仍然为空。以下代码是我所拥有的示例:
<h:form id="form">    
  <p:dataGrid id="guestList" var="guest" value="${guestList.guests}" columns="3" paginator="true" rows="20">
    <f:facet name="header">
      Guest List
    </f:facet>

    <p:panel>
      <h:outputText value="${guest.name}" />
      <br />
      <h:outputText value="${guest.street}" />
      <br />
      <h:outputText rendered="#{guest.street2.length() gt 0}"
        value="${guest.street2}" />
      <h:panelGroup rendered="#{guest.street2.length() gt 0}">
        <br />
      </h:panelGroup>
      <h:outputText value="${guest.city}, " />
      <h:outputText value="${guest.state} " />
      <h:outputText value="${guest.zipCode}" />
      <p:commandButton update="@form:newGuestDetail" oncomplete="PF('newGuestDialog').show()" icon="ui-icon-edit" styleClass="ui-btn-inline">
        <h:outputText styleClass="ui-icon ui-icon-edit" style="margin:0 auto;" />
        <f:setPropertyActionListener value="#{guest}" target="#{guestList.selectedGuest}" />
      </p:commandButton>
    </p:panel>
  </p:dataGrid>

  <p:dialog header="#{guestList.hasSelected() ? 'Edit Guest' : 'New Guest'}" widgetVar="newGuestDialog" modal="true" showEffect="fade" hideEffect="fade">
    <p:outputPanel id="newGuestDetail">
      <h:outputText value="'#{guestList.selectedGuest.name}'"/>
      <p:inputText id="guestName" value="#{guestList.hasSelected() ? '' : guestList.selectedGuest.name}" pt:placeholder="Name"/>
      <p:commandButton value="#{guestList.selectedGuest == null ? 'Create Guest' : 'Update Guest'}"/>
    </p:outputPanel>
  </p:dialog>
</h:form>

hasSelected()方法用于判断所选客人是否为空,如果不为空则返回true。当单击commandButton时应设置selectedGuest,以便对话框可以检索对象,但是,在get/set中使用跟踪器来获取selectedGuest时,我没有看到setter与上面的代码片段一起调用。如果我删除inputText,那么即使hasSelected仍然返回false,因此“New Guest”将成为对话框的标题,但outputText也会填充一个值。
我发现这篇很棒的帖子讨论了关于操作、操作监听器等执行顺序的问题,但我认为这并不是我的问题:Differences between action and actionListener
所以最终的问题是,为什么只有outputText时,命令按钮会调用我的setter,但是有inputText时,我从未在日志中看到它被调用?
非常感谢您提供的时间和帮助。

value="#{guestList.hasSelected() ? '' : guestList.selectedGuest.name}" 在编辑期间,该值将为空,因为它未连接到任何字段。 - Geinmachi
@Geinmachi,我不认为我理解你的意思。但是我注意到,你指出的代码片段应该交换表达式的结果,即#{guestList.hasSelected() ? guestList.selectedGuest.name : ''}。逻辑最初是相反的。即使进行了这种更改,setPropertyActionListener也没有像在对话框中没有inputText时那样被触发。 - klog
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Geinmachi
你的意思是我只需要这样写:value="#{guestList.selectedGuest.name}"?我试过了,但好像没什么用。目前我想到的是传递null来区分“新建”和“编辑”,但根据你的说法,这似乎不是一个好方法。至于日志,我只看到跟踪器,我的get方法返回null,没有异常。使用我的新值="..."时,会抛出以下异常:javax.el.PropertyNotFoundException: /index.xhtml @78,103 value="#{guestList.selectedGuest.name}": Target Unreachable, 'null' returned null。这意味着set操作没有发生。 - klog
1
在添加按钮的动作方法中,只需使用new Guest()创建一个空的selectedGuest实例即可?否则,您打算如何收集/转换/验证提交的值? - BalusC
我还没做到那一步,但甚至还不能修改我已有的示例条目。 - klog
1个回答

5
即使我们解决了你的问题,这个结构
<p:inputText value="#{guestList.hasSelected() ? '' : guestList.selectedGuest.name}">

这样是不会起作用的。它需要引用一个模型属性,而不是一个空字符串。

最好是重用编辑表单,并让创建按钮预先创建一个空实体。这将简化视图方面的很多工作。如果实体具有 @Id 属性,那么当它在数据库中持久化时,该属性只出现一次。

以下是一个启动示例:

<h:form id="entitiesForm">
    <p:dataTable id="entitiesTable" value="#{bean.entities}" var="entity">
        <p:column>#{entity.foo}</p:column>
        <p:column>#{entity.bar}</p:column>
        <p:column>
            <p:commandButton id="edit" value="Edit" 
                process="@this" action="#{bean.edit(entity)}"
                update=":entityDialog" oncomplete="PF('entityDialog').show()" />
            <p:commandButton id="delete" value="Delete" 
                process="@this" action="#{bean.delete(entity)}"
                update=":entitiesForm:entitiesTable" />
        </p:column>
    </p:dataTable>
    <p:commandButton id="add" value="Add" 
        process="@this" action="#{bean.add}" 
        update=":entityDialog" oncomplete="PF('entityDialog').show()" />
</h:form>

<p:dialog id="entityDialog" widgetVar="entityDialog" 
    header="#{empty bean.entity.id ? 'New' : 'Edit'} entity">
    <h:form id="entityForm">
        <p:inputText id="foo" value="#{bean.entity.foo}" />
        <p:inputText id="bar" value="#{bean.entity.bar}" />
        <p:commandButton id="save" value="#{empty bean.entity.id ? 'Create' : 'Update'} entity" 
            process="@form" action="#{bean.save}"
            update=":entitiesForm:entitiesTable" oncomplete="PF('entityDialog').hide()" />
    </h:form>
</p:dialog>

有了这个@ViewScoped bean:

private List<Entity> entities; // +getter
private Entity entity; // +getter

@EJB
private EntityService entityService;

@PostConstruct
public void load() {
    entities = entityService.list();
    entity = null;
}

public void add() {
    entity = new Entity();
}

public void edit(Entity entity) {
    this.entity = entity;
}

public void save() {
    entityService.save(entity); // if (id==null) em.persist() else em.merge()
    load();
}

public void delete(Entity entity) {
    entityService.delete(entity); // em.remove(em.find(type, id))
    load();
}

另请参阅:

(说明:本翻译为参考译文,不代表最终结果)

谢谢您提供的示例。我会尝试一下并告诉您结果如何。我注意到您的示例中命令按钮没有使用 setPropertyActionListener,而我使用了它,我认为这与我的问题有关,尽管我在尝试填充表单时仍然失败了。也许我能够填充,但您已经展示了那就是我所能做的全部。 - klog
1
<f:setPropertyActionListener> 也可以使用,但我更喜欢 EL 2.2 的传递方法参数的功能,因为它会产生更清晰的代码。另请参见 https://dev59.com/Jm445IYBdhLWcg3wLXWh。 - BalusC
1
你的示例帮了我很多。你的示例包含了一些我所缺失的细节,例如某些元素的ID。我在解决更新属性时遇到了一些问题,但那是由于我的提供的代码中缺少了一些嵌套。我还有很多东西要学习,因为我现在才开始接触JSF堆栈。谢谢。 - klog

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接