在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中的事件不再被触发。
如何使这个想法可行? (通过复选框inputtext控件显示,使其为必选,通过复选框再次隐藏,并使其非必选)
答案 0 :(得分:3)
让我们开始说,您对JSF生命周期以及何时发生的事情感到惊讶。
使用以下事件处理程序,不带任何execMode="partial"
:
<xp:eventHandler event="onclick"
submit="true" refreshMode="partial"
refreshId="pnlInterest">
您正在告诉服务器“重新执行”整个页面(这不是一个好习惯,因为服务器实际上没有跳过,因此您实际上无法有效地跳过服务器的页面哪些部分)有效部分(这是一个典型示例),其中包含xp:inputText required="true"
。验证阶段失败是因为输入为空-它不知道您不再需要输入-因此跳过了其他后续阶段,包括再次隐藏输入。
您可以通过在eventHandler中添加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"
不会受到干扰)。