p的自定义验证器:selectOneMenu使其无法渲染/无法渲染其他组件



我有这个选择:

<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.valsetter中放置了一个断点。调用中的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:selectOneMenuhideNoSelectionOption属性。但PrimeFaces 3.4.1。由于您不想升级,可以通过为SelectOneMenu创建自定义渲染器来添加此行为。

创建一个新类,比如my.custom.MySelectOneMenuRenderer,并扩展SelectOneMenuRenderer。在这个你想@OverrideencodeInput方法类似于:

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

好吧,这是我的解决方案,多亏了狗鼻子的答案第一部分:

  1. 将输入更改为:
<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"(我不了解它的范围……即使我不放它,验证也有效(

  1. 将文件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
  1. 然后我添加了一个p:messages,如下所示:
<p:messages id="messages" closable="true" showDetail="true" />
  1. 然后,我用这个技巧删除了重复的消息

最新更新