如何使用EL检索JSF组件值?

时间:2009-12-21 06:34:04

标签: jsf binding components seam

在继续之前,请参阅此question

它的JSF表格再次显示如下:

<f:view>
    <h:form>
        <div>
            <label>Id</label>
            <input type="text" name="accountId"/>
        </div>
        <div>
            <label>Amount</label>
            <input type="text" name="amount"/>
        </div>
        <h:commandButton value="Withdraw" action="#{accountService.withdraw(param.accountId, param.amount)}"/>
    </h:form>
</f:view>

请注意,我使用的是<input type="text" name="amount">而不是<h:inputText id="amount">要使用Seam EL解析器检索其值,我使用param.amount

如果我使用<input type="text"并且服务器端出现问题,我需要再次显示该页面。因此,提交的值未被检索,因为它是一个普通的HTML代码。因此,我需要使用<h:inputText JSF组件。

所以问题是:如何使用表达式语言检索<h:inputText JSF组件值

3 个答案:

答案 0 :(得分:18)

JSF客户端ID以父UINamingContainer组件的cliend ID为前缀(例如h:formh:dataTablef:subview)。如果您在webbrowser中检查生成的HTML源代码(右键单击,查看源代码),那么您应该看到它们。生成的输入元素的idname前缀为父表单的id。您需要在参数映射中使用与键相同的名称。作为分隔符,冒号:是EL中的“非法”字符,您需要使用括号符号param['foo:bar']来检索它们。

<f:view>
    <h:form id="account">
        <div>
            <label>Id</label>
            <h:inputText id="id" />
        </div>
        <div>
            <label>Amount</label>
            <h:inputText id="amount" />
        </div>
        <h:commandButton value="Withdraw" 
            action="#{accountService.withdraw(param['account:id'], param['account:amount'])}"/>
    </h:form>
</f:view>

如果没有类似Seam-EL的方法参数(您显然不希望/拥有它),您也可以使用客户端ID作为键在请求参数映射中访问它们:

public void withDraw() {
    Map<String, String> map = FacesContext.getCurrentInstance().getRequestParameterMap();
    String id = map.get("account:id");
    String amount = map.get("account:amount");
    // ...
}

毋庸置疑,这是令人讨厌的。只需按照正常的JSF方式执行,使用bean属性绑定值。

根据您编辑的最终问题

编辑

  

所以问题是:如何使用表达式语言检索<h:inputText JSF组件值?

之前已经回答过。使用 JSF生成的名称作为参数名称。这通常采用formId:inputId模式,其中formId是父id组件的UIForm,而inputIdid的{​​{1}} UIInput组件。检查生成的HTML输出以获取生成的<input type="text">字段的确切名称。要获取参数值,请使用大括号['name'],因为您不能像:中那样在EL中使用冒号${param.formId:inputId}

因此:

#{param['formId:inputId']}

答案 1 :(得分:1)

inputText的参数名称/ ID由控件渲染器封装,最终是实现细节。在实践中,他们使用clientId。不需要直接从参数图中读取这些内容;使用值绑定将它们推入模型并从那里读取它们。

通过将组件绑定到托管bean,可以使用EL直接从组件读取值。为简单起见,这里绑定了请求范围:

<!-- bind a UIComponent to the request map as "foo" -->
<h:inputText binding="#{requestScope.foo}" />
<!-- read value from a UIComponent that implements ValueHolder -->
#{requestScope.foo.value}

但是,一般来说,这没有优势:

<!-- bind a value to the request map as "foo" -->
<h:inputText value="#{requestScope.foo}" />
<!-- read value from the request scope -->
#{requestScope.foo}

为避免污染请求映射(可能导致跨视图冲突),请使用托管bean命名/封装您的值,而不是直接使用请求范围。

答案 2 :(得分:0)

虽然我可以通过其客户端标识符检索JSF组件值,但有一些缺点如下:

  1. 根据McDowell的回答,客户标识符是一个实现细节
  2. 当控件层次结构中有多个命名容器时,客户端标识符可能与组件标识符不同。 (JSF in Action book)
  3. 因此,如果您不想依赖客户端标识符,您可以按如下方式实现自己的ElResolver:

    public class ComponentIdResolver extends ELResolver {
    
        public Object getValue(ELContext context, Object base, Object property) {
            if (base instanceof UIComponent && property instanceof String) {
                UIComponent r = ((UIComponent) base).findComponent((String) property);
    
                if (r != null) {
                    context.setPropertyResolved(true);
    
                    return r;
                }
            }
    
            return null;
        }
    
    }
    

    现在我可以使用类似的东西(通知撤销方法)

    <h:inputText id="accountId" />
    <h:inputText id="amount" />
    <h:commandButton value="Withdraw" action="#{accountService.withdraw(view.accountId.value, view.amount.value)}"/>
    

    view是一个隐式的JSF对象(类似于FacesContext.getCurrentInstance()。getViewRoot())

    然后注册您的ELResolver,如下所示(faces-config.xml)

    <application>
        <el-resolver>br.com.view.resolver.ComponentIdResolver</el-resolver>
    </application>
    

    如果您想了解有关ElResolver的良好见解,请参阅Extending the Java EE Unified Expression Language with a Custom ELResolver

    的问候,