2013-03-13 93 views
4

考虑一个简单的H:outputText组件:JSF懒加载组件值

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

我怎么能延迟加载该页面后,价值已经呈现,并且代替值,同时显示自定义“AJAX加载”图标这是正在完成?

我在我的项目中使用PrimeFaces 3.5,所以任何PF特定的实现将受到欢迎。

回答

6

建议在页面加载后(通过将autoRun属性设置为true)调用remoteCommand并更新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完全deffer呈现先加boolean在你的后台bean的属性,将此属性设置为trueinitMyValue方法的末尾:

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"/> 
+0

看起来像它会工作,但也意味着myText将在页面呈现期间急切加载。我怎样才能避免这种情况?我意识到我可以在后台bean中做到这一点,但只要延迟加载就好了。此外,在这种情况下,ajaxStatus将是全局的 - 我只想显示一个加载状态来代替专门为此组件设置的值。谢谢! – rootkit 2013-03-13 16:28:05

+0

我编辑了一个答案。我添加了可能更适合您需求的部分。 – partlov 2013-03-14 07:48:24

+0

是的,这经过一些调整后才起作用。尽管如此,对于这样一个简单的任务来说,上述所有方面都是太麻烦了。没有更优雅的解决方案吗?我会写一个组件来做懒惰的渲染...... – rootkit 2013-03-14 16:27:14

1

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

  1. 定义在<h:outputText/>

    <h:outputText id="myText"> 
         <f:event name="preRenderComponent" id="started"/> 
        </h:outputText> 
    
  2. 一个preRenderComponent事件定义<p:blockUI/>与事件的ID作为触发

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

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

谨慎的一句话:我认为你需要这个,因为你在这个组件的getter中做了一些繁重的工作。知道getter将在该页面的生命周期中多次调用。因此隐瞒手术花费很长时间的事实不会改变事实。一个更好的设计将是在一个持久的范围内预加载和缓存该组件的值,而不是“加载”跳动者的表演。

+0

尝试过,但在我的页面显示给用户之前调用preRenderComponent事件侦听器。这是一个模态动态的PF对话框 - 想知道这与它有什么关系?此外,我完全理解你在缓存持久范围中的值时所说的话 - 在这种情况下,我有API调用来将IP地址解析为位置,并且由于API调用的数量有限,我宁愿不这样做,除非用户真正查看数据。 – rootkit 2013-03-14 14:52:18

+0

@rootkit,现在有更好的上下文,我可以建议一个更合适的解决方案。在对话框中设置'dynamic =“true”'来阻止加载页面时加载对话框的内容。此外,可以使outputText的'rendered'属性有条件,以确保该元素仅在需要时才放入DOM中 – kolossus 2013-03-14 15:11:57

+0

该对话框已经是动态的,但我多次显示它。我只想在用户打开对话框时查找位置,并且由于查找需要好几秒钟,我不想延迟打开对话框...... – rootkit 2013-03-14 16:14:22

1

这是我怎么会实现它:

<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. 不容易重用 - 取决于backing bean的'loaded'标志(在这种情况下,#{empty myBean.lastLoginLocation}) ,并要求动作侦听器实际设置该值。基于这种方法的任何复合组件都将依赖于backing bean中的特定代码。

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