使用“请选择" f:selectItem在p:selectOneMenu中具有空值/空值 [英] Using a "Please select" f:selectItem with null/empty value inside a p:selectOneMenu

查看:59
本文介绍了使用“请选择" f:selectItem在p:selectOneMenu中具有空值/空值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从数据库中填充一个<p:selectOneMenu/>,如下所示.

I'm populating a <p:selectOneMenu/> from database as follows.

<p:selectOneMenu id="cmbCountry" 
                 value="#{bean.country}"
                 required="true"
                 converter="#{countryConverter}">

    <f:selectItem itemLabel="Select" itemValue="#{null}"/>

    <f:selectItems var="country"
                   value="#{bean.countries}"
                   itemLabel="#{country.countryName}"
                   itemValue="#{country}"/>

    <p:ajax update="anotherMenu" listener=/>
</p:selectOneMenu>

<p:message for="cmbCountry"/>

加载此页面时默认选择的选项是

The default selected option, when this page is loaded is,

<f:selectItem itemLabel="Select" itemValue="#{null}"/>

转换器:

@ManagedBean
@ApplicationScoped
public final class CountryConverter implements Converter {

    @EJB
    private final Service service = null;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        try {
            //Returns the item label of <f:selectItem>
            System.out.println("value = " + value);

            if (!StringUtils.isNotBlank(value)) {
                return null;
            } // Makes no difference, if removed.

            long parsedValue = Long.parseLong(value);

            if (parsedValue <= 0) {
                throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "", "Message"));
            }

            Country entity = service.findCountryById(parsedValue);

            if (entity == null) {
                throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_WARN, "", "Message"));
            }

            return entity;
        } catch (NumberFormatException e) {
            throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "", "Message"), e);
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        return value instanceof Country ? ((Country) value).getCountryId().toString() : null;
    }
}

<f:selectItem>表示的菜单中选择第一项并提交表单后,在getAsObject()方法中获得的valueSelect,它是<f:selectItem>的标签-第一个列表中的项目,这是直觉上根本不需要的.

When the first item from the menu represented by <f:selectItem> is selected and the form is submitted then, the value obtained in the getAsObject() method is Select which is the label of <f:selectItem> - the first item in the list which is intuitively not expected at all.

<f:selectItem>itemValue属性设置为空字符串时,即使精确捕获并注册了ConverterException异常,它也会在getAsObject()方法中抛出java.lang.NumberFormatException: For input string: "".

When the itemValue attribute of <f:selectItem> is set to an empty string then, it throws java.lang.NumberFormatException: For input string: "" in the getAsObject() method even though the exception is precisely caught and registered for ConverterException.

getAsString()return语句从更改为

return value instanceof Country?((Country)value).getCountryId().toString():null;

return value instanceof Country?((Country)value).getCountryId().toString():"";

null被一个空字符串替换,但是当所涉及的对象是null时返回一个空字符串,这又引起了另一个问题,如

null is replaced by an empty string but returning an empty string when the object in question is null, in turn incurs another problem as demonstrated here.

如何使此类转换器正常工作?

How to make such converters work properly?

也尝试使用org.omnifaces.converter.SelectItemsConverter,但这没什么区别.

Also tried with org.omnifaces.converter.SelectItemsConverter but it made no difference.

推荐答案

当选择项目值是,然后JSF将不呈现,而仅.因此,浏览器将改为提交选项的标签.这在 HTML规范中有明确规定(强调我的):

When the select item value is null, then JSF won't render <option value>, but only <option>. As consequence, browsers will submit the option's label instead. This is clearly specified in HTML specification (emphasis mine):

value = cdata [CS]

此属性指定控件的初始值. 如果未设置此属性,则将初始值设置为OPTION元素的内容.

This attribute specifies the initial value of the control. If this attribute is not set, the initial value is set to the contents of the OPTION element.

您还可以通过查看HTTP流量监视器来确认这一点.您应该看到正在提交的选项标签.

You can also confirm this by looking at HTTP traffic monitor. You should see the option label being submitted.

您需要将选择项值设置为空字符串.然后,JSF将呈现<option value="">.如果您使用的是转换器,那么当值是null时,实际上应该从转换器返回一个空字符串"".在

You need to set the select item value to an empty string instead. JSF will then render a <option value="">. If you're using a converter, then you should actually be returning an empty string "" from the converter when the value is null. This is also clearly specified in Converter#getAsString() javadoc (emphasis mine):

getAsString

...

返回:如果值为null,则返回零长度的字符串,否则返回转换结果

因此,如果将<f:selectItem itemValue="#{null}">与此类转换器结合使用,则会呈现<option value="">,浏览器将只提交一个空字符串而不是选项标签.

So if you use <f:selectItem itemValue="#{null}"> in combination with such a converter, then a <option value=""> will be rendered and the browser will submit just an empty string instead of the option label.

关于处理空字符串提交的值(或null),您实际上应该让转换器将此责任委托给required="true"属性.因此,当传入的valuenull或空字符串时,则应立即返回null. 基本上您的实体转换器应按以下方式实现:

As to dealing with the empty string submitted value (or null), you should actually let your converter delegate this responsibility to the required="true" attribute. So, when the incoming value is null or an empty string, then you should return null immediately. Basically your entity converter should be implemented like follows:

@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
    if (value == null) {
        return ""; // Required by spec.
    }

    if (!(value instanceof SomeEntity)) {
        throw new ConverterException("Value is not a valid instance of SomeEntity.");
    }

    Long id = ((SomeEntity) value).getId();
    return (id != null) ? id.toString() : "";
}

@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
    if (value == null || value.isEmpty()) {
        return null; // Let required="true" do its job on this.
    }

    if (!Utils.isNumber(value)) {
        throw new ConverterException("Value is not a valid ID of SomeEntity.");
    }

    Long id = Long.valueOf(value);
    return someService.find(id);
}

关于您对此的特殊问题,

As to your particular problem with this,

,但是当所讨论的对象为null时返回空字符串,这又引发了另一个问题,如此处.

正如在那边回答的那样,这是Mojarra中的一个错误,自OmniFaces 1.8开始在<o:viewParam>中被忽略.因此,如果至少升级到OmniFaces 1.8.3并使用其<o:viewParam>而不是<f:viewParam>,那么此错误将不再影响您.

As answered over there, this is a bug in Mojarra and bypassed in <o:viewParam> since OmniFaces 1.8. So if you upgrade to at least OmniFaces 1.8.3 and use its <o:viewParam> instead of <f:viewParam>, then you shouldn't be affected anymore by this bug.

在这种情况下,OmniFaces SelectItemsConverter也应该表现良好.它为null返回一个空字符串.

The OmniFaces SelectItemsConverter should also work as good in this circumstance. It returns an empty string for null.

这篇关于使用“请选择" f:selectItem在p:selectOneMenu中具有空值/空值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆