Интеграция Primefaces в приложение на Spring Boot. Часть 3 — динамическое обновление контента страницы
Во второй части мы сосредоточились главным образом на создании меню на основе компонента Tree ContextMenu. Пришло время показать, как можно этим меню воспользоваться. В моем случае сценарий такой — необходимо по клику на одном из трех пунктов меню обновить содержание главной части страницы, в которой должно отобразиться каждый раз разное содержимое. Метод, который я покажу, достаточно универсальный, его можно применять самыми разными способами. (Вообще, основной текст xhtml страницы и бина компонента уже показаны в предыдущей части статьи, кто-то, возможно, уже и сам разобрался в этом, но все равно, разберем этот момент подробнее)
Итак, вот еще раз часть кода страницы:
Компонент p:splitter
очень простой, он просто разделяет страницу на две области в заданной пропорции. В левой части, собственно, размещен наш компонент меню p:tree
. В правой — размещаем компонент ui: include из библиотеки http://xmlns.jcp.org/jsf/facelets. Обратите внимание, что я дважды завернул его в компонент h:panelGroup
и включил во внутренней обертке rendered="true"
, это сделано для того, чтобы при частичном рендеринге страницы вложенная в него страница также обновлялась. Далее, указываем источник, где размещена вложенная страница
. getSrc()
— это у меня метод бина компонента, который получает адрес вложенной страницы. В бине устанавливаем адрес по дефолту, который указывает на вложенную страницу, загружаемую при первом заходе на главную страницу. Затем нам необходимо написать метод setSrc()
, который будет загружать в поле бина listSrc новый адрес при клике по пункту меню. Приведем еще раз класс бина компонента, который уже публиковался во второй части статьи, чтобы вы его не искали:
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import org.primefaces.PrimeFaces;
import org.primefaces.model.TreeNode;
import javax.annotation.ManagedBean;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import java.io.Serializable;
import java.util.List;
@ManagedBean("treeContextMenuView")
@ViewScoped
public class PageMenuView implements Serializable {
private final TreeNode root;
private TreeNode selectedNode;
private final String DEFAULT_LIST = "employees.xhtml";
private String listSrc;
@Inject
public PageMenuView(PageService service) {
root = service.createPages();
listSrc = DEFAULT_LIST;
}
public TreeNode getRoot() {
return root;
}
public TreeNode getSelectedNode() {
return selectedNode;
}
public void setSelectedNode(TreeNode selectedNode) {
this.selectedNode = selectedNode;
}
public void setSrc() {
if (selectedNode.getData().getLink() != null) {
listSrc = selectedNode.getData().getLink();
UIViewRoot view = FacesContext.getCurrentInstance().getViewRoot();
List uiComponents = view.getChildren();
UIComponent uiComponent = uiComponents.get(2).getChildren().get(0).getChildren().get(3).getChildren().get(1)
.getChildren().get(0);
PrimeFaces.current().ajax().update(uiComponent.getClientId());
}
}
public String getSrc() {
return listSrc;
}
}
Чтобы метод сработал, его нужно вызвать ajax запросом из компонента меню, привязав событие select к обработчику setSrc()
Обработчик считывает выбранный узел в виде объекта TreeNode
, извлекает из данных объекта новый линк, привязанный к соответствующему пункту меню и загружает линк в переменную listSrc. После чего необходимо программным способом вызвать обновление компонента
, что мы и делаем. В моем случае я выбрал самый упрощенный путь поиска компонента в дереве DOM страницы, так как не предполагаю динамически менять ее никогда. При ре-рендеринге перезагружается другая вложенная страница с другим содержимым.
Однако, в Интернет вы найдете массу описаний, как получить компонент или просто любой другой элемент в проектах на Primefaces по id элемента или компонента. Не удивляйтесь, что в большинстве случаев они работать не будут, так как они используют другую конструкцию — FacesContext.getCurrentInstance().getViewRoot().findComponent(id)
и последний метод в нем, как правило, не может найти компонент по id, просто потому, что на странице часто много динамики, много разных компонентов, инклудов и так далее, из-за которых вы фактически будете вызывать компонент из того места кода, где контекст или его часть фактически уже потеряны. И разбираться во всем этом хитросплетении чаще бывает намного дольше и сложнее, чем просто пройтись по DOM страницы и найти нужный компонент в режиме дебага. Или еще можно написать или нагуглить какой-то метод для поиска компонента по id рекурсивным поиском по DOM, например, как здесь https://stackoverflow.com/questions/14378437/find-component-by-id-in-jsf. Я не стал мучиться, и просто нашел компонент вручную.
В следующей части статьи мы посмотрим, как я делал списки для вывода из БД в компоненте DataTable Filter (список табличных данных с фильтром)
Данный цикл статей подготовлен в преддверии старта курса «Java Developer. Professional». Также рекомендую к посещению бесплатный урок курса по теме: «Реактивное подключение к Postgresql в приложениях на Java».