jsf - 使用a4j :support to update the model and view,准备下一个按钮/提交 Action

标签 jsf richfaces seam ajax4jsf

问题

我们有一个用于企业应用程序的基于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不会覆盖agedob中的值,因为它不再处理它们。不幸的是,它具有副作用,即它也不再处理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/

    相关文章:

    java - 是否可以使用 ApplicationScoped bean 为 JSF 2 应用程序添加 richfaces 皮肤?

    java - weblogic 10.3 上的 ClassCastException jboss-seam

    java - 不评估 EL 表达式

    java - 如何为JSF配置web.xml、glassfish-web.xml文件?

    Java 设计 : Locking and Monitor reports

    jsf - 重构链接和图像

    css - JSF : Changing component style in jSTL c:foreach array not working

    java - 如何在我的 JSF 项目中使用 RESTful Web 服务?

    java - 如何从 RAMJobStore 迁移到 JobStoreCMT,以便在 Seam 中持久化 Quartz 作业

    java - 如何让 Seam Validation 在 Java EE 容器之外工作?