我们有一个基于swing的前端用于企业应用程序,现在正在为它实现一个(现在更简单)JSF / Seam / Richfaces前端。
某些页面包含的字段在编辑时应导致其他字段因此而更改。我们需要立即向用户显示此更改(即他们不必按下按钮或任何其他内容)。
我已成功使用h:commandButton
并将onchange="submit()"
添加到导致其他字段更改的字段中。这样,表单提交在他们编辑字段时发生,其他字段也会因此而更新。
这在功能上运行良好,但特别是当服务器处于显着负载(经常发生)时,表单提交可能需要很长时间,我们的用户在此期间继续编辑字段,然后在响应时恢复<{1}}请求已呈现。
为了解决这个问题,我希望能够实现以下目标:
好吧,我认为首先展示一下我的页面可能是最容易的。请注意,这只是一个摘录,有些页面会有很多字段和许多按钮。
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"
来显示模型中更改的值。这很好。
我也在使用全局队列来确保AJAX请求的排序。
但是,在我点击页面上的其他位置或按Tab键或其他内容之前,reRender="age,dob"
事件不会发生。当用户输入一个值onchange
,然后按age
而不点击页面上的其他位置或按Tab键时,这会导致问题。
calculateButton
事件似乎确实首先发生,因为我可以看到onchange
的值发生了变化,但是当执行dob
请求时,这两个值会被还原。
所以,最后,问题是:有没有办法确保模型和视图在calculateButton
请求发生之前完全更新,以便它不会还原它们?既然我使用的是AJAX队列,为什么还没有发生呢?
有两种策略可以解决这个限制,但它们都需要在facelet代码中膨胀,这可能会让其他开发人员感到困惑并导致其他问题。
此策略如下:
calculateButton
属性添加到ajaxSingle="true"
。calculateButton
属性的a4j:support
标记添加到ajaxSingle="true"
。第一步确保firstName
不会覆盖calculateButton
或age
中的值,因为它不再处理它们。不幸的是,它的副作用是它不再处理dob
。添加第二步以通过在按下firstName
之前处理firstName
来抵消此副作用。
请注意,虽然可能有20多个字段,例如calculateButton
。填写表单的用户可能会向服务器发出20多个请求!就像我之前提到的那样,这也可能让其他开发人员感到困惑。
感谢@DaveMaple和@MaxKatz建议这个策略,它如下:
firstName
属性添加到ajaxSingle="true"
。calculateButton
属性添加到process="firstName"
。第一步实现与第一个解决方法相同,但具有相同的副作用。这一次,第二步确保在按下时calculateButton
处理firstName
。
同样,请记住,虽然可能有20多个字段(如calculateButton
)包含在此列表中。就像我之前提到的那样,这也可能让其他开发人员感到困惑,特别是因为列表必须包含一些字段而不包括其他字段。
firstName
答案 0 :(得分:0)
你的bean的范围是什么?当执行该按钮时,它是一个新请求,如果您的bean在请求范围内,那么之前的值将消失。
答案 1 :(得分:0)
所以,最后,问题是:有没有办法确保模型和视图在进行calculateButton请求之前完全更新,以便它不会还原它们?
您可以执行的操作是在您启动ajax请求之前禁用提交按钮,直到您的ajax请求完成为止。这将有效地阻止用户按下提交按钮,直到它结算:
<a4j:support
event="onblur"
ajaxSingle="true"
onsubmit="jQuery('#mainForm\\:calculateButton').attr('disabled', 'disabled');"
oncomplete="jQuery('#mainForm\\:calculateButton').removeAttr('disabled');" />
这种方法另外有用的一件事是,如果您在最终用户身上显示“ajaxy”图像,这样他们就会直观地了解即将发生的事情。您也可以在onsubmit方法中显示此图像,然后将其隐藏在oncomplete。
修改强> 问题可能只是您需要将process属性添加到a4j:commandButton。此属性按ID指定应参与模型更新阶段的组件:
<a4j:commandButton
id="calculateButton"
value="Calculate"
action="#{illustrationManager.calculatePremium()}"
process="firstName"
reRender="mainForm" />
答案 2 :(得分:0)
我想我可以提供另一种解决方法。
我们应该在js级别上有两个标志:
var requestBlocked = false;
var requestShouldBeSentAfterBlock = false;
h:inputText
元素阻止模糊的ajax请求:
<h:inputText id="dob" onblur="requestBlocked = true;" ...
如果a4j:commandButton
为false, requestBlocked
会发送请求:
<a4j:commandButton id="calculateButton"
onkeyup="requestShouldBeSentAfterBlock = requestBlocked;
return !requestBlocked;" ...
如果a4j:support
为真, requestShouldBeSentAfterBlock
会发送请求:
<a4j:support event="onchange"
oncomplete="requestBlocked = false;
if (requestShouldBeSentAfterBlock) {
requestShouldBeSentAfterBlock = false;
document.getElementById('calculateButton').click();
}" ...
因为oncomplete
块在重新渲染所有需要的元素之后工作,所以事情将以所需的顺序工作。
答案 3 :(得分:0)
看起来有一个原因在于getter / setter中的某个地方。
例如,其中一种可能性:当没有ajaxSingle=true
和点击计算按钮时。所有值都设置为模型,因此调用setAge
和setDateOfBirth
。可能会发生这种情况,以便在setDateOfBirth
之前调用setAge
。
仔细观察setAge
方法,它实际上将日期重置为年初,即使日期已经过了正确的年份。
我建议先简化逻辑。例如,为年份和出生日分别设置了断开连接的字段,并检查问题是否仍然可以重现,以找到重现所需的最低条件。
同样从用户体验的角度来看,常见的做法是执行以下操作,因此一旦用户停止输入,事件就会触发:
<a4j:support event="onkeyup"
ajaxSingle="true"
ignoreDupResponses="true"
requestDelay="300"
reRender="..."/>