Jsf 使用「;请选择";f:selectItem在p:SelectOne菜单中具有空/空值
我正在从数据库中填充一个Jsf 使用「;请选择";f:selectItem在p:SelectOne菜单中具有空/空值,jsf,primefaces,converter,jsf-2.2,selectonemenu,Jsf,Primefaces,Converter,Jsf 2.2,Selectonemenu,我正在从数据库中填充一个,如下所示 <p:selectOneMenu id="cmbCountry" value="#{bean.country}" required="true" converter="#{countryConverter}"> <f:selectItem itemLabel="Select" itemValue="#{null}"/>
,如下所示
<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"/>
<p:selectOneMenu id="cmbCountry"
value="#{stateManagedBean.selectedItem}"
required="true">
<f:selectItem itemLabel="Select" itemValue="#{null}"/>
<f:selectItems var="country"
converter="#{countryConverter}"
value="#{stateManagedBean.selectedItems}"
itemLabel="#{country.countryName}"
itemValue="${country}"/>
</p:selectOneMenu>
<p:message for="cmbCountry"/>
到
null
被一个空字符串替换,但当所讨论的对象是null
时,返回一个空字符串,这反过来会导致另一个问题,如所示
如何使这种转换器正常工作
也尝试过使用
org.omnifaces.converter.SelectItemsConverter
,但没有什么不同。你混合了一些东西,我不太清楚你想要实现什么,但让我们试试
这显然会导致抛出java.lang.NumberFormatException
在它的转换器中
里面没有什么明显的东西。若值为空或空字符串,则不签入转换器,并且应该签入。在这种情况下,转换器应该返回null
为什么它将Select(itemLabel)呈现为其值而不是空值
字符串(itemValue)
“选择”菜单必须已选择某些内容。如果不提供空值,将选择列表中的第一个元素,这不是您所期望的
只需将转换器修复为使用空/空字符串,并让JSF对返回的null
作为不允许的值作出反应。首先调用转换,然后进行验证
我希望这能回答您的问题。除了不完整之外,这个答案也被弃用,因为我在写这篇文章时使用的是Spring: 我已经修改了转换器的
getAsString()
方法,当没有发现类似的Country
对象时(除了一些其他更改),将返回空字符串,而不是返回null
这将生成以下HTML
<select id="form:cmbCountry_input" name="form:cmbCountry_input">
<option value="" selected="selected">Select</option>
<option value="56">Country1</option>
<option value="55">Country2</option>
</select>
挑选
国家1
国家2
之前,生成的HTML看起来像
<select id="form:cmbCountry_input" name="form:cmbCountry_input">
<option selected="selected">Select</option>
<option value="56">Country1</option>
<option value="55">Country2</option>
</select>
挑选
国家1
国家2
注意第一个
没有值
属性
当选择第一个选项时(即使require
设置为false),这也会像预期的那样绕过转换器工作。当itemValue
更改为非null
时,它的行为不可预测(我不理解这一点)
如果列表中的其他项目设置为非空值,并且转换器中接收的项目始终为空字符串(即使选择了其他选项),则无法选择列表中的其他项目
此外,在转换器中将此空字符串解析为Long
时,引发NumberFormatException
后产生的ConverterException
不会在UIViewRoot
中报告错误(至少应该发生这种情况)。相反,可以在服务器控制台上看到完整的异常堆栈跟踪
如果有人能透露一些信息,我会接受答案,如果答案是肯定的。这对我来说完全有效:
<p:selectOneMenu id="cmbCountry"
value="#{bean.country}"
required="true"
converter="#{countryConverter}">
<f:selectItem itemLabel="Select"/>
<f:selectItems var="country"
value="#{bean.countries}"
itemLabel="#{country.countryName}"
itemValue="#{country}"/>
<p:ajax update="anotherMenu" listener=/>
</p:selectOneMenu>
当select项值为
null
时,JSF将不会呈现
,而只呈现
。因此,浏览器将提交选项的标签。这在(我的重点)中有明确规定:
value=cdata[CS]
此属性指定控件的初始值如果未设置此属性,则初始值将设置为选项元素的内容。
您还可以通过查看HTTP流量监视器来确认这一点。您应该看到正在提交的选项标签
您需要将“选择项”值改为空字符串。然后JSF将呈现一个
。如果您使用的是转换器,那么当值为null
时,您实际上应该从转换器返回一个空字符串“”
。javadoc(我的重点)中也明确规定了这一点:
getAsString
返回:如果值为null,则返回长度为零的字符串,否则返回转换结果
因此,如果将
与这样的转换器结合使用,则会呈现
,浏览器将只提交一个空字符串,而不是选项标签
至于处理空字符串提交值(或null
),实际上应该让转换器将此职责委托给required=“true”
属性。因此,当传入的值
为null
或空字符串时,您应该立即返回null
。基本上,实体转换器的实现应如下所示:
@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);
}
至于你在这方面的特殊问题
但是,当所讨论的对象为null时返回空字符串,反过来又会导致另一个问题,如所示
正如那边所回答的,这是Mojarra中的一个bug,在OmniFaces 1.8中被绕过了
。因此,如果您至少升级到OmniFaces 1.8.3,并使用其
而不是
,那么您就不会再受到此错误的影响
OmniFacesSelectItemsConverter
在这种情况下也可以正常工作。它返回一个空字符串,表示null
- 如果要避免所选组件的空值,最优雅的方法是使用
noselection选项
noSelectionOption=“true”
时,转换器甚至不会尝试处理该值
另外,当您将其与
结合使用时,当用户尝试选择该选项时,您将得到一个验证错误
最后一次触摸,您可以使用itemsabled
属性向用户明确说明他不能使用此选项
<p:selectOneMenu id="cmbCountry"
value="#{bean.country}"
required="true"
converter="#{countryConverter}">
<f:selectItem itemLabel="Select"
noSelectionOption="true"
itemDisabled="true"/>
<f:selectItems var="country"
value="#{bean.countries}"
itemLabel="#{country.countryName}"
itemValue="#{country}"/>
<p:ajax update="anotherMenu" listener=/>
</p:selectOneMenu>
<p:message for="cmbCountry"/>
- 现在,如果您确实希望能够设置空值,您可以使用“欺骗”转换器以返回空值
<f:selectItem itemLabel="Select" itemValue="" />
在getAsO中
<select id="form:cmbCountry_input" name="form:cmbCountry_input">
<option selected="selected">Select</option>
<option value="56">Country1</option>
<option value="55">Country2</option>
</select>
<p:selectOneMenu id="cmbCountry"
value="#{bean.country}"
required="true"
converter="#{countryConverter}">
<f:selectItem itemLabel="Select"/>
<f:selectItems var="country"
value="#{bean.countries}"
itemLabel="#{country.countryName}"
itemValue="#{country}"/>
<p:ajax update="anotherMenu" listener=/>
</p:selectOneMenu>
@Controller
@Scope("request")
public final class CountryConverter implements Converter {
@Autowired
private final transient Service service = null;
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.trim().equals("")) {
return null;
}
//....
// No change
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return value == null ? null : value instanceof Country ? ((Country) value).getCountryId().toString() : null;
//**** Returns an empty string, when no Country is found ---> wrong should return null, don't care about the rendering.
}
}
@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);
}
<p:selectOneMenu id="cmbCountry"
value="#{bean.country}"
required="true"
converter="#{countryConverter}">
<f:selectItem itemLabel="Select"
noSelectionOption="true"
itemDisabled="true"/>
<f:selectItems var="country"
value="#{bean.countries}"
itemLabel="#{country.countryName}"
itemValue="#{country}"/>
<p:ajax update="anotherMenu" listener=/>
</p:selectOneMenu>
<p:message for="cmbCountry"/>
<f:selectItem itemLabel="Select" itemValue="" />
public void limparSelecao(AjaxBehaviorEvent evt) {
Object submittedValue = ((UIInput)evt.getSource()).getSubmittedValue();
if (submittedValue != null) {
getPojo().setTipoCaixa(null);
}
}
<p:selectOneMenu id="tipo"
value="#{cadastroCaixaMonitoramento.pojo.tipoCaixa}"
immediate="true"
required="true"
valueChangeListener="#{cadastroCaixaMonitoramento.selecionarTipoCaixa}">
<f:selectItem itemLabel="Selecione" itemValue="SELECIONE" noSelectionOption="false"/>
<f:selectItems value="#{cadastroCaixaMonitoramento.tiposCaixa}"
var="tipo" itemValue="#{tipo}"
itemLabel="#{tipo.descricao}" />
<p:ajax process="tipo"
update="iten_monitorado"
event="change" listener="#{cadastroCaixaMonitoramento.limparSelecao}" />
</p:selectOneMenu>