如何通过导航菜单ajax刷新动态包含内容? (JSF SPA) [英] How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)

查看:138
本文介绍了如何通过导航菜单ajax刷新动态包含内容? (JSF SPA)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于这个站点,我在这么短的时间内学到了很多东西,所以我正在学习JSF 2.

I'm just learning JSF 2 thanks to this site I had learned a lot in such a short time.

我的问题是关于如何在我的所有JSF 2页面上实现通用布局,并且每当我从其他面板中单击链接/菜单时,仅页面的内容部分而不是整个页面都刷新.我正在使用Facelets方法进行操作,只是每次单击面板中的链接(例如左侧面板中的菜单项)时都会刷新整个页面.我正在寻找的是一种仅刷新页面内容部分的方法.为了说明这一点,以下是我的目标页面布局.

My question is regarding how to implement a common layout to all my JSF 2 pages and have only the content part of the page refresh not the whole page whenever I click a link/menu from a different panel. I am using the Facelets approach it does what I want except that each time I click a link from a panel (e.g. menu items from left panel) the whole page is refreshed. What I am looking for is a way to refresh only the content part of my page. To illustrate this below is my target pagelayout.

没有发布我的代码,因为我不确定Facelets是否可以做到这一点.除了Facelets之外,还有其他方法更适合我的要求吗?

Did not post my code because I'm not sure if Facelets can do this . Are there other approach more suited for my requirement other than Facelets?

推荐答案

一种简单的方法将是以下视图:

A straightforward approach would be the following view:

<h:panelGroup id="header" layout="block">
    <h1>Header</h1>
</h:panelGroup>
<h:panelGroup id="menu" layout="block">
    <h:form>
        <f:ajax render=":content">
            <ul>
                <li><h:commandLink value="include1" action="#{bean.setPage('include1')}" /></li>            
                <li><h:commandLink value="include2" action="#{bean.setPage('include2')}" /></li>            
                <li><h:commandLink value="include3" action="#{bean.setPage('include3')}" /></li>            
            </ul>
        </f:ajax>
    </h:form>
</h:panelGroup>
<h:panelGroup id="content" layout="block">
    <ui:include src="/WEB-INF/includes/#{bean.page}.xhtml" />
</h:panelGroup>

使用此bean:

@ManagedBean
@ViewScoped
public class Bean implements Serializable {

     private String page;

     @PostConstruct
     public void init() {
         page = "include1"; //  Default include.
     }

     // +getter+setter.
 }

在此示例中,实际的包含模板是/WEB-INF/includes文件夹中的include1.xhtmlinclude2.xhtmlinclude3.xhtml(文件夹和位置完全由您选择;文件仅按顺序放置在/WEB-INF中)来阻止直接通过猜测浏览器地址栏中的URL来访问.

In this example, the actual include templates are include1.xhtml, include2.xhtml and include3.xhtml in /WEB-INF/includes folder (folder and location is fully free to your choice; the files are just placed in /WEB-INF in order to prevent direct access by guessing the URL in browser's address bar).

此方法适用于所有MyFaces版本,但最低要求为Mojarra 2.3.0.如果您使用的Mojarra版本低于2.3.0,则当<ui:include>页面包含一个<h:form>时,所有操作都会失败.任何回发都将失败,因为它完全丢失了视图状态.您可以通过至少升级到Mojarra 2.3.0或使用此答案中的脚本来解决此问题 h:commandButton/h:commandLink在第一次单击时不起作用,仅在第二次单击时起作用,或者如果您已经在使用JSF实用程序库 OmniFaces ,请使用其 FixViewState脚本.或者,如果您已经在使用PrimeFaces并专门使用<p:xxx> ajax,那么它已经被透明地考虑在内了.

This approach works in all MyFaces versions, but requires a minimum of Mojarra 2.3.0. In case you're using a Mojarra version older than 2.3.0, then this all fails when the <ui:include> page in turn contains a <h:form>. Any postback will fail because it is totally missing the view state. You can solve this by upgrading to minimally Mojarra 2.3.0 or with a script found in this answer h:commandButton/h:commandLink does not work on first click, works only on second click, or if you're already using JSF utility library OmniFaces, use its FixViewState script. Or, if you're already using PrimeFaces and exclusively use <p:xxx> ajax, then it's already transparently taken into account.

此外,请确保您使用的Mojarra 2.1.18最少,因为较旧的版本将无法保持视图范围的Bean处于活动状态,从而导致回发期间使用了错误的包含.如果无法升级,则需要退回到下面的(相对笨拙的)有条件地呈现视图而不是有条件地构建视图的方法:

Also, make sure that you're using minimally Mojarra 2.1.18 as older versions will fail in keeping the view scoped bean alive, causing the wrong include being used during postback. If you can't upgrade, then you'd need to fall back to the below (relatively clumsy) approach of conditionally rendering the view instead of conditionally building the view:

...
<h:panelGroup id="content" layout="block">
    <ui:fragment rendered="#{bean.page eq 'include1'}">
        <ui:include src="include1.xhtml" />
    </ui:fragment>
    <ui:fragment rendered="#{bean.page eq 'include2'}">
        <ui:include src="include2.xhtml" />
    </ui:fragment>
    <ui:fragment rendered="#{bean.page eq 'include3'}">
        <ui:include src="include3.xhtml" />
    </ui:fragment>
</h:panelGroup>

缺点是视图将变得相对较大,并且即使未按渲染条件使用它们,所有关联的受管Bean也可能会不必要地初始化.

The disadvantage is that the view would become relatively large and that all associated managed beans may be unnecessarily initialized even though when they would not be used as per the rendered condition.

对于元素的定位,这只是应用正确的CSS的问题.这超出了JSF的范围:)至少,<h:panelGroup layout="block">呈现了<div>,因此应该足够好.

As to positioning of the elements, that's just a matter of applying the right CSS. That's beyond the scope of JSF :) At least, <h:panelGroup layout="block"> renders a <div>, so that should be good enough.

最后但并非最不重要的是,此SPA(单页应用程序)方法不是SEO友好的.所有页面都不能被搜索机器人索引,也不能由最终用户添加书签,您可能需要在客户端中弄乱HTML5历史记录并提供服务器端的备用.而且,对于具有表单的页面,在所有页面上都将重用相同视图范围的Bean实例,从而在您导航回先前访问的页面时导致直观的作用域行为.我建议采用模板方法,而不是此答案的第二部分中概述的方法:>如何在JSF中导航?如何使URL反映当前页面(而不是上一页).

Last but not least, this SPA (Single Page Application) approach is not SEO friendly. All the pages are not indexable by searchbots nor bookmarkable by endusers, you may need to fiddle around with HTML5 history in client and provide a server side fallback. Moreover, in case of pages with forms, the very same view scoped bean instance would be reused across all pages, resulting in unintuitive scoping behavior when you navigate back to a previously visited page. I'd suggest to go with templating approach instead as outlined in 2nd part of this answer: How to include another XHTML in XHTML using JSF 2.0 Facelets? See also How to navigate in JSF? How to make URL reflect current page (and not previous one).

这篇关于如何通过导航菜单ajax刷新动态包含内容? (JSF SPA)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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