#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. Компонент дерева не работает таким образом, что вы не можете просто обновлять отдельные узлы. Я знаю, что вы хотите сделать, но, к сожалению, вы должны обновить весь компонент.