我有以下代码:
<h:form>
<h:inputText id="inputField" value="#{bean.myProperty}">
<f:validateLongRange
minimum="#{bean.minimum}"
maximum="#{bean.maximum}"/>
</h:inputText>
<h:commandButton id="submit" value="Submit" >
<f:ajax execute="inputField" render="outputField errors" />
</h:commandButton>
<h:outputText id="outputField" value="#{bean.myPropertyFormatted}"/>
<h:message id="errors" for="inputField"/>
</h:form>
当验证inputText失败时,我想从用户中删除/隐藏outputText。要做到这一点,最优雅、最经得起未来重构考验的方法是什么?
我尝试在outputText元素上设置属性rendered="#{!facesContext.validationFailed}"
,但这只决定是否重新呈现outputText元素,而不是保持旧文本不变。但是,当validateLongRange验证失败时,我希望从用户完全删除/隐藏outputText,因为用户将看到验证错误消息,并且不希望看到基于先前有效输入的旧输出消息,该输入仍然是存储在bean中的值。
作为JSF的经验法则,如果您想有条件地呈现任何内容,您应该将其包装在容器组件(<foo:panel/>
)中,并使容器组件成为ajax更新的目标。
<h:form>
<h:inputText id="inputField" value="#{bean.myProperty}">
<f:validateLongRange
minimum="#{bean.minimum}"
maximum="#{bean.maximum}"/>
</h:inputText>
<h:commandButton id="submit" value="Submit" >
<f:ajax execute="inputField" render="thePanel errors" />
</h:commandButton>
<h:panelGrid id="thePanel">
<h:outputText rendered="#{!facesContext.validationFailed}" id="outputField" value="#{bean.myPropertyFormatted}"/>
</h:panelGrid>
<h:message id="errors" for="inputField"/>
</h:form>
对于一个要被ajax更新的组件,它必须已经在浏览器的DOM中,这就是ajax的工作方式。因此,当您的视图最初呈现时,由于rendered
条件评估为false, outputField
不存在。因此,由于上述原因,任何后续对ajax更新的请求都将失败。容器组件策略是为了确保对标记区域进行全面更新,而不管之前的
问题是,当您将rendered
属性设置为对象并且其值为false
时,组件将不会在组件树中,因为没有呈现,并且您无法重新呈现(或更新)它。解决方案是将组件设置在UIContainer
中并呈现容器:
<h:commandButton id="submit" value="Submit" >
<f:ajax execute="inputField" render="pnlResult" />
</h:commandButton>
<h:panelGrid id="pnlResult">
<h:outputText id="outputField" value="#{bean.myPropertyFormatted}"
rendered="#{not facesContext.validationFailed}" />
<h:message id="errors" for="inputField"/>
</h:panelGrid>
根据kolossus和Luiggi Mendoza的精彩回答,我最终做了以下事情:
<h:form>
<h:inputText id="inputField" value="#{bean.myProperty}">
<f:validateLongRange
minimum="#{bean.minimum}"
maximum="#{bean.maximum}"/>
</h:inputText>
<h:commandButton id="submit" value="Submit" >
<f:ajax execute="inputField" render="outputField errors" />
</h:commandButton>
<h:panelGroup layout="block" id="outputGroup">
<h:outputText id="outputField" value="#{bean.myPropertyFormatted}" rendered="#{not facesContext.validationFailed}"/>
<h:message id="errors" for="inputField"/>
</h:panelGroup>
</h:form>
我选择了h:panelGroup
而不是h:panelGrid
,因为我的web开发背景让我对基于表格的布局的想法不寒而栗。与layout="block"
一起,h:panelGroup
被渲染为<div/>
,而h:panelGrid
被渲染为<table/>
。