Вызвать f:viewAction условно на основе f:viewParam
У нас есть настройка, в которой у нас есть различные необязательные параметры просмотра, передаваемые на страницы JSF, и последующие действия просмотра, которые должны обрабатываться после установки параметров. Очень простой пример показан ниже:
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>
страница
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
не работает (page.xhtml?a=123), в то время как обработка b
работает как шарм (page.xhtml?b=123) - хотя я думал, что просто перенес нулевую проверку с Java на JSF. Что касается читабельности, я бы предпочел пропустить дополнительные проверки нуля в Java и полностью обработать параметры представления в JSF, но как я могу настроить код, чтобы первый сценарий работал?
РЕДАКТИРОВАТЬ В соответствии с принятым ответом Какова цель визуализируемого атрибута в f: viewAction?, if
работает как таковой, поэтому я подозреваю, что неправильный порядок выполнения (сначала оцените условие действия, затем примените значения к модели).
1 ответ
<f:viewAction if>
атрибут в основном переименован <h:xxx rendered>
атрибут (я оставлю в середине, будет ли это более ясным или нет, как следствие, он имеет по крайней мере ошибку в автоматически сгенерированной документации; rendered
вместо if
) и, таким образом, имеет точно такой же жизненный цикл во время фазы " Применить значения запроса", как и у всех других компонентов пользовательского интерфейса. Эта фаза называется UIComponent#decode()
всех компонентов пользовательского интерфейса в представлении. Для UIViewAction
, класс компонента пользовательского интерфейса позади <f:viewAction>
тег, decode()
описывается следующим образом:
Не предпринимайте никаких действий, если выполняется любое из следующих условий:
Текущий запрос является обратной передачей, а экземпляр настроен так, чтобы не выполнять обратную передачу. Увидеть
isOnPostback()
,Условие указано в
if
свойство оценивается как ложное. УвидетьisRendered()
Так что, да, вы действительно правы относительно "неправильного порядка исполнения". На этапе применения значений запроса он проверяет if
атрибут и если он оценивает false
тогда декодирование не произойдет, а событие не будет поставлено в очередь. Смотрите также строку 644 UIViewAction
исходный код, где он тестирует isRendered()
insice decode()
и не продолжается, если false
, В вашем случае #{page.a}
, который вы проверяете в <f:viewAction if>
, доступен только на этапе обновления значений модели, который идет после этапа применения значений запроса.
Вы хотите протестировать что-то еще, что гарантированно будет доступно на этапе применения значений запроса. Лучшим кандидатом будет сам фактический параметр запроса. Все "простые" параметры запроса находятся в области видимости EL, доступной для неявного объекта EL #{param}
который ссылается на Map<String, String>
с именем параметра в качестве ключа.
Итак, в общем, это должно сделать:
<f:viewParam name="a" value="#{page.a}"/>
<f:viewAction action="#{page.populateA}" if="#{not empty param.a}"/>
Обновление, чтобы решить не интуитивное поведение <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}"/>