【问题标题】:Creating master-detail table and dialog, how to reuse same dialog for create and edit创建主从表和对话框,如何重用相同的对话框进行创建和编辑
【发布时间】:2016-01-08 19:20:32
【问题描述】:

我正在尝试创建一个用于创建对象和更新对象的对话框。因此,如果我碰巧点击“新建”按钮,我将看到一个对话框,其中包含要填充的空字段,或者如果我点击条目的编辑按钮,该条目的数据将显示在对话框中以供更新。

按照 5.2 版 primefaces 展示中的示例,我可以以只读的 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() 方法评估所选客人是否为 null,如果不为 null,则返回 true。 selectedGuest 应该在单击 commandButton 时设置,以便对话框可以检索对象,但是,对于 selectedGuest 的 get/set 中的跟踪器,我没有看到使用上述 sn-p 调用的 setter。如果我删除了inputText,那么即使hasSelected 仍然返回false,因此'New Guest' 是对话框的标题,outputText 会填充一个值。

我发现这篇很棒的帖子讨论了关于动作、动作监听器等的执行顺序,但不要认为这完全是我的问题:Differences between action and actionListener

所以最终的问题是,当我只有一个 outputText 时,为什么我的 setter 会被命令按钮调用,但使用 inputText,我从未在日志中看到它被调用?

感谢任何人提供的时间和帮助。

【问题讨论】:

  • value="#{guestList.hasSelected() ? '' : guestList.selectedGuest.name}" 在编辑期间该值将为空,因为它没有连接到任何字段。
  • @Geinmachi,我不认为我在听你说的话。但是,我确实注意到,您指出的 sn-p 应该交换表达式的结果,即#{guestList.hasSelected() ? guestList.selectedGuest.name : ''}。原来的逻辑是颠倒的。即使进行了此更改,setPropertyActionListener 也不会像在对话框中没有 inputText 那样被触发。
  • 我刚刚指出您在inputText 中有空值。如果它是空的,那么它为什么存在?无论如何,您将无法对它做任何事情。如果你在那里输入一些东西,它不会被保存,因为值没有绑定到任何 bean。也许这会导致一些错误并停止进一步处理,如果您有任何错误,请检查服务器日志,例如javax.faces.component.UpdateModelException: javax.el.PropertyNotWritableException:
  • 听起来你说我应该有:value="#{guestList.selectedGuest.name}"?我已经尝试过了,但这似乎没有帮助。目前我在想我会通过 null 来区分“新”和“编辑”,但这似乎是你所说的不好的方法。至于日志,我只看到跟踪器,我的 get 返回 null,没有异常。使用我的新值 =“...” 引发此异常:javax.el.PropertyNotFoundException: /index.xhtml @78,103 value="#{guestList.selectedGuest.name}": Target Unreachable, 'null' returned null。意味着集合没有发生。
  • 在添加按钮的操作方法中使用new Guest() 创建一个空的selectedGuest 实例?您原本打算如何收集/转换/验证提交的值?

标签: jsf primefaces dialog master-detail


【解决方案1】:

即使我们解决了你的问题,这个构造

<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,我认为这与我的问题有关,尽管我仍然无法尝试填充表单。我可能已经能够填充,你肯定已经证明这将是我所能做的。
  • &lt;f:setPropertyActionListener&gt; 也可以,我只是更喜欢 EL 2.2 传递方法参数的特性,因为它以更清晰的代码结尾。另见 a.o. stackoverflow.com/questions/4994458/…
  • 您的示例帮助很大。您的示例包含一些细微之处,而我缺少一些细节,例如,某些元素的一些 ID。我在解决更新属性时遇到了一些麻烦,但这是由于我提供的代码中不存在一些嵌套。我还有很多东西要学,因为我刚刚开始学习 JSF 堆栈。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-03
  • 1970-01-01
  • 1970-01-01
  • 2012-12-19
  • 1970-01-01
  • 2018-05-22
  • 1970-01-01
相关资源
最近更新 更多