JSF Ajax Update 不更新组件

Posted

技术标签:

【中文标题】JSF Ajax Update 不更新组件【英文标题】:JSF Ajax Update not updating the component 【发布时间】:2013-01-11 02:03:51 【问题描述】:

以下是场景。我有左侧面板,其中包含所有菜单项。当我单击菜单项时,应在中心/主面板中加载相应的页面,而无需刷新页面。所以我使用 ajax(setupdate 方法)在单击菜单项时加载页面。

我的要求是为某些菜单项加载相同的页面。但是基于菜单项选择,我需要从数据库中检索记录,因此页面布局保持不变。但是我为所有菜单项提供了相同的页面。仅在第一次时,调用被发送到支持 bean,对于后续的点击,没有调用支持 bean 并且提供相同的页面。

我正在使用 PrimeFaces 3.4.1 和 JSF 2.0

注意:我正在动态加载屏幕。在客户端页面中,我使用 #menuMB.screenName 动态加载屏幕。

下面是代码sn-p。

模板页面

<f:view contentType="text/html; charset=UTF-8" encoding="UTF-8" >

        <div id="outerWrapper">

            <div id="contentWrapper">
                <div id="leftPanel">
                    <div class="companylogo">

                    </div>
                    <div class="jsmenu">
                        <ui:insert name="leftPanel">
                        </ui:insert>
                    </div>
                </div>

                <div id="mainContentWrapper">
                    <div id="pageHeader">
                        <ui:insert name="pageHeader">
                        </ui:insert>
                    </div>
                    <div id="mainContent">
                        <div id="mainStyle">
                            <ui:insert name="mainContent">
                            </ui:insert>
                        </div>
                    </div>
                </div>
                <div class="clearFloat"></div>
            </div>
            <div class="clearFloat"></div>
            <div id="footer">
                <ui:insert name="footer">
                </ui:insert>
            </div>
        </div>
    </f:view>

客户端 XHTML

所有页面都在 mainContentForm 内的 mainOutputPanel 中加载。我正在获取需要从支持 bean menuMB 加载的屏幕名称。

<h:body>
    <ui:composition template="/pages/protected/templates/layoutTemplate.xhtml">


        <ui:define name="pageHeader">
            <ui:include src="/pages/protected/templates/loginHeader.xhtml">
            </ui:include>
        </ui:define>
        <ui:define name="leftPanel">
            <h:form id="leftMainForm">
                <ui:include src="/pages/protected/templates/requestfactoryleft.xhtml">
                </ui:include>
            </h:form>
        </ui:define>
        <ui:define name="mainContent" >
            <h:form id="mainContentForm" enctype="multipart/formdata" prependId="true">
                <h:panelGroup id="mainOutputPanel" layout="block" >
                    <ui:include src="#menuMB.screenName">
                    </ui:include>
                </h:panelGroup>

            </h:form>

        </ui:define>
        <ui:define name="footer">
            <ui:include src="/pages/protected/templates/footer.xhtml">
            </ui:include>
        </ui:define>
    </ui:composition>

</h:body>

左 XHTML(包含从数据库动态加载的菜单)

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
            xmlns:ui="http://java.sun.com/jsf/facelets"
            xmlns:h="http://java.sun.com/jsf/html"
            xmlns:p="http://primefaces.org/ui"
            xmlns:f="http://java.sun.com/jsf/core" 
            xmlns:c="http://java.sun.com  /jsp/jstl/core">

     <div class="testmenu" style="padding:7px; 
             border-radius: 10px 10px 10px 10px; margin-top: 7px; 
             background: darkgray;  width: 187px;">
        <div id="rfMainMenu">
            <p:panelMenu id="rfleftMainMenu" model="#menuMB.mnuModel" >
            </p:panelMenu>
        </div>

     </div>


</ui:composition>

Backing bean(选择菜单项时动态加载页面)

@SessionScoped
@ManagedBean(name = "menuMB")
public class MenuMB implements Serializable 


    @PostConstruct
    public void loadMenu() 

      if (getLoggedUser() != null) 
          fmList = loginService.getMenuForUser(getLoggedUser());
      

    //Call createMenu method to populate the sub menu and menu items

     createMenu(fmList);
  

    public void loadScreensForUser(ActionEvent event) 
        MenuItem menuItem = (MenuItem) event.getComponent();
        String attrName;

    try 
        if (menuItem != null) 
            selectedMenuItem = menuItem.getId();

            //Get the screen name from the properties file
            menuUrl = RequestFactoryContextUtil.getResourceBundleString(menuItem.getId());

            //Set the screen name to be displayed
            setScreenName(menuUrl);

            //Call update to update the form  
          RequestContext.getCurrentInstance().update("mainContentForm:mainOutputPanel");

        


     

    catch (Exception exc) 

    

  


  private void createMenu(List<FunctionMaster> fmList) 
    //Submenu rfSubMenu = new Submenu();

    try 
        if (fmList != null) 
            for (FunctionMaster sub : fmList) 
                if (sub.getParentFunctionID() == 0) 
                    Submenu rfSubMenu = new Submenu();
                    rfSubMenu.setLabel(sub.getScreenDisplayName());
                    getMnuModel().addSubmenu(rfSubMenu);

                    for (FunctionMaster item : fmList) 
                        if (item.getParentFunctionID() != 0) 
                            if (item.getParentFunctionID() == sub.getFunctionID()) 

                                MenuItem rfSubItem = new MenuItem();

                                rfSubItem.setId(item.getFunctionName() + item.getFunctionID().toString());
                                rfSubItem.setValue(item.getScreenDisplayName());

                                rfSubItem.setImmediate(true);

                                rfSubItem.setUpdate(":mainContentForm:mainOutputPanel");
                                rfSubItem.setAjax(true);
                                rfSubItem.setRendered(true);
                                rfSubItem.setIcon("search");
                                //rfSubItem.setIcon("ui-icon-search");

                                 ExpressionFactory factory = FacesContext.getCurrentInstance().getApplication().getExpressionFactory();
                                 //rfSubItem.setActionExpression(factory.createMethodExpression(FacesContext.getCurrentInstance().getELContext(), #menuMB.loadScreenFromMenu", Void.class, new Class[]ActionEvent.class));
                                 MethodExpression methodExpr = factory.createMethodExpression(FacesContext.getCurrentInstance().getELContext(), "#menuMB.loadScreensForUser", Void.class, new Class[]ActionEvent.class);
                                 MethodExpressionActionListener actionListener = new MethodExpressionActionListener(methodExpr);
                                 rfSubItem.addActionListener(actionListener);

                                 rfSubMenu.getChildren().add(rfSubItem);
                                //addMenuItem(rfSubItem);
                            
                        
                    
                    //mnuModel.addSeparator(new Separator());

                

            
        
       catch (Exception ex) 
        String excep = ex.getMessage();
    

  


【问题讨论】:

您是否进行了调试以检查loadScreensForUser 是否已执行并且没有给出任何错误? 是的,我调试过,没有出现任何异常。正如我所说,我的支持 bean 只被调用一次,对于随后的菜单单击,我得到相同的页面 你的backing bean的范围是什么? 你是如何触发loadScreensForUser 方法的? menuMB的范围是什么?请张贴初始化菜单项的代码。 大多数情况下,使用 SessionScoped bean 支持页面是一个坏主意,主要是因为您现在遇到的原因:仅在第一次加载或工作的内容(当会话 bean 或变量在会话 bean 首先被初始化);您可以尝试为页面支持 bean 尝试更小的范围吗? 【参考方案1】:

我注意到&lt;h:body&gt; 位于&lt;ui:composition 之外,这将导致&lt;h:body&gt; 被丢弃....(&lt;ui:composition 之外的任何内容都将被忽略)

我建议您将&lt;h:body&gt; 标签放在模板本身内

【讨论】:

以上是关于JSF Ajax Update 不更新组件的主要内容,如果未能解决你的问题,请参考以下文章

通过 Ajax 更新 JSF 组件后,JavaScript/jQuery 事件侦听器不起作用

是否可以使用 JSF ajax 更新非 JSF 组件(纯 HTML)?

使用 f:ajax 时 JSF 不触发 bean setter

JSF,用ajax定期刷新一个组件?

JSF 复合组件 <f:ajax> 包含未知 id - 无法在组件的上下文中找到它

JSF 2 -- 保存所有有效的组件值