2014-08-11 3 views
3

У нас есть параметр, в котором у нас есть разные необязательные параметры представления, переданные на страницы JSF, и последующие действия вида, которые должны быть обработаны после того, как параметры были установлены. Очень простой пример показан ниже:Invoke f: viewAction условно на основе f: viewParam

page.xhtml:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://xmlns.jcp.org/jsf/html" 
    xmlns:f="http://xmlns.jcp.org/jsf/core"> 

<f:view> 
    <f:metadata> 
     <f:viewParam name="a" value="#{page.a}"/> 
     <f:viewAction action="#{page.populateA()}" if="#{not empty page.a}"/> 

     <f:viewParam name="b" value="#{page.b}"/> 
     <f:viewAction action="#{page.populateB()}"/> 
    </f:metadata> 

    <h:outputLabel value="#{page.message}"/> 
</f:view> 
</html> 

Page

import javax.faces.view.ViewScoped; 
import javax.inject.Named; 

@ViewScoped 
@Named 
public class Page { 

    private String a; 

    private String b; 

    private String message; 

    public String getA() { 
     return a; 
    } 

    public void setA(String a) { 
     this.a = a; 
    } 

    public String getB() { 
     return b; 
    } 

    public void setB(String b) { 
     this.b = b; 
    } 

    public String getMessage() { 
     return message; 
    } 

    public void populateA() { 
     this.message = "Param a given: " + this.a; 
    } 

    public void populateB() { 
     if (this.b != null) { 
      this.message = "Param b given: " + this.b; 
     } 
    } 
} 

Теперь, разница в том, что обработка a не работает (стр .xhtml? a = 123), в то время как обработка b работает как шарм (page.xhtml? b = 123) - хотя я думал, что просто перевел нулевую проверку с Java на JSF. Что касается удобочитаемости, я бы предпочел исключить дополнительные проверки нулей в Java и полностью обработать обработку параметров представления в JSF, но как я могу настроить код, чтобы первый сценарий работал?

EDIT Согласно принятому ответу What is the purpose of rendered attribute on f:viewAction?, if работает сама по себе, так что я подозреваю, что неправильный порядок выполнения (первая оценка состояния действия, а затем применить значения в модели).

ответ

6

Атрибут <f:viewAction if> в основном переименован <h:xxx rendered> атрибут (я оставлю в середине, что, будь-более ясно или нет, он имеет по крайней мере bug in autogenerated documentation, как следствие, он перечисляет rendered вместо if) и имеет, таким образом, точно так же, жизненный цикл, в том числе Примените значения запроса, как и все другие компоненты пользовательского интерфейса. Эта фаза вызывает UIComponent#decode() всех компонентов пользовательского интерфейса в представлении. Для UIViewAction, класс компонента UI за <f:viewAction> тега, то decode() описывается следующим образом:

не предпринимать никаких действий, если любой из следующих условий:

  • Текущий запрос является постбэк и экземпляр настроен так, чтобы не работать с обратной передачей. См. isOnPostback().

  • Условие, указанное в свойстве if, равно false. См isRendered()

Так что, да, вы действительно правы, как в "неправильном порядке исполнения". Во время Применить Request Values ​​ фаза проверяет атрибут if, и если он оценивает false, то декодирование не будет выполнено, и событие действия не будет поставлено в очередь. См. Также строку 644 от UIViewActionsource code, где она проверяет isRendered() insice decode() и не действует, если false. В вашем случае, #{page.a}, который вы проверяете в <f:viewAction if>, доступен только в модели обновления значений фазу, которая послеПрименить запрос значения фазы.

Вы хотите проверить что-то еще, что гарантированно будет доступно в течение Заявка на участие фаза. Лучшим кандидатом будет сам фактический параметр запроса. Все «простые» параметры запроса находятся в области EL, доступной implicit EL object#{param}, которая ссылается на Map<String, String> с именем параметра в качестве ключа.

Так, в конце концов, это должно сделать:

<f:viewParam name="a" value="#{page.a}"/> 
<f:viewAction action="#{page.populateA}" if="#{not empty param.a}"/> 

Update решить неинтуитивное поведение <f:viewAction if>, JSF утилиту библиотеку OmniFaces будет, начиная с версией 2.2 предлагает <o:viewAction> которого if только оценивается во время Заключить приложение фаза, прямо перед трансляцией события. Этот трюк был сделан просто расширяя UIViewAction компонент и опрокинув его broadcast() и isRendered(), как показано ниже:

@Override 
public void broadcast(FacesEvent event) throws AbortProcessingException { 
    if (super.isRendered()) { 
     super.broadcast(event); 
    } 
} 

@Override 
public boolean isRendered() { 
    return !isImmediate() || super.isRendered(); 
} 

Это позволяет использовать тег более интуитивно:

<f:viewParam name="a" value="#{page.a}"/> 
<o:viewAction action="#{page.populateA}" if="#{not empty page.a}"/> 
Смежные вопросы