Для динамического «клонирования», создания копий, коллекций компонент
на странице, в ADF используются конструкции
af:forEach и
af:iterator. Если внешне они имеют сходство, то в работе есть большое отличие.
Его я и хочу показать
И af:forEach и af:iterator могут
использовать коллекции в своей работе. И если
af:forEach вычисляет выражения «Var» только
на момент построения, то af:iterator может вычислять выражения и после построения
страницы. Потому что af:iterator имеет доступ к модели данных через выражения. Вот как про это сказано в документации «<af:forEach> does not work with a JSF DataModel, or
CollectionModel. It also cannot be bound to EL expressions. Это и есть главное отличие. Покажу
как это выглядит
Схема HR на Oracle XE. Исходный набор данных - таблица Jobs
Описание на странице
<af:forEach items="#{bindings.JobsView1.allRowsInRange}" var="row"> <af:commandButton text="#{row.attributeValues[1]}" id="cb2" actionListener="#{pageBean.testForEach}" inlineStyle="width:200px;"/> <af:spacer width="1" height="2" id="s1"/> </af:forEach>
<af:iterator id="i1" value="#{bindings.JobsView1.collectionModel}" var="row" rows="0">
<af:commandButton text="#{row.JobTitle}" id="cb1"
actionListener="#{pageBean.testIterator}" inlineStyle="width:200px;"/>
<af:spacer width="1" height="2" id="s2"/>
</af:iterator>
Внешний вид
Код в бине
/**
* Вызов с кнопки forEach
* @param actionEvent
*/
public void testForEach(ActionEvent actionEvent) {
// вернет - null
System.out.format("%s \r\n", JSFUtils.resolveExpression("#{row.attributeValues[2]}"));
}
/**
* Вызов с кнопки iterator
* @param actionEvent
*/
public void testIterator(ActionEvent actionEvent) {
// вернет верный результат
System.out.format("%s, %s \r\n", JSFUtils.resolveExpression("#{row.MinSalary}"),
JSFUtils.resolveExpression("#{row.MaxSalary}"));
}
Т.е. после того как страница создана и все свойства вычислены, iterator может обращаться к модели и вычислять выражения, а forEach - нет. И в случае forEach, если на момент построения страницы надо вычислить еще дополнительные атрибуты, то лучше это сделать через- f:attribute
<af:forEach items="#{bindings.JobsView1.allRowsInRange}" var="row"> <af:commandButton text="#{row.attributeValues[1]}" id="cb2"> <f:attribute name="attr1" value="#{row.attributeValues[2]}"/> </af:commandButton> </af:forEach>
Поскольку в forEachнет нет доступа к модели и при вычислении свойств он обращается непосредственно к объектам из - items. У нас это - Row[] getAllRowsInRange(), то пожалуй единственный способ получить значение это вызвать в Row
java.lang.Object[] getAttributeValues(), и обращаться через индекс в массиве. Но есть все таки еще одна возможность. Если у ViewObject будет RowImpl класс, то можно будет обратится к его accessors. Вот так это будет выглядеть.
<af:forEach items="#{bindings.JobsView1.allRowsInRange}" var="row"> <af:commandButton text="#{row.jobTitle}" id="cb2"/> </af:forEach>
Конечно обращение по имени - приятней. Таким образом, мой вывод - там, где нужны вычисления EL в Runtime от модели данных на которой построен список, то конечно лучше использовать - af:iterator.
Источник
Комментариев нет:
Отправить комментарий