Как показать детали текущей строки из p: dataTable в диалоговом окне p: и обновить после сохранения

У меня есть приложение JSF 2, в котором есть две страницы, одна из которых предназначена для перечисления студентов, а другая - для отображения сведений об этом учащемся. На странице списка есть ссылка на страницу сведений в каждой строке таблицы учеников, которая открывает новую вкладку в браузере, чтобы отображать эти данные при нажатии.

Теперь требования изменились на не более подробную информацию на новой вкладке, но в модальном диалоговом окне на странице списка.

Моя идея - просто вставлять содержимое страницы деталей в модальное диалоговое окно, чтобы страница с листингом не становилась слишком большой и трудноподдерживающейся. Здесь начинаются мои сомнения. После некоторых исследований я изменил ссылку в каждой строке списка на следующую кнопку:

<p:commandButton value="Details" type="button"
                 onclick="PF('dialog-details').show()">
</p:commandButton>

Диалог объявляется следующим образом:

<p:dialog widgetVar="dialog-details" header="Details" modal="true" width="95%">
    <ui:include src="student_details.xhtml">
        <ui:param name="id" value="#{student.id}"/>
    </ui:include>
</p:dialog>

Наконец, страница сведений была изменена так:

<ui:composition
    xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
    xmlns:p="http://primefaces.org/ui" xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">

    <f:metadata>
        <f:viewParam name="id" value="#{studentBean.id}" />
    </f:metadata>

    <h1 class="title ui-widget-header ui-corner-all">Details of #{studentBean.bean.name} / #{studentBean.bean.number}</h1>
</ui:composition>                       

Когда я нажимаю кнопку, диалоговое окно действительно показывает, а контент - это страница сведений. Я вижу следующий диалог в диалоговом окне:

Details of  / 

Никаких ошибок вообще, но данные, которые должны быть показаны, - нет. Точка останова была установлена ​​в StudentBean.setId() (этот метод загружает свойство с именем bean с экземпляром Student, соответствующим переданному id), но он никогда не попадает.

Спустя некоторое время подумав об этом, я понял, почему он не работает. Параметр, переданный на страницу сведений, student.id, но Student - это имя, используемое как var в <p:datatable/>, которое показывает всех студентов, поэтому Student недействительно в <p:dialog/>, который находится вне <p:datatable/>.

Итак, мне нужен способ показать диалог, используя идентификатор соответствующего учащегося в данной строке. В идеале, мне нужен вызов ajax, поэтому детали будут загружены только тогда, когда они будут добавлены.

Любые идеи?

Ответ 1

Кнопка должна быть ajax-кнопкой, которая устанавливает текущий итеративный объект в bean, а затем обновляет содержимое диалогового окна и, наконец, показывает его. Диалог должен просто ссылаться на этот объект в bean и обновлять список и таблицу сохранения.

Вот пример запуска:

<h:form id="master">
    <p:dataTable value="#{bean.entities}" var="entity">
        <p:column>#{entity.property1}</p:column>
        <p:column>#{entity.property2}</p:column>
        <p:column>#{entity.property3}</p:column>
        ...
        <p:column>
            <p:commandButton value="View" action="#{bean.setEntity(entity)}" 
                update=":detail" oncomplete="PF('detail').show()" />
        </p:column>
    </p:dataTable>
</h:form>

<p:dialog id="detail" widgetVar="detail">
    <h:form>
        <p:inputText value="#{bean.entity.property1}" />
        <p:inputText value="#{bean.entity.property2}" />
        <p:inputText value="#{bean.entity.property3}" />
        ...
        <p:button value="Close" onclick="PF('detail').hide(); return false" />
        <p:commandButton value="Save" action="#{bean.save}" 
            update=":master" oncomplete="PF('detail').hide()" />
    </h:form>
</p:dialog>

При этом внутри @ViewScoped bean:

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

@EJB
private EntityService entityService;

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

public void save() {
    entityService.save(entity);
    load();
}

См. также: