繁体   English   中英

根据f:viewParam有条件地调用f:viewAction

[英]Invoke f:viewAction conditionally based on 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的null-check。 关于可读性,我宁愿在Java中省略额外的空值检查,并且将视图参数处理完全放在JSF中,但是如何调整代码以使第一个场景工作?

编辑根据接受的答案f:viewAction的渲染属性的目的是什么? if本身工作所以我怀疑执行顺序错误(首先评估行动条件,然后将值应用于模型)。

<f:viewAction if>属性基本上是一个重命名的<h:xxx rendered>属性(我将留在中间是否更清楚,它至少在自动生成的文档中有一个错误 ;它列出了rendered而不是if )并且因此具有完全相同的生命周期,其中“ 应用请求值”阶段与所有其他UI组件一样。 此阶段调用视图中所有UI组件的UIComponent#decode() 对于UIViewAction<f:viewAction>标签后面的UI组件类, decode()描述如下:

如果满足以下任一条件,请不要采取任何措施:

  • 当前请求是回发,并且实例已配置为不在回发上运行。 请参阅isOnPostback()

  • if属性中声明的条件评估为false。 isRendered()

所以,是的,你对“错误的执行顺序”确实是对的。 在“ 应用请求值”阶段,它会检查if属性,如果它的计算结果为false ,则不会进行解码,并且不会对action事件进行排队。 另请参阅UIViewAction 源代码的第644行,其中它测试isRendered() insice decode() ,如果为false则不继续。 在您的情况下,您在<f:viewAction if>检查的#{page.a}仅在“ 更新模型值”阶段(即“ 应用请求值”阶段之后)可用。

您希望测试在“ 申请请求值”阶段期间保证可用的其他内容。 最佳候选者将是实际的请求参数本身。 所有“普通”请求参数都在EL范围内,由隐式EL对象 #{param} ,它引用Map<String, String> ,参数名称为key。

总而言之,这应该做到:

<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仅在调用动作事件被广播之前的Invoke Application阶段期间进行评估。 这个技巧是通过简单地扩展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}"/>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM