【问题标题】:JSF lazy loading component valueJSF 延迟加载组件值
【发布时间】:2013-03-01 15:44:39
【问题描述】:

考虑一个简单的 h:outputText 组件:

<h:outputText value="#{myBean.myValue}"/>

如何在页面呈现后延迟加载该值,并在完成时显示自定义“ajax 加载”图标而不是值?

我在我的项目中使用 PrimeFaces 3.5,因此欢迎任何特定于 PF 的实现。

【问题讨论】:

    标签: jsf jsf-2 primefaces


    【解决方案1】:

    建议在页面加载后调用remoteCommand 来执行此操作(通过将autoRun 属性设置为true 来完成)并更新您的outputText

    private String myValue;
    
    // getter and setter
    
    public void initMyValue() {
      // init myValue
    }
    

    在页面上,您应该有ajaxStatus 组件用于查看加载图像,以及您的outputText。还应该有p:remoteCommand组件:

    <p:ajaxStatus style="width:16px;height:16px;" id="ajaxStatusPanel">  
      <f:facet name="start">  
        <h:graphicImage value="ajaxloading.gif" />  
      </f:facet>
      <f:facet name="complete">  
        <h:outputText value="" />
      </f:facet>  
    </p:ajaxStatus>
    
    <h:outputText id="myText" value="#{myBean.myValue}"/>
    
    <p:remoteCommand autoRun="true" actionListener="#{myBean.initMyValue}" update="myText"/>
    

    编辑:我想你想延迟加载 outputText 的值,因为它包含一些长时间运行的计算,但如果你想完全推迟 outputText 的渲染,首先添加 boolean属性,并在 initMyValue 方法的末尾将此属性设置为 true

    private boolean loaded;
    
    // getter and setter
    
    public void initMyValue() {
      // init myValue
      loaded = true;
    }
    

    在页面上重新组织如下:

    <h:panelGroup id="myPanel" layout="block">
      <h:graphicImage value="ajaxloading.gif" rendered="#{!myBean.loaded}"/>
      <h:outputText value="#{myBean.myValue}" rendered="#{myBean.loaded}"/>
    </h:panelGroup>
    
    <p:remoteCommand autoRun="true" actionListener="#{myBean.initMyValue}" update="myPanel"/>
    

    【讨论】:

    • 看起来它会工作,但也意味着 myText 将在页面呈现期间急切地加载。我怎样才能避免这种情况?我意识到我可以在支持 bean 中做到这一点,但是延迟加载它会很好。此外,在这种情况下,ajaxStatus 将是全局的——我只想显示一个加载状态来代替专门针对该组件的值。谢谢!
    • 我编辑了一个答案。我添加了部分可能更适合您的需求。
    • 是的,这在稍作调整后就可以工作了。尽管如此,对于这样一个简单的任务来说,以上所有这些都太麻烦了。没有更优雅的解决方案吗?我会写一个组件来做延迟渲染...
    • 确实,按照上面的逻辑,创建延迟加载子组件的复合组件并不难。
    • 接受您的回答。我还将提供我自己的答案以及完整的实施细节。谢谢!
    【解决方案2】:

    这就是我最终实现它的方式:

    <h:panelGroup id="loginLocation">
    <p:graphicImage library="assets" name="small-kit-loader.gif" width="16" height="16" rendered="#{empty mybean.lastLoginLocation}"></p:graphicImage> 
    <h:outputText value="#{myBean.lastLoginLocation}" rendered="#{!empty myBean.lastLoginLocation}"/>
    </h:panelGroup>
    <p:remoteCommand global="false" actionListener="#{actionBean.getUserLoginLocation(myBean.selectedUser)}" name="refreshLoginLocation" id="rc1" autoRun="true" update="loginLocation" process="@this"></p:remoteCommand>
    

    我个人对这个实现并不完全满意:

    1. 延迟加载状态存储在服务器端,而不是应该存储在客户端的位置
    2. 我必须在我的支持 bean (getUserLoginLocation) 上实现单独的方法来检索值,并将其显式存储在另一个属性 (lastLoginLocation) 中。在浏览器中渲染页面后,如果有一个惰性调用的 getter 会更简洁
    3. 不容易重复使用 - 取决于支持 bean 的“已加载”标志(在本例中为 #{empty myBean.lastLoginLocation}),并且需要操作侦听器来实际设置值。任何基于这种方法的复合组件也将依赖于支持 bean 中的特定代码。

    欢迎任何有关如何改进此代码的建议! :)

    【讨论】:

      【解决方案3】:

      您可以使用BlockUI 在加载时有条件地阻止组件。

      1. &lt;h:outputText/&gt; 上定义preRenderComponent 事件

           <h:outputText id="myText">
              <f:event name="preRenderComponent" id="started"/>
           </h:outputText>
        
      2. 定义一个&lt;p:blockUI/&gt;,事件的id作为触发器

           <p:blockUI block="myText" trigger="started" />
        

      您可以自定义 blockui 以显示图像或其他内容。

      请注意:我认为您需要这个,因为您在该组件的吸气剂中做了一些繁重的工作。知道 getter 将在该页面的生命周期中被多次调用。所以隐藏操作需要很长时间的事实不会改变事实。更好的设计是在持久范围内预加载和缓存该组件的值,而不是“加载”颤动的戏剧。

      【讨论】:

      • 试过了,但是在我的页面显示给用户之前调用了 preRenderComponent 事件侦听器。这是一个模态动态 PF 对话框 - 想知道这是否与它有关?另外,我完全理解您所说的在持久范围内缓存值 - 在这种情况下,我有 API 调用来将 IP 地址解析为位置,并且由于 API 调用的数量是有限的,除非用户实际查看数据。
      • @rootkit,现在有了更好的上下文,我可以提出更合适的解决方案。在对话框上设置dynamic="true" 以停止在页面加载时加载对话框的内容。此外,outputText 的rendered 属性可以设置为有条件的,以确保元素仅在需要时放入 DOM 中
      • 对话框已经是动态的,但我多次显示它。我希望仅在用户打开对话框时查找位置,并且由于查找需要几秒钟,我不想延迟打开对话框...
      • @rootkit 然后将 ouptutText 的 rendered 属性设置为将在按钮单击时切换的条件。如果您的 bean 是 @RequestScoped,那么您可以确保在对话框完全渲染后立即将渲染条件重置为 false 或任何默认值。发表您的观点,我可以提供代码示例
      • 为什么点击按钮?我不希望用户单击任何内容以加载值。相反,带有 autoStart=true 的 p:remoteCommand 可以调用切换“rendered”属性的方法。这几乎就是@partlov 所建议的。
      猜你喜欢
      • 1970-01-01
      • 2020-10-17
      • 2011-07-07
      • 2019-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-18
      相关资源
      最近更新 更多