JSF - 如何在立即采取行动后将瞬态值保留在 ui:repeat 中
JSF - How can I retain the transient values within a ui:repeat after an immediate action
我根据我的项目创建了一个非常简单的示例来说明我的疑问。只是一种用电话 phone 号码列表注册一个人的方法。
MainController.java
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());
}
index.xhtml
<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>
在我的示例中,请注意必须填写所有添加的 phone 字段(必需 = true)。
问题是:当我键入 name 并单击 add(添加一个 phone)时字段被维护。但是,当我先键入 phone 并单击 add 时,phone 的值不会保留。对于组件 ui:repeat.
中的所有字段都会发生这种情况
有没有办法像 name 字段那样在立即请求后保留输入值?
额外说明: 我注意到的其他奇怪行为是添加至少两个 phone 字段时,让第一个空白并填充第二个,然后保存表格。验证失败后(由于 phone 空白),单击添加将使所有字段填充第二个 phone.
的值
Wildfly 9.0.2,JSF Api (Jboss) 2.2.12
我对这个问题使用的解决方案是为循环创建一个外部字段,它存储一个 JSON,其中包含应保存的值。该字段在循环之外,在每次尝试后正确保存值,并在必要时恢复缺失值。我使用两个函数 JavaScript 和 JQuery 库。
所以文件看起来像这样:
index.xhtml
<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>
all.js
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,有一些小的改动),但它看起来像是一个 hack,而不是一个理想的解决方案。因此,如果有人可以提供严格基于 JSF 的任何解决方案,我将不胜感激。谢谢
感谢@BalusC . The OmniFaces 库有两个可以在这种情况下使用的标记处理程序。在这两种情况下,输入值都将被保留以防验证失败。注意 h:commandButton 应该与 <h:commandButton immediate="false" />
.
ignoreValidationFailed
在这种情况下,所有验证失败都将被忽略(包括转换器失败)。请注意,h:form 必须更改为 o:form。此外,失败消息仍将显示,这可以通过在渲染属性中设置适当的条件来解决。这些文件将如下所示:
index.xhtml
<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}" />
skipValidators
在这种情况下,只会忽略验证失败(转换器仍会 运行)。除转换器外,不会显示故障消息。请注意,此标记处理程序仅在 2.3 版本后可用。这些文件将如下所示:
index.xhtml
<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>
我根据我的项目创建了一个非常简单的示例来说明我的疑问。只是一种用电话 phone 号码列表注册一个人的方法。
MainController.java
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());
}
index.xhtml
<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>
在我的示例中,请注意必须填写所有添加的 phone 字段(必需 = true)。
问题是:当我键入 name 并单击 add(添加一个 phone)时字段被维护。但是,当我先键入 phone 并单击 add 时,phone 的值不会保留。对于组件 ui:repeat.
中的所有字段都会发生这种情况有没有办法像 name 字段那样在立即请求后保留输入值?
额外说明: 我注意到的其他奇怪行为是添加至少两个 phone 字段时,让第一个空白并填充第二个,然后保存表格。验证失败后(由于 phone 空白),单击添加将使所有字段填充第二个 phone.
的值Wildfly 9.0.2,JSF Api (Jboss) 2.2.12
我对这个问题使用的解决方案是为循环创建一个外部字段,它存储一个 JSON,其中包含应保存的值。该字段在循环之外,在每次尝试后正确保存值,并在必要时恢复缺失值。我使用两个函数 JavaScript 和 JQuery 库。
所以文件看起来像这样:
index.xhtml
<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>
all.js
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,有一些小的改动),但它看起来像是一个 hack,而不是一个理想的解决方案。因此,如果有人可以提供严格基于 JSF 的任何解决方案,我将不胜感激。谢谢
感谢@BalusC <h:commandButton immediate="false" />
.
ignoreValidationFailed
在这种情况下,所有验证失败都将被忽略(包括转换器失败)。请注意,h:form 必须更改为 o:form。此外,失败消息仍将显示,这可以通过在渲染属性中设置适当的条件来解决。这些文件将如下所示:
index.xhtml
<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}" />
skipValidators
在这种情况下,只会忽略验证失败(转换器仍会 运行)。除转换器外,不会显示故障消息。请注意,此标记处理程序仅在 2.3 版本后可用。这些文件将如下所示:
index.xhtml
<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>