#jsf-2 #primefaces
#jsf-2 #основные пространства
Вопрос:
У нас есть следующая структура в нашем xhtml:
<ui:repeat ...>
...
<h:selectOneMenu ...>
...
<p:ajax event="change" update="@parent:@parent" process="@parent:@parent" />
</h:selectOneMenu>
</ui:repeat ...>
В обработчике событий мы получаем доступ к UIComponent, представляющему selectOneMenu . Мы можем перейти к родительскому элементу, представляющему пользовательский интерфейс: повтор. При просмотре дочерних элементов я ожидал бы увидеть все selectOneMenu, видимые на веб-странице, но я вижу только один on . Тот, который вызвал событие изменения.
Как я могу получить доступ к родственным компонентам через компонент ui: repeat?
Мотивация:
Мы в основном создаем сгруппированную таблицу. Т.Е. Таблицу, которая сгруппирована в разделы с данными, которые принадлежат друг другу. Приведенный выше код создает одну группу. Определенные значения в selectOneMenu должны быть выбраны ровно для одной записи в группе. Поэтому, когда изменяется одно значение, мы должны получить доступ ко всем записям в одной группе, чтобы проверить, заполнено ли ограничение, и в противном случае отображать сообщения об ошибках в полях, нарушающих.
Как это выглядит в браузере:
table: there is another outer repeat for creating the contents of this table
..group 1: content of each group is created by the ui:repeat
....row with selectOnMenu
....row with selectOnMenu
....row with selectOnMenu
....row with selectOnMenu
..group 2: content of each group is created by the ui:repeat
....row with selectOnMenu
....row with selectOnMenu
....row with selectOnMenu
....
строка с selectOnMenu
Как это выглядит в обработчике событий:
UiRepeat --> SelectOneMenu(exactly one)
Комментарии:
1. Каждый из ваших
h:selectOneMenu
компонентов должен быть привязан к серверной модели, заданной егоvalue
атрибутом. Вам этого недостаточно или вам нужно также получить экземпляр UIComponent конкретно? Что вы ищете в UIComponent?2. нам нужен UIComponent, потому что мы хотим прикрепить к нему сообщения проверки. Я также хотел бы понять, нормально ли, что мы видим только один компонент, или мы делаем что-то особенное / неправильное, просто чтобы лучше понять JSF.
3. Запросы Ajax могут отправлять разные части формы. Это то, что вы определяете в своих
f:ajax execute=""
p:ajax process=""
атрибутах or . Поскольку они установлены по умолчанию@this
, в process отправляется только current component (h:selectOneMenu
) , поэтому переключение на него@form
может быть ключевым для вашей проблемы. Кстати, используете ли выh:selectOneMenu
withp:ajax
по какой-либо конкретной причине? Вы должны использовать либоf:ajax
ванильный JSFp:selectOneMenu
, либо если хотите сделать все это с помощью Prime.4. @XtremeBiker атрибут процесса должен охватывать все selectOneMenus, я думаю. Я обновил код в вопросе. Причина смешивания h: и p: не очень конкретна. p:selectOneMenu просто выглядел очень уродливо.
5. Затем продолжайте
f:ajax
. Это тег для компонентов JSF.
Ответ №1:
Компоненты любят ui:repeat
и h:dataTable
используют подход, называемый штамповкой, для обработки дочернего содержимого. Это означает, что дочерние компоненты существуют только один раз, независимо от количества элементов в коллекции, на которую ссылается value
. Когда компонент обрабатывается, JSF повторно использует этот компонент (ы) для каждого элемента в коллекции (когда вы смотрите на отображаемый HTML-код, вы можете увидеть индекс в идентификаторе). При таком подходе размер дерева компонентов остается одинаковым, если в вашей коллекции один или 1000 элементов.
Приведенное выше является лишь объяснением поведения, которое вы заметили. Что касается вашей проблемы, может быть несколько решений в зависимости от точных требований и способа структурирования ваших данных.
Вы можете выполнить проверку в прослушивателе, который вы указываете в p:ajax
теге, запускающем запрос (при условии, что вы можете найти данные для текущей группы в модели). Этот прослушиватель выполняется на этапе 5 жизненного цикла. Если запросы ajax отправляют текущую группу, данные уже должны быть доступны в модели.
Затем вы можете добавить сообщения об ошибках проверки для определенного компонента следующим образом:
FacesContext ctx = FacesContext.getCurrentInstance();
ctx.addMessage("clientId of Component",
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Your message", null));
Один из способов получить идентификаторы клиентов представленных компонентов — это прослушиватель системных событий для preValidate
события на вашем h:selectOneMenu
:
<f:event type="preValidate" listener="#{page.preValidate}"/>
Затем в методе прослушивателя вы можете получить доступ к идентификатору клиента текущего компонента (включая индекс текущего элемента!):
public void preValidate(ComponentSystemEvent event) {
String clientId = event.getComponent().getClientId();
}
Затем этот прослушиватель вызывается для всех представленных компонентов. Кроме того, вам каким-то образом нужно будет сопоставить этот идентификатор клиента с текущим элементом в модели (например, получить индекс родительского ui:repeat
компонента).
Выше приведены лишь некоторые основные идеи.
Ответ №2:
Основываясь на вашем поведении и ответе Миши, вы должны использовать
<c:forEach>
Вместо
<ui:repeat>
. ForEach сгенерирует все необходимые вам компоненты.