Создание таблицы и диалога мастер-деталировки, как повторно использовать один и тот же диалог для создания и редактирования

Я пытаюсь создать диалог, который будет служить как для создания объектов, так и для их обновления. Поэтому, если мне удастся нажать кнопку "новый", мне будет представлено диалоговое окно, содержащее пустые поля для заполнения, или если я нажму кнопку редактирования для записи, эти данные ввода будут представлены в диалоговом окне для обновления.

Следуя примеру в витрине штрихов для версии 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, если не null. ВыбранныйGuest должен быть установлен при нажатии кнопки commandButton, чтобы объект был доступен для извлечения по диалогу, однако с трассировщиками в get/set для selectedGuest, я не вижу вызывающего устройства с указанным выше фрагментом. Если я удалю inputText, то даже если hasSelected все еще возвращает false, и, таким образом, "Новый Гость" загорается диалоговым окном, значение outputText заполняется значением.

Я нашел этот отличный пост, рассказывающий о порядке исполнения в отношении действия, прослушивателя действий и т.д., но не думаю, что это довольно моя проблема: Различия между действием и ActionListener.

Итак, конечный вопрос в том, почему мой сеттер вызывается с помощью кнопки команды, когда у меня есть только выходной текст, но с inputText, я никогда не вижу его вызванного в журнале?

Я ценю время и помощь, которую каждый может предоставить.

Ответ 1

Даже если мы исправим вашу проблему, эта конструкция

<p:inputText value="#{guestList.hasSelected() ? '' : guestList.selectedGuest.name}">

никогда не будет работать. Он должен ссылаться на свойство модели, а не на пустую строку.

Лучше всего просто повторно использовать форму редактирования, и пусть кнопка create создаст пустой объект. Это упростило бы многое в стороне зрения. Было бы проще, если бы объект имел свойство @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();
}

См. также: