我根据我的项目创建了一个非常简单的示例,以说明我的疑问。只是一种向一个人注册电话号码的方法。
private String name;
private List<Phone> phoneList;
// Getters and Setters
@PostConstruct
private void init() {
phoneList = new ArrayList<>();
}
public static class Phone implements Serializable {
private String number;
// Getters and Setters
@Override
public String toString() {
return number != null ? number : "null";
}
}
public void add() {
phoneList.add(new Phone());
}
public void save() {
System.out.println("Name: " + name + "; " + phoneList.toString());
}
<h:form>
<h:inputText value="#{mainController.name}" required="true" />
<ui:repeat var="phone" value="#{mainController.phoneList}" varStatus="status">
<h:inputText value="#{phone.number}" required="true" />
</ui:repeat>
<h:commandButton action="#{mainController.add()}" value="Add Phone" immediate="true" />
<h:commandButton action="#{mainController.save()}" value="Save" />
</h:form>
在我的示例中,请注意添加的所有电话字段必须填写(required = true)。
问题是:当我输入名称并点击添加(添加手机)时,会保留该字段的值。但是,当我键入第一个手机并点击添加时,手机的值不会保留。对于组件ui:repeat中的所有字段都会发生这种情况。
有没有办法在即时请求后保留输入值,就像名称字段一样?
额外注意事项:我注意到的其他奇怪行为是在添加至少两个手机字段时,让第一个空白并填充第二个,然后保存表单。验证失败后(由于电话空白),单击“添加”将使所有字段都填充第二部电话的值。
Wildfly 9.0.2,JSF Api(Jboss)2.2.12
答案 0 :(得分:3)
感谢@BalusC comment。 OmniFaces库有两个可以在这种情况下使用的标记处理程序。在这两种情况下,如果验证失败,将保留输入值。请注意,h:commandButton应该与<h:commandButton immediate="false" />
。
在这种情况下,将忽略所有验证失败(包括转换器故障)。请注意,h:表单必须更改为o:form。此外,仍将显示失败消息,这可以通过在呈现的属性中放置适当的条件来解决。文件如下所示:
<o:form>
<h:inputText value="#{mainController.name}" required="true" />
<ui:repeat var="phone" value="#{mainController.phoneList}" varStatus="status">
<h:inputText value="#{phone.number}" required="true" />
</ui:repeat>
<h:commandButton action="#{mainController.add()}" value="Add Phone">
<o:ignoreValidationFailed />
</h:commandButton>
<h:commandButton action="#{mainController.save()}" value="Save" />
</o:form>
<h:messages rendered="#{facesContext.validationFailed}" />
在这种情况下,只会忽略验证失败(转换器仍会运行)。除转换器外,不会显示故障消息。请注意,此标记处理程序仅在2.3版本之后可用。文件如下所示:
<h:form>
<h:inputText value="#{mainController.name}" required="true" />
<ui:repeat var="phone" value="#{mainController.phoneList}" varStatus="status">
<h:inputText value="#{phone.number}" required="true" />
</ui:repeat>
<h:commandButton action="#{mainController.add()}" value="Add Phone">
<o:skipValidators />
</h:commandButton>
<h:commandButton action="#{mainController.save()}" value="Save" />
</h:form>
答案 1 :(得分:0)
我用于此问题的解决方案是为循环创建一个外部字段,该字段存储包含应保存的值的JSON。该字段位于循环外部,在每次尝试后正确保存值,并在必要时恢复缺失值。我使用两个函数JavaScript和JQuery库。
所以文件看起来像这样:
<h:outputScript library="jquery" name="jquery.min.js" />
<h:outputScript library="all" name="all.js" />
<h:form>
<h:inputText value="#{mainController.name}" required="true" />
<ui:repeat var="phone" value="#{mainController.phoneList}" varStatus="status">
<h:inputText styleClass="savePhoneNumber" value="#{phone.number}" required="true" onchange="saveUiRepeatInput('#{allPhoneNumber.clientId}', 'savePhoneNumber')" />
</ui:repeat>
<h:inputHidden id="allPhoneNumber" binding="#{allPhoneNumber}" />
<h:outputScript>loadUiRepeatInput('#{allPhoneNumber.clientId}', 'savePhoneNumber')</h:outputScript>
<h:commandButton action="#{mainController.add()}" value="Add Phone" immediate="true" />
<h:commandButton action="#{mainController.save()}" value="Save" />
</h:form>
function saveUiRepeatInput(inputAll, inputClass) {
document.getElementById(inputAll).value = JSON.stringify($('.' + inputClass).map(function() { return this.value; }).get());
}
function loadUiRepeatInput(inputAll, inputClass) {
var jsonAll = document.getElementById(inputAll).value;
if (jsonAll) {
var array = JSON.parse(jsonAll);
$('.' + inputClass).each(function(i) { if (i < array.length) this.value = array[i]; });
}
}
虽然工作完美(包括通过ajax,稍微改动一下),但它看起来像黑客,不是理想的解决方案。因此,如果任何人都可以帮助完全基于JSF的任何解决方案,我将不胜感激。感谢。