我有这个选择:
<p:selectOneMenu value="#{bean.val}">
<f:selectItem itemValue="X" itemLabel="Select" />
<f:selectItems value="#{bean.getVals()}" />
<p:ajax update="wrapper" />
</p:selectOneMenu>
这是它更新的包装:
<p:panel id="wrapper">
<p:panel rendered="#{bean.val == 'A' or bean.val == 'B'}">
<!-- insert your code here -->
</p:panel>
</p:panel>
包装器在select之外,处于同一级别。
一开始,一切都很好。包装是隐藏的。
例如,如果我选择"A",然后选择"C",包装器就会消失但是,如果我再次选择"A"或"B"和"X">(第一个"选择",选择(,包装不会消失
我在bean.val
的setter中放置了一个断点。调用中的setter用于所有选项,但对于第一个选项,调试器内的值与上一个选项相同!
但是!如果我删除验证器,它就会工作!
这就是验证器:
@FacesValidator(value="requiredSelect")
public class RequiredSelect implements Validator {
protected MessageUtil messageUtil = new MessageUtil();
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
String val = (String) value;
if ("X".equals(val)) {
FacesMessage msg = this.messageUtil.getDefaultValidationError();
throw new ValidatorException(msg);
}
}
}
以前我使用另一个验证器:
@FacesValidator(value="requiredString")
public class RequiredString implements Validator {
protected MessageUtil messageUtil = new MessageUtil();
@Override
public void validate(
FacesContext context,
UIComponent component,
Object value
) throws ValidatorException {
String val = (String) value;
if (val == null || val.trim().isEmpty()) {
FacesMessage msg = this.messageUtil.getDefaultValidationError();
throw new ValidatorException(msg);
}
}
}
但它确实没有工作,因为空字符串在菜单更改时被保存到backingbean中。因此,例如,如果您选择了"A",然后返回"(选择(,并尝试提交表单,则选择会发出错误信号,但选择的值返回为‘A’!所以是伪造的"X"值。
我正在使用Primefaces 3.4.1/Mojarra 2.1.7
您的问题有点像XY问题。您正试图使用X
选择项破解创建所需p:selectOneMenu
的方法。这需要您创建一个验证器。如果您只是将p:selectOneMenu
设为必需,并将null
用作占位符的itemValue
,则不需要处理X
,因此不需要验证器。
选择null
将导致验证失败。因此,一旦进行了选择,就不再需要渲染null
占位符。通常使用p:selectOneMenu
的hideNoSelectionOption
属性。但PrimeFaces 3.4.1。由于您不想升级,可以通过为SelectOneMenu
创建自定义渲染器来添加此行为。
创建一个新类,比如my.custom.MySelectOneMenuRenderer
,并扩展SelectOneMenuRenderer
。在这个你想@Override
的encodeInput
方法类似于:
protected SelectItem selectMeOption = new SelectItem(null, "Select");
@Override
protected void encodeInput(
FacesContext context, SelectOneMenu menu, String clientId,
List<SelectItem> selectItems, Object values, Object submittedValues,
Converter converter
) throws IOException {
String classes = menu.getStyleClass();
Pattern pattern = Pattern.compile("\bnormalSelect\b");
Matcher matcher = pattern.matcher(classes);
boolean isNormal = matcher.find();
Object value = menu.getValue();
// If there's not a class "normalSelect" and no value is set, add the
// null option as the first item
if (!isNormal) {
if (value == null) {
selectItems.add(0, selectMeOption);
}
else {
SelectItem firstOption = selectItems.get(0);
if (selectMeOption.equals(firstOption)) {
selectItems.remove(0);
}
}
}
super.encodeInput(
context, menu, clientId, selectItems, values, submittedValues,
converter
);
}
将自定义渲染器添加到faces-config.xml
中的render-kit
部分,如:
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.SelectOneMenuRenderer</renderer-type>
<renderer-class>my.custom.MySelectOneMenuRenderer</renderer-class>
</renderer>
</render-kit>
查看示例:
<p:selectOneMenu value="#{bean.val}" layout="pageDirection">
<f:selectItems value="#{bean.vals()}" />
<p:ajax update="#{empty bean.val ? '@this' : ''}" />
</p:selectOneMenu>
有关工作示例,请参阅:https://github.com/jepsar/primefaces-test/blob/so_68457571/src/main/webapp/test.xhtml
另请参阅:
- 如何对我的应用程序的每个p:selectOneMenu中的f:selectItems进行排序
请查看JSF生命周期,例如:https://www.torsten-horn.de/img/JSF-Lifecycle.gif
你会注意到,如果你把";Validator Exceptions";";"更新模型值";跳过阶段。(转发处理事件以呈现响应(。
因此你的价值";X〃;,您在验证器中认为无效的永远不会发送到bean,因此包装器不会消失。
你真正想要的是:
- 定义一个适当的";无选择选项">
- 使字段";所需">
然后,在提交时,所需字段将被视为空,并在需要的地方抛出验证器异常。
ps.:一种巧妙的方式来绕过这个";发行";是在selectOneMenu
上使用hideNoSelectionOption
;请选择";,但是用户不能切换回"显示";请选择";,一旦他做出选择:
<p:selectOneMenu value="#{bean.val}" hideNoSelectionOption="#{not empty bean.val}">
<f:selectItem itemValue="#{null}" itemLabel="Select" noSelectionOption="true" />
<f:selectItems value="#{bean.getVals()}" />
<p:ajax update="@this,wrapper" process="@this" />
</p:selectOneMenu>
已更新,将@this
添加到p:ajax
。
PS:这不适用于没有hideNoSelectionOption
的旧版本Primefaces
好吧,这是我的解决方案,多亏了狗鼻子的答案第一部分:
- 将输入更改为:
<p:selectOneMenu value="#{bean.val}" required="true">
<f:selectItem itemValue="" itemLabel="Select" />
<f:selectItems value="#{bean.getVals()}" />
<p:ajax update="wrapper" />
</p:selectOneMenu>
不需要itemValue="#{none}"
,因为默认情况下,jboss或primefaces会将空字符串自动转换为空字符串,所以我不记得了。也不需要noSelectionOption="true"
(我不了解它的范围……即使我不放它,验证也有效(
- 将文件
messages.properties
添加到包my.package
中,内容如下:
javax.faces.component.UIInput.REQUIRED = Error
javax.faces.component.UIInput.REQUIRED_detail = One or more fields are missing or wrong. Please check the form
- 然后我添加了一个
p:messages
,如下所示:
<p:messages id="messages" closable="true" showDetail="true" />
- 然后,我用这个技巧删除了重复的消息