家长:
<p:selectOneMenu id="parentList"
value="#{bean.selectedParent}"
converter="#{parentConverter}"
required="true">
<f:selectItem itemLabel="Select" itemValue="#{null}"/>
<f:selectItems var="parent"
value="#{bean.parentList}"
itemLabel="#{parent.parentName}"
itemValue="#{parent}"/>
<p:ajax update="childrenList" listener="#{bean.setchildren}"/>
</p:selectOneMenu>
child :
<p:selectOneMenu id="childrenList"
value="#{bean.selectedchild}"
converter="#{childConverter}"
required="true">
<f:selectItem itemLabel="Select" itemValue="#{null}"/>
<f:selectItems var="child"
value="#{bean.childrenList}"
itemLabel="#{child.childName}"
itemValue="#{child}"/>
</p:selectOneMenu>
托管 bean:
@Named
@ViewScoped
public class Bean implements Serializable {
@Inject
private Service service;
private Parent selectedParent;
private Child selectedChild;
private List<Parent> parentList;
private List<Child> childrenList;
private static final long serialVersionUID = 1L;
public Bean() {}
@PostConstruct
private void init() {
parentList = service.getParentList();
// Not necessary unless selectedParent is already available in edit mode.
if(selectedParent != null) {
childrenList = service.getChildrenListByParent(selectedParent);
}
}
public void setChildren() {
if(selectedParent != null) {
childrenList = service.getChildrenListByParent(selectedParent);
} else {
childrenList = null;
}
}
// Getters and setters.
}
子列表将根据其父级填充,即子列表应仅包含与特定父级关联的子级。
当选择父级列表中的第一个父级时,子级列表应重置为空,即子级在没有父级的情况下不可见。
由于父列表有一个必需的字段验证器,因此它会导致验证。当选择父列表中的第一项时,由于required="true"
,子列表将被阻止更新。从技术上讲没有什么问题,但是没有 parent 的 child 的存在可能会给最终用户带来糟糕的体验。
应该发生的是,当选择父列表中的第一项时,它不应该引起验证,即有条件地跳过验证。
执行此操作的一种方法是检查 selectedChild
或 childrenList
本身是否为 null/空。比如,
required="#{empty selectedChild or empty childrenList}"
但这似乎不是在这种情况下有条件跳过验证的规范方法。
当选择父列表中的第一项时,是否存在更好的方法来跳过验证,以便子列表也可以与父列表一起清空(验证应该在所有其他情况下引起。例如,当表单本身同步或异步提交时)?
最佳答案
基本上,您需要依赖于操作的验证。 IE。当特定 <p:ajax>
时跳过验证调用操作,而不是其他操作。
不幸的是,在 View 中声明这一点确实不简单。有几个技巧/解决方法。最常用的方法是仅检查特定操作是否被调用。
例如通过确定HTTP request parameter map中是否存在其客户端ID来检查是否调用了所需的保存按钮。由 implicit EL object 提供#{param}
:
<h:form>
<p:selectOneMenu ... required="#{not empty param[save.clientId]}">
...
<p:ajax ... />
</p:selectOneMenu>
<p:selectOneMenu ... required="true">
...
</p:selectOneMenu>
<p:commandButton binding="#{save}" ... />
</h:form>
或者检查组件是否是自己的<p:ajax>
不会通过确定组件自己的客户端 ID 是否不等于具有预定义名称 javax.faces.source
的 HTTP 请求参数来调用表示 ajax 请求的来源(下面的 #{component}
是一个隐式 EL 变量,表示当前的 UIComponent
):
<h:form>
<p:selectOneMenu ... required="#{param['javax.faces.source'] ne component.clientId}">
...
<p:ajax ... />
</p:selectOneMenu>
<p:selectOneMenu ... required="true">
...
</p:selectOneMenu>
<p:commandButton ... />
</h:form>
或者检查父表单是否由 UIForm#isSubmitted()
提交,它只会评估 true
当使用“完整表单提交”时,如process="@form"
( <p:ajax process>
默认为 @this
,不会触发“完整表单提交”, <p:commandButton process>
默认为 @form
,从而触发“完整表单提交”):
<h:form binding="#{form}">
<p:selectOneMenu ... required="#{form.submitted}">
...
<p:ajax ... />
</p:selectOneMenu>
<p:selectOneMenu ... required="true">
...
</p:selectOneMenu>
<p:commandButton ... />
</h:form>
或者通过 UIComponent#getNamingContainer()
引用表单而不绑定(bind)表单(如果您知道组件树中的位置;如果形式例如是 2 个命名容器父项,则使用 #{component.namingContainer.parent.namingContainer.submitted}
):
<h:form>
<p:selectOneMenu ... required="#{component.namingContainer.submitted}">
...
<p:ajax ... />
</p:selectOneMenu>
<p:selectOneMenu ... required="true">
...
</p:selectOneMenu>
<p:commandButton ... />
</h:form>
任你挑选。第一个解决方案之前已多次提供,因为它最容易被初学者理解和调整。
另请参阅:
关于validation - 当为空时,有条件地跳过验证 f :selectItem in p/h:selectOneMenu is selected,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31624969/