问题
我们有一个用于企业应用程序的基于wing的前端,现在正在为其实现一个(现在更简单的)JSF/Seam/Richfaces前端。
有些页面包含一些字段,这些字段在编辑后应导致其他字段发生变化。我们需要将此更改立即显示给用户(即他们不必按按钮或其他任何操作)。
我已经使用h:commandButton
并通过将onchange="submit()"
添加到导致其他字段更改的字段中来成功实现了此操作。这样,当他们编辑字段时就会提交表单,其他字段也会随之更新。
这在功能上可以正常工作,但是特别是当服务器承受大量负载(经常发生)时,表单提交可能会花费很长时间,并且我们的用户在此期间一直在继续编辑字段,然后当对onchange="submit()"
请求的响应被回复时被渲染。
为了解决这个问题,我希望能够实现以下目标:
(不稳定)解决方案
好的,我认为可能最简单的是先显示我的页面的一部分。请注意,这只是摘录,某些页面将具有许多字段和许多按钮。
<a4j:form id="mainForm">
...
<a4j:commandButton id="calculateButton" value="Calculate" action="#{illustrationManager.calculatePremium()}" reRender="mainForm" />
...
<h:outputLabel for="firstName" value=" First Name" />
<h:inputText id="firstName" value="#{life.firstName}" />
...
<h:outputLabel for="age" value=" Age" />
<h:inputText id="age" value="#{life.age}">
<f:convertNumber type="number" integerOnly="true" />
<a4j:support event="onchange" ajaxSingle="true" reRender="dob" />
</h:inputText>
<h:outputLabel for="dob" value=" DOB" />
<h:inputText id="dob" value="#{life.dateOfBirth}" styleClass="date">
<f:convertDateTime pattern="dd/MM/yyyy" timeZone="#{userPreference.timeZone}" />
<a4j:support event="onchange" ajaxSingle="true" reRender="age,dob" />
</h:inputText>
...
</a4j:form>
更改
age
的值会导致dob
的值在模型中更改,反之亦然。我使用reRender="dob"
和reRender="age,dob"
来显示模型中更改的值。这很好。我还使用全局队列来确保AJAX请求的排序。
但是,在我单击页面上的其他位置或按Tab键或其他操作之前,
onchange
事件不会发生。当用户在age
中输入一个值,然后按calculateButton
而不用单击页面上的其他位置或按Tab键时,这会导致问题。因为我可以看到
onchange
的值发生了更改,所以dob
事件确实确实首先发生了,但是在执行calculateButton
请求时,这两个值随后又恢复了。因此,最后是一个问题:是否有一种方法可以确保在发出
calculateButton
请求之前完全更新模型和 View ,以使其不还原它们?自从我使用AJAX队列以来,为什么还没有发生这种情况?解决方法
有两种策略可以解决此限制,但是它们都需要在facelet代码中膨胀,这可能会使其他开发人员感到困惑并引起其他问题。
解决方法1:使用a4j:support
该策略如下:
ajaxSingle="true"
属性添加到calculateButton
中。 a4j:support
属性的ajaxSingle="true"
标签添加到firstName
。 第一步确保
calculateButton
不会覆盖age
或dob
中的值,因为它不再处理它们。不幸的是,它具有副作用,即它也不再处理firstName
。添加第二步以通过在按下firstName
之前处理calculateButton
来消除这种副作用。请记住,尽管可能有20多个字段,例如
firstName
。用户填写表格可能会导致20多个请求到服务器!就像我之前提到的那样,这也会使其他开发人员感到困惑。解决方法2:使用进程列表
感谢@DaveMaple和@MaxKatz提出了此策略,它如下:
ajaxSingle="true"
属性添加到calculateButton
中。 process="firstName"
属性添加到calculateButton
中。 第一步可以达到与第一种解决方法相同的效果,但是具有相同的副作用。这次,第二步确保在按下
firstName
时对calculateButton
进行处理。再次提醒您,尽管可能有20多个字段(例如
firstName
)包含在此列表中。就像我之前提到的那样,这也可能会使其他开发人员感到困惑,特别是因为列表必须包含某些字段,而没有其他字段。年龄和DOB设置者和获取者(以防万一是造成问题的原因)
public Number getAge() {
Long age = null;
if (dateOfBirth != null) {
Calendar epochCalendar = Calendar.getInstance();
epochCalendar.setTimeInMillis(0L);
Calendar dobCalendar = Calendar.getInstance();
dobCalendar.setTimeInMillis(new Date().getTime() - dateOfBirth.getTime());
dobCalendar.add(Calendar.YEAR, epochCalendar.get(Calendar.YEAR) * -1);
age = new Long(dobCalendar.get(Calendar.YEAR));
}
return (age);
}
public void setAge(Number age) {
if (age != null) {
// This only gives a rough date of birth at 1/1/<this year minus <age> years>.
Calendar calendar = Calendar.getInstance();
calendar.set(calendar.get(Calendar.YEAR) - age.intValue(), Calendar.JANUARY, 1, 0, 0, 0);
setDateOfBirth(calendar.getTime());
}
}
public Date getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(Date dateOfBirth) {
if (notEqual(this.dateOfBirth, dateOfBirth)) {
// If only two digits were entered for the year, provide useful defaults for the decade.
Calendar calendar = Calendar.getInstance();
calendar.setTime(dateOfBirth);
if (calendar.get(Calendar.YEAR) < 50) {
// If the two digits entered are in the range 0-49, default the decade 2000.
calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + 2000);
} else if (calendar.get(Calendar.YEAR) < 100) {
// If the two digits entered are in the range 50-99, default the decade 1900.
calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + 1900);
}
dateOfBirth = calendar.getTime();
this.dateOfBirth = dateOfBirth;
changed = true;
}
}
最佳答案
您的bean的作用范围是什么?当执行按钮时,这是一个新请求,如果您的bean在请求范围内,则以前的值将消失。
关于jsf - 使用a4j :support to update the model and view,准备下一个按钮/提交 Action ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6024130/