如果从表单触发Ajax并更新另一个表单,Facelets是否会重建整个页面? [英] Does Facelets rebuild the whole page if Ajax is trigger from a form and updates another?

查看:44
本文介绍了如果从表单触发Ajax并更新另一个表单,Facelets是否会重建整个页面?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

设置: 我有2种表格A和乙 我有一个A型的CommandLink:

<h:commandLink actionListener="#{homeView.selectDiv('homeUpdates')}">#{msg.homeUpdates}
   <f:ajax render=":B" execute="@this" />
</h:commandLink>

...将更新表格B.

问题是,当我单击ajax链接时,它也会重新生成A形,并从我拥有的ui:repeat中获取异常.这是正确的行为吗?它也应该重建表格A吗?

我正在使用JSF 2.2,并且表单A包含ui:fragment => ui:include => ui:repeat

=====添加了SSCCE ======= 按下更新B后,以下代码将无法运行!两次.它给出了重复ID的例外. ui:repeat的值不相关

<h:head>
</h:head>

<h:body>
    <h:form id="A">
        <ul class="tableView notification">
            <ui:repeat var="notification" value="#{dashboardBean.notifications}">
                <li>
                    xx
                </li>
            </ui:repeat>
        </ul>

        <h:commandLink value="Update B!" listener="#{dashboardBean.toggleRendered}">
            <f:ajax execute="@this" render=":B" />
        </h:commandLink>

    </h:form>

    <h:form id="B">
    </h:form>
</h:body>

解决方案

在初始请求时,将创建视图,回发后将恢复该视图.为了清楚起见,请列举 JSF 2.2规范的要点(强调我的观点):

P. 2.2.1 :

如果请求不是回发...在ViewHandler上调用 createView().如果请求是回发,则...调用ViewHandler. restoreView(),为当前请求传递FacesContext实例和视图标识符,并为还原后的视图返回UIViewRoot.

P. 2.5.8 :

可以对JSF视图中的

选择的组件进行优先处理(称为部分处理),并且可以将选择的组件呈现给客户端(称为部分渲染).

P. 13.4 :

可以将JavaServer Faces生命周期视为执行阶段和呈现阶段.部分遍历是一种可用于访问"视图中的一个或多个组件的技术,有可能使它们通过请求处理生命周期的执行"和/或呈现"阶段.

使用AJAX时,PartialViewContext类将包含遍历还原的视图所需的所有信息.


因此,要回到您的问题,在<f:ajax render=":B" execute="@this" />设置下,将仅呈现具有id="B"的表单,这表示<h:form id="B">,没有表单嵌套等.

关于您的无效"评论,带有纯视图范围的托管Bean的简单测试用例为我带来了预期的结果:

<h:form id="A" >
    <h:outputText value="#{twoFormsBean.a}"/>
    <h:commandLink actionListener="#{twoFormsBean.actionA}">
        Update B!
        <f:ajax execute="@this" render=":B"/>
    </h:commandLink>
</h:form>
<h:form id="B" >
    <h:outputText value="#{twoFormsBean.b}"/>
    <h:commandLink>
        Update Both!
        <f:ajax execute="@this" render=":A :B"/>
    </h:commandLink>
</h:form>

使用

@ManagedBean
@ViewScoped
public class TwoFormsBean implements Serializable {

    private String a = "A";//getter
    private String b = "B";//getter

    public void actionA(ActionEvent ae) {
        a = "newA";
        b = "newB";
    }

}

Setup: I have 2 forms A & B I have a commandLink in form A:

<h:commandLink actionListener="#{homeView.selectDiv('homeUpdates')}">#{msg.homeUpdates}
   <f:ajax render=":B" execute="@this" />
</h:commandLink>

...which updates form B.

The problem is that when I click the ajax link, it rebuilds form A as well and gets an exception from a ui:repeat I have. Is this correct behaviour? Should it rebuild form A as well?

I am using JSF 2.2 and form A contains a ui:fragment=>ui:include=>ui:repeat

=====Added SSCCE======= The following code does not run after pressing Update B! twice. It gives an exception of duplicate id. The value for ui:repeat is irrelevant

<h:head>
</h:head>

<h:body>
    <h:form id="A">
        <ul class="tableView notification">
            <ui:repeat var="notification" value="#{dashboardBean.notifications}">
                <li>
                    xx
                </li>
            </ui:repeat>
        </ul>

        <h:commandLink value="Update B!" listener="#{dashboardBean.toggleRendered}">
            <f:ajax execute="@this" render=":B" />
        </h:commandLink>

    </h:form>

    <h:form id="B">
    </h:form>
</h:body>

解决方案

Upon initial request the view is created, upon postbacks the view is restored. To recite some points of JSF 2.2 specification for clarity (emphasis mine):

P. 2.2.1:

If the request is not a postback ... call createView() on the ViewHandler. If the request is a postback, ... call ViewHandler.restoreView(), passing the FacesContext instance for the current request and the view identifier, and returning a UIViewRoot for the restored view.

P. 2.5.8:

Selected components in a JSF view can be priocessed (known as partial processing) and selected components can be rendered to the client (known as partial rendering).

P. 13.4:

The JavaServer Faces lifecycle, can be viewed as consisting of an execute phase and a render phase. Partial traversal is the technique that can be used to "visit" one or more components in the view, potentially to have them pass through the "execute" and/or "render" phases of the request processing lifecycle.

When you use AJAX, PartialViewContext class will contain all the information that's needed to traverse the restored view.


So, to get back to your question, under <f:ajax render=":B" execute="@this" /> setup, only the form with id="B" will be rerendered, which implies <h:form id="B">, no form nestings, etc.

Regarding your 'doesn't work' comment the simple test case with a plain view scoped managed bean gave me the expected results:

<h:form id="A" >
    <h:outputText value="#{twoFormsBean.a}"/>
    <h:commandLink actionListener="#{twoFormsBean.actionA}">
        Update B!
        <f:ajax execute="@this" render=":B"/>
    </h:commandLink>
</h:form>
<h:form id="B" >
    <h:outputText value="#{twoFormsBean.b}"/>
    <h:commandLink>
        Update Both!
        <f:ajax execute="@this" render=":A :B"/>
    </h:commandLink>
</h:form>

with

@ManagedBean
@ViewScoped
public class TwoFormsBean implements Serializable {

    private String a = "A";//getter
    private String b = "B";//getter

    public void actionA(ActionEvent ae) {
        a = "newA";
        b = "newB";
    }

}

这篇关于如果从表单触发Ajax并更新另一个表单,Facelets是否会重建整个页面?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆