在继续之前,请参阅此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组件值?
答案 0 :(得分:18)
JSF客户端ID以父UINamingContainer
组件的cliend ID为前缀(例如h:form
,h:dataTable
,f:subview
)。如果您在webbrowser中检查生成的HTML源代码(右键单击,查看源代码),那么您应该看到它们。生成的输入元素的id
和name
前缀为父表单的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
,而inputId
是id
的{{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组件值,但有一些缺点如下:
因此,如果您不想依赖客户端标识符,您可以按如下方式实现自己的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
的问候,