Как ajax-обновить динамическое включение контента по меню навигации?(JSF SPA) - PullRequest
34 голосов
/ 18 августа 2011

Я только изучаю JSF 2, благодаря этому сайту я многому научился за такое короткое время.

Мой вопрос касается того, как реализовать общий макет для всех моих страниц JSF 2 и чтобы только контентная часть страницы обновлялась, а не вся страница всякий раз, когда я щелкаю ссылку / меню на другой панели. Я использую подход Facelets, он делает то, что я хочу, за исключением того, что каждый раз, когда я нажимаю ссылку на панели (например, пункты меню на левой панели), вся страница обновляется. То, что я ищу, - это способ обновить только контентную часть моей страницы. Чтобы проиллюстрировать это ниже, моя цель pagelayout.

enter image description here Не опубликовал мой код, потому что я не уверен, что Facelets может сделать это. Есть ли другой подход, более подходящий для моего требования, кроме Facelets?

Ответы [ 3 ]

61 голосов
/ 19 августа 2011

Простым подходом будет следующий вид:

<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>

С этим компонентом:

@ManagedBean
@ViewScoped
public class Bean implements Serializable {

     private String page;

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

     // +getter+setter.
 }

В этом примере фактические включаемые шаблоны: include1.xhtml, include2.xhtmlи include3.xhtml в папке /WEB-INF/includes (папка и папка по вашему выбору полностью свободны; файлы просто помещаются в /WEB-INF, чтобы запретить прямой доступ путем угадывания URL-адреса в адресной строке браузера).

Этот подход работает во всех версиях 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, то это уже прозрачно учтено.

Кроме того, убедитесь, что вы используете минимально Mojarra 2.1.18, так как старые версии не будут работатьв поддержании живого объекта видимости, вызывая неправильное использование во время обратной передачи.Если вы не можете выполнить обновление, тогда вам придется вернуться к (относительно неуклюжему) подходу условной визуализации представления вместо условного построения представления:

...
<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-компоненты могут быть излишне инициализированы, даже если они не будут использоваться согласно визуализированному условию.

Что касается позиционирования элементов, то это просто вопрос применения правильного CSS,Это выходит за рамки JSF :) По крайней мере, <h:panelGroup layout="block"> отображает <div>, так что этого должно быть достаточно.

И последнее, но не менее важное, этот подход SPA (одностраничное приложение) не подходит для SEO,Все страницы не индексируются поисковыми роботами и не могут быть добавлены в закладки конечными пользователями, возможно, вам придется поиграться с историей HTML5 в клиенте и предоставить запасной вариант на стороне сервера.Более того, в случае страниц с формами один и тот же экземпляр bean-объекта области видимости будет повторно использоваться на всех страницах, что приведет к неинтуитивному поведению области видимости при переходе к ранее посещенной странице.Вместо этого я предложил бы использовать шаблонный подход, как описано во 2-й части этого ответа: Как включить еще один XHTML в XHTML с использованием JSF 2.0 Facelets? См. Также Как перемещаться в JSF?Как сделать так, чтобы URL отражал текущую (а не предыдущую) страницу .

2 голосов
/ 18 августа 2011

Если вы хотите обновить только часть страницы, есть только 2 способа (для Интернета в целом, а не только для JSF).Вы должны использовать фреймы или Ajax.JSF 2 изначально поддерживает ajax. Проверьте тег f: ajax, чтобы обновить только 1 компонент без перезагрузки всей страницы.

0 голосов
/ 18 августа 2011

Netbeans предоставляет мастер, который создает предложенный макет с минимальными усилиями, используя JSF.Итак, лучший способ начать - взглянуть на Мастер шаблонов Facelets и посмотреть на сгенерированный источник.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...