xp:inputtext 的验证冻结了我的 Xpage,为什么?
Validation for xp:inputtext freezes my Xpage, why?
在 Xpage 上,我有一个用于 xp:inputtext 控件的 show/hide 函数。当显示输入框时,我希望它是强制性的。
这是我的代码:
<xp:panel
styleClass="row"
id="pnlInterest">
<div class="col-sm-12">
<table>
<tr>
<td>
<xp:checkBox id="cbInterest" value="#{eventBean.event.interest}">
<xp:eventHandler event="onclick"
submit="true" refreshMode="partial"
refreshId="pnlInterest">
<xp:this.action><![CDATA[#{javascript:print("click")
print("selected " + eventBean.getEvent().getInterest())
if(eventBean.getEvent().getInterest() != "true"){
eventBean.getEvent().setYourName("");
}}]]></xp:this.action>
</xp:eventHandler></xp:checkBox>
</td>
<td>
<label class="checkbox">
<span>Are you interested in this event?
</label>
</td>
</tr>
<tr>
<td></td>
<td>
<xp:panel>
<xp:this.rendered><![CDATA[#{javascript:if ("true" == eventBean.getEvent().getInterest()){
return true;
} else{
return false;
}}]]></xp:this.rendered>
<div class="form-inline">
<div class="form-group">
<xp:inputText
id="inpYourName"
value="#{eventBean.event.yourName}" required="true">
<xp:this.attrs>
<xp:attr
name="placeholder" value="Enter your name" />
</xp:this.attrs>
<xp:this.validators>
<xp:validateRequired
message="You forgot to enter your name">
</xp:validateRequired>
</xp:this.validators></xp:inputText>
<xp:message id="msg"
for="inpYourName">
</xp:message>
</div>
</div>
</xp:panel>
</td>
</tr>
</table>
</div>
</xp:panel>
当我没有 xp:inputtext 的验证集时,显示/隐藏工作正常。但是一旦我添加它并通过复选框显示它,我就不能再隐藏它了。 onclick 中的事件不再被触发。
我怎样才能使这个想法奏效? (通过checkbox inputtext控件显示,使其成为必填项,通过checkbox再次隐藏并使其成为非必填项)
首先让我们说您对 JSF 生命周期中发生的事情和时间感到困惑。
使用以下事件处理程序,没有任何 execMode="partial"
:
<xp:eventHandler event="onclick"
submit="true" refreshMode="partial"
refreshId="pnlInterest">
您是在告诉服务器“重新执行”整个页面(这不是一个好的做法,您没有有效地判断服务器实际上可以跳过页面的哪些部分,因为它们不会发挥任何积极作用,这是一个典型的例子),包括 xp:inputText required="true"
。验证阶段失败,因为输入为空 - 它不知道您不再需要它 - 因此跳过任何其他后续阶段,包括再次隐藏输入。
您可以通过在事件处理程序中添加 disableValidators="true"
属性 来修复它。基本上,这会指示服务器跳过将为您产生预期结果的验证阶段。实际上我很少倾向于这个选项,因为您只需通过缩小执行范围来绕过它。例如,我会重构代码以使其更高效但也遵循标准(事实上,当您清除复选框时您也清除了输入,在这种情况下使用 valueChangeListener
会更好)。它可以沿着这些方向发展:
豆子
public class Controller implements Serializable {
private static final long serialVersionUID = 1L;
private String interest;
private String yourName;
public String getInterest() {
return interest;
}
public String getYourName() {
return yourName;
}
public boolean isInterested() {
return interest != null && Boolean.valueOf(interest);
}
public void setInterest(String interest) {
this.interest = interest;
}
public void setYourName(String yourName) {
this.yourName = yourName;
}
public void onInterestChange(ValueChangeEvent event) throws AbortProcessingException {
if ("true".equals(event.getNewValue())) {
setYourName(null);
}
}
}
onInterestChange
将负责在任何时候清除输入的名称值 interest
将设置为不同于布尔值 true
的值。
isInterested
方法在 xsp 上是为了方便和简洁,但如果您创建了一个布尔转换器,就可以避免所有这些麻烦。
页面
<table>
<tr>
<td>
<xp:checkBox id="cbInterest" value="#{controller.interest}"
checkedValue="true" uncheckedValue="false" valueChangeListener="#{controller.onInterestChange}">
<xp:eventHandler event="onchange" submit="true" execMode="partial" refreshMode="partial"
refreshId="rowName" />
</xp:checkBox>
</td>
<td>
<label class="checkbox">
<span>Are you interested in this event?</span>
</label>
</td>
</tr>
<xp:tr id="rowName">
<td />
<td>
<xp:div styleClass="form-inline" rendered="#{controller.interested}">
<div class="form-group">
<xp:inputText id="inpYourName" value="#{controller.yourName}"
required="true">
<xp:this.attrs>
<xp:attr name="placeholder" value="Enter your name" />
</xp:this.attrs>
<xp:this.validators>
<xp:validateRequired message="You forgot to enter your name" />
</xp:this.validators>
</xp:inputText>
<xp:message id="msg" for="inpYourName" />
</div>
</xp:div>
</td>
</xp:tr>
</table>
<xp:button value="Submit" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" />
</xp:button>
如您所见,我没有在复选框组件中使用 disableValidators="true"
。那是因为我将执行范围缩小到复选框本身。当表单实际提交时,服务器将只在复选框上执行,从而忽略视图根上的所有其他内容(这意味着没有 xp:inputText required="true"
打扰)。
在 Xpage 上,我有一个用于 xp:inputtext 控件的 show/hide 函数。当显示输入框时,我希望它是强制性的。
这是我的代码:
<xp:panel
styleClass="row"
id="pnlInterest">
<div class="col-sm-12">
<table>
<tr>
<td>
<xp:checkBox id="cbInterest" value="#{eventBean.event.interest}">
<xp:eventHandler event="onclick"
submit="true" refreshMode="partial"
refreshId="pnlInterest">
<xp:this.action><![CDATA[#{javascript:print("click")
print("selected " + eventBean.getEvent().getInterest())
if(eventBean.getEvent().getInterest() != "true"){
eventBean.getEvent().setYourName("");
}}]]></xp:this.action>
</xp:eventHandler></xp:checkBox>
</td>
<td>
<label class="checkbox">
<span>Are you interested in this event?
</label>
</td>
</tr>
<tr>
<td></td>
<td>
<xp:panel>
<xp:this.rendered><![CDATA[#{javascript:if ("true" == eventBean.getEvent().getInterest()){
return true;
} else{
return false;
}}]]></xp:this.rendered>
<div class="form-inline">
<div class="form-group">
<xp:inputText
id="inpYourName"
value="#{eventBean.event.yourName}" required="true">
<xp:this.attrs>
<xp:attr
name="placeholder" value="Enter your name" />
</xp:this.attrs>
<xp:this.validators>
<xp:validateRequired
message="You forgot to enter your name">
</xp:validateRequired>
</xp:this.validators></xp:inputText>
<xp:message id="msg"
for="inpYourName">
</xp:message>
</div>
</div>
</xp:panel>
</td>
</tr>
</table>
</div>
</xp:panel>
当我没有 xp:inputtext 的验证集时,显示/隐藏工作正常。但是一旦我添加它并通过复选框显示它,我就不能再隐藏它了。 onclick 中的事件不再被触发。
我怎样才能使这个想法奏效? (通过checkbox inputtext控件显示,使其成为必填项,通过checkbox再次隐藏并使其成为非必填项)
首先让我们说您对 JSF 生命周期中发生的事情和时间感到困惑。
使用以下事件处理程序,没有任何 execMode="partial"
:
<xp:eventHandler event="onclick"
submit="true" refreshMode="partial"
refreshId="pnlInterest">
您是在告诉服务器“重新执行”整个页面(这不是一个好的做法,您没有有效地判断服务器实际上可以跳过页面的哪些部分,因为它们不会发挥任何积极作用,这是一个典型的例子),包括 xp:inputText required="true"
。验证阶段失败,因为输入为空 - 它不知道您不再需要它 - 因此跳过任何其他后续阶段,包括再次隐藏输入。
您可以通过在事件处理程序中添加 disableValidators="true"
属性 来修复它。基本上,这会指示服务器跳过将为您产生预期结果的验证阶段。实际上我很少倾向于这个选项,因为您只需通过缩小执行范围来绕过它。例如,我会重构代码以使其更高效但也遵循标准(事实上,当您清除复选框时您也清除了输入,在这种情况下使用 valueChangeListener
会更好)。它可以沿着这些方向发展:
豆子
public class Controller implements Serializable {
private static final long serialVersionUID = 1L;
private String interest;
private String yourName;
public String getInterest() {
return interest;
}
public String getYourName() {
return yourName;
}
public boolean isInterested() {
return interest != null && Boolean.valueOf(interest);
}
public void setInterest(String interest) {
this.interest = interest;
}
public void setYourName(String yourName) {
this.yourName = yourName;
}
public void onInterestChange(ValueChangeEvent event) throws AbortProcessingException {
if ("true".equals(event.getNewValue())) {
setYourName(null);
}
}
}
onInterestChange
将负责在任何时候清除输入的名称值 interest
将设置为不同于布尔值 true
的值。
isInterested
方法在 xsp 上是为了方便和简洁,但如果您创建了一个布尔转换器,就可以避免所有这些麻烦。
页面
<table>
<tr>
<td>
<xp:checkBox id="cbInterest" value="#{controller.interest}"
checkedValue="true" uncheckedValue="false" valueChangeListener="#{controller.onInterestChange}">
<xp:eventHandler event="onchange" submit="true" execMode="partial" refreshMode="partial"
refreshId="rowName" />
</xp:checkBox>
</td>
<td>
<label class="checkbox">
<span>Are you interested in this event?</span>
</label>
</td>
</tr>
<xp:tr id="rowName">
<td />
<td>
<xp:div styleClass="form-inline" rendered="#{controller.interested}">
<div class="form-group">
<xp:inputText id="inpYourName" value="#{controller.yourName}"
required="true">
<xp:this.attrs>
<xp:attr name="placeholder" value="Enter your name" />
</xp:this.attrs>
<xp:this.validators>
<xp:validateRequired message="You forgot to enter your name" />
</xp:this.validators>
</xp:inputText>
<xp:message id="msg" for="inpYourName" />
</div>
</xp:div>
</td>
</xp:tr>
</table>
<xp:button value="Submit" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" />
</xp:button>
如您所见,我没有在复选框组件中使用 disableValidators="true"
。那是因为我将执行范围缩小到复选框本身。当表单实际提交时,服务器将只在复选框上执行,从而忽略视图根上的所有其他内容(这意味着没有 xp:inputText required="true"
打扰)。