Я бы сказал, что вы почти работаете против JSF и того, как он работает в вашем примере кода. Прежде чем показать вам рабочий пример, я хотел бы сказать несколько вещей, связанных с хорошей практикой:
- Не вызывайте методы напрямую, используйте встроенный перевод ссылок на свойства. Ссылка на
data.locked
будет автоматически преобразована в вызов data.isLocked()
. Вызов data.locked
предпочтительнее, так как это заставит фреймворк оценить его вместо того, чтобы вы отправляли уже оцененное значение.
- Работайте с JSF — не против. В вашем примере кода много ненужных идентификаторов и использование ненужных тегов и индексов. Будьте проще и работайте с фреймворком. Вместо того, чтобы ссылаться на идентификатор, ссылайтесь на объект напрямую — это упрощает код и упрощает его использование на самой странице.
- Используйте действие в качестве основного исполнителя бизнес-логики и результата. Слушатели действий выполняются заранее и могут использоваться для перехвата или остановки выполнения основного действия. Поэтому они подходят для использования в качестве шага проверки перед выполнением бизнес-логики.
- Отметьте свои события. Рекомендуется использовать соглашение об именах
on<Something>
при именовании методов, получающих пользовательские события. Это позволяет четко их идентифицировать.
Я сделал небольшой рабочий пример вашего кода (используется Lombok и Apache Commons);
@Data
@Named
@ViewScoped
public class DataListViewBackingBean implements Serializable {
private Entity entity;
private Entity selectedEntity;
private List<Entity> dataEntities;
@PostConstruct
private void init() {
dataEntities = new ArrayList<>();
for (int i = 0; i < 10; i++) {
dataEntities.add(new Entity(i, RandomUtils.nextBoolean(),
RandomStringUtils.randomAlphabetic(30)));
}
}
@Data
@AllArgsConstructor
@EqualsAndHashCode(exclude = {"locked","description"})
public class Entity {
private int id;
private boolean locked;
private String description;
}
public void onEdit(Entity entity) {
selectedEntity = entity;
}
public void onDelete(Entity entity) {
dataEntities.remove(entity);
selectedEntity = null;
}
}
Приведенный выше код инициализирует список данных из десяти сущностей и заполняет его случайными данными. Я воспользовался привилегией изменить data
на entity
. Когда дело доходит до вашего HTML-кода, я чувствую, что его нужно немного почистить. Определение JSF будет выглядеть примерно так;
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Data list test</title>
</h:head>
<h:body>
<h:form id="items">
<p:dataList type="definition" value="#{dataListViewBackingBean.dataEntities}" var="entity">
<div class="ui-g">
<div class="ui-g-8">
#{entity.description}
</div>
<div class="ui-g-4" style="text-align: right">
<p:commandButton value="Edit" disabled="#{entity.locked}" action="#{dataListViewBackingBean.onEdit(entity)}" update=":edit" />
<p:commandButton value="Delete" disabled="#{entity.locked}" action="#{dataListViewBackingBean.onDelete(entity)}" update="@form :edit" />
</div>
</div>
</p:dataList>
</h:form>
<h:form id="edit">
<p:outputPanel rendered="#{dataListViewBackingBean.selectedEntity != null}">
<h1>Editing...</h1>
<p:inputText placeholder="Description" value="#{dataListViewBackingBean.selectedEntity.description}" />
<p:commandButton value="Save" update=":items" />
</p:outputPanel>
</h:form>
</h:body>
</html>
Обратите внимание, как редактирование div/outputPanel
заключено в другой контейнер (форму). Если бы мы пропустили упаковку и вместо этого отправили обновление непосредственно в обернутый контейнер, тег rendered
контейнера никогда не обновлялся бы во время обновления, и поэтому div никогда не отображался бы. В данном конкретном случае именно поэтому форма определяется вне контейнера, а не внутри.
В этом примере используется bean-компонент @ViewScoped
, поэтому, пока вы остаетесь на странице, резервные данные должны оставаться неизменными. Если вы перезагрузите страницу, вы получите новый набор данных с новыми объектами, так как это повторно инициализирует вспомогательный компонент и снова вызовет @PostConstruct
.
См. также
person
Adam Waldenberg
schedule
11.01.2019
edit_{data.id}
. Может быть, это проблема. Вы получаете сообщения об ошибках? Если вам нужен идентификатор только дляupdate=
, вы должны поместить<span
и<p:panelGrid
внутри<h:panelGroup id='edit_#{data.id}'>
и лишить их идентификаторов. - person Holger   schedule 10.01.2019<h:panelGroup id='edit_#{data.id}'>
, и никто другой не должен получать такой же идентификатор. - person Holger   schedule 10.01.2019Cannot find component for expression "edit_1" referenced from "main:j_idt70:0:j_idt122".
Заявление об обновлении ищет edit_1, но идентификатор панели сетки генерируется Primefaces: main:j_idt70:0:edit_. Но я хочу, чтобы у panelGrid был тот же идентификатор --› edit_1 для примера. - person JohnRamb0r   schedule 10.01.2019:0
, вам не нужно использовать динамические идентификаторы. Просто используйте, например,editbox
. Он будет изменен наmain:j_idt70:x:editbox
, где x — индекс строки списка данных. Родственникupdate='editbox'
без:
должен найти. - person Holger   schedule 10.01.2019update="editbox"
, то все поля редактирования будут всплывать - я прав? - person JohnRamb0r   schedule 10.01.2019