среда, 14 августа 2013 г.

17й - практикум. Oracle ADF. af:forEach vs af:iterator


Для динамического «клонирования», создания копий, коллекций компонент на странице, в 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.

Источник
 

   

 

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

Отправить комментарий