p:дерево / o:дерево обновляет отдельные узлы с помощью p:автоматическая дата не работает

#jsf #jakarta-ee #primefaces #omnifaces

Вопрос:

Я хочу обновить <p:outputPanel id="personName"> внутри узла дерева с помощью AJAX-обновления PrimeFaces. Я попробовал свой подход как с примерами, так <p:tree> и с омнифейсами <o:tree> . В обоих случаях вложенность <p:outputPanel> не обновляется. Однако обновление всего дерева работает. Я думаю, что я назначил id все необходимые элементы.

Чтобы обновить <p:outputPanel id="personName"> I вложенный a <p:autoUpdate on="person-change-event" /> . Он AutoUpdateTagHandler берет трубку <p:outputPanel> , но визуализатор никогда не вызывается. Кроме того, обновленное <p:outputPanel id="personName"> никогда не является частью частичного ответа на просмотр, отправленного клиенту.

Если я добавлю идентификаторы personTree или oTree в список обновлений командной кнопки, это сработает. Но я специально хочу обновить только части узла, чтобы сэкономить затраты. Что я делаю не так?

Я создал минимальный рабочий пример, который я опишу:

Дерево примитивов:

 <p:card id="personTreeCard">
    <f:facet name="title">Persons (PrimeFaces)</f:facet>
    <p:tree id="personTree"
            var="person"
            value="#{personTreeModel}">
        <p:treeNode>
            <p:outputPanel layout="inline" id="personId">
                (<h:outputText value="#{person.dbId}"/>)
            </p:outputPanel>
            <p:outputPanel layout="inline" id="personName" styleClass="person-#{person.state}">
                <h:outputText value="#{person.name}"/>
                <p:autoUpdate on="person-change-event"/>
            </p:outputPanel>
        </p:treeNode>
    </p:tree>
</p:card>
 

Дерево омнифейсов:

    <p:card id="otherPersonTreeCard">
        <f:facet name="title">Persons (OmniFaces)</f:facet>
        <o:tree value="#{otherPersonTreeViewModel.root}" var="person" varNode="node" id="oTree">
            <o:treeNode level="0">
                <ul class="person-list">
                    <o:treeNodeItem id="personNode">
                        <li class="person-list-item">
                            <p:outputPanel layout="inline" id="oPersonId">
                                (<h:outputText value="#{person.dbId}"/>)
                            </p:outputPanel>
                            <p:outputPanel layout="inline" id="oPersonName"
                                            styleClass="person-#{person.state}">
                                <h:outputText value="#{person.name}"/>
                                <p:autoUpdate on="person-change-event"/>
                            </p:outputPanel>
                        </li>
                    </o:treeNodeItem>
                </ul>
            </o:treeNode>
        </o:tree>
    </p:card>
 

У меня есть простая форма, которая выбирает Person и обновляет имя, добавляя случайное число в конец:

 <h:form id="personForm">
            <p:card id="settingsCard">
                <div class="ui-fluid p-formgrid p-grid">
                    <div class="p-field p-col-12">
                        <p:selectOneMenu id="personSelectOneMenu"
                                         converter="omnifaces.SelectItemsConverter"
                                         value="#{personFormViewModel.selectedPerson}">
                            <f:selectItems value="#{personSessionModel.personList}"
                                           itemLabel="(#{person.dbId}) #{person.name}"
                                           itemValue="#{person}"
                                           var="person"/>
                            <f:selectItem noSelectionOption="true" itemLabel="-- select person --"/>
                            <p:ajax/>
                        </p:selectOneMenu>
                    </div>
                    <div class="p-field p-col-12">
                        <p:commandButton value="Change person"
                                         update="@this @obs(person-change-event) @id(personName) personSelectOneMenu messages"
                                         action="#{personFormAction.changePersonAction}"/>
                    </div>
                </div>
            </p:card>
        </h:form>
 

Вспомогательные Бобы:

 @Model
public class PersonTreeModel extends RootTreeNode implements Serializable {

    private static final long serialVersionUID = 454578540550974256L;

    @Inject
    private PersonSessionModel personSessionModel;

    @PostConstruct
    void onPostConstruct() {
        final List<TreeNode> personTreeNodes = personSessionModel.getPersonList()
                .stream()
                .map(this::createPersonNode)
                .collect(Collectors.toList());
        this.setChildren(personTreeNodes);
    }

    private TreeNode createPersonNode(final Person person) {
        final DefaultTreeNode personNode = new DefaultTreeNode(person);
        this.addTreeNode(person.getDbId(), personNode);
        return personNode;
    }

}

@Slf4j
@Named
@ApplicationScoped
public class PersonSessionModel {

    @Inject
    private PersonService personService;

    private static final int NUMBER_OF_PERSONS = 10;

    @Getter
    private List<Person> personList;

    @PostConstruct
    private void onPostConstruct() {
        log.info("Creating {} persons", NUMBER_OF_PERSONS);
        this.personList = personService.createPersons(NUMBER_OF_PERSONS);
    }

}

@Getter
@Setter
@ViewModel
public class PersonFormViewModel implements Serializable {

    private static final long serialVersionUID = -4933603892578811138L;
    private Person selectedPerson;
}

@Action
public class PersonFormAction {

    private static final Random RANDOM = new Random();

    @Inject
    private PersonFormViewModel viewModel;

    @Inject
    private PersonTreeModel treeModel;

    public void changePersonAction() {
        final Person selectedPerson = viewModel.getSelectedPerson();
        if (selectedPerson.getState().equals("alive")) {
            selectedPerson.setState("dead");
        } else {
            selectedPerson.setState("alive");
        }
        selectedPerson.setName(selectedPerson.getName()   " "   RANDOM.nextInt(10));

        treeModel.onPostConstruct();
    }
}

@ViewModel
public class OtherPersonTreeViewModel implements Serializable {

    private static final long serialVersionUID = -5150070481006078761L;

    @Getter
    private TreeModel<Person> root;

    @Inject
    private PersonSessionModel personSessionModel;

    @PostConstruct
    private void onPostConstruct() {
        root = new ListTreeModel<>();

        personSessionModel.getPersonList().forEach(root::addChild);
    }

}
 

Комментарии:

1. Компонент дерева не работает таким образом, что вы не можете просто обновлять отдельные узлы. Я знаю, что вы хотите сделать, но, к сожалению, вы должны обновить весь компонент.