Интеграция Primefaces в приложение на Spring Boot. Часть 3 — динамическое обновление контента страницы

3b45dbc3b239ea67cd9cb10865db6061.png

Во второй части мы сосредоточились главным образом на создании меню на основе компонента 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».

© Habrahabr.ru