Comment faire pour ajax-rafraîchir dynamique inclure le contenu par menu de navigation? (JSF SPA)

je viens d'apprendre JSF 2 grâce à ce site, j'ai beaucoup appris en si peu de temps.

ma question Est de savoir comment implémenter une mise en page commune à toutes mes pages JSF 2 et n'avoir que la partie contenu de la page rafraîchir pas toute la page chaque fois que je clique sur un lien/menu à partir d'un panneau différent. J'utilise L'approche Facelets il fait ce que je veux sauf que chaque fois que je clique sur un lien à partir d'un panneau (par exemple les éléments de menu à partir du panneau de gauche) la page entière est rafraîchir. Ce que je cherche est un moyen de rafraîchir seulement la partie de contenu de ma page. Pour illustrer ceci ci-dessous est mon pagelayout cible.

enter image description here N'a pas posté mon code parce que je ne suis pas sûr si les Facelets peuvent faire cela . Y a-t-il d'autres approches plus adaptées à mes besoins que les Facelets?

32
demandé sur BalusC 2011-08-18 18:03:11

3 réponses

une approche simple serait la suivante:

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

avec ce haricot:

@ManagedBean
@ViewScoped
public class Bean implements Serializable {

     private String page;

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

     // +getter+setter.
 }

dans cet exemple, les modèles include réels sont include1.xhtml , include2.xhtml et include3.xhtml dans /WEB-INF/includes dossier (dossier et l'emplacement est entièrement libre à votre choix; les fichiers sont juste placés dans /WEB-INF afin de empêcher l'accès direct en devinant L'URL dans la barre d'adresse du navigateur).

cette approche fonctionne dans toutes les versions de MyFaces, mais nécessite un minimum de Mojarra 2.3.0. Si vous utilisez une version Mojarra plus ancienne que 2.3.0, alors tout échoue lorsque la page <ui:include> contient à son tour un <h:form> . Toute publication échoue, car il est totalement absente de l'état d'affichage. Vous pouvez résoudre ce problème en mettant à jour au minimum Mojarra 2.3.0 ou avec un script trouvé dans cette réponse h:commandButton/h:commandLink ne fonctionne pas sur le premier clic, fonctionne seulement sur le deuxième clic , ou si vous utilisez déjà la bibliothèque utilitaire JSF OmniFaces , utilisez son FixViewState script . Ou, si vous utilisez déjà PrimeFaces et utilisez exclusivement <p:xxx> ajax, alors il est déjà clairement pris en compte.

aussi, assurez-vous que vous utilisez au minimum Mojarra 2.1.18 que les versions plus anciennes ne parviendront pas à garder la vue scoped bean vivante, causant la mauvaise inclure utilisé au cours de publication. Si vous ne pouvez pas mettre à niveau, alors vous devez revenir à l'approche ci-dessous (relativement maladroite) de rendre conditionnellement la vue au lieu de construire conditionnellement la vue:

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

l'inconvénient est que la vue deviendrait relativement grande et que tous les haricots gérés associés peuvent être inutilement initialisés même si elles ne seraient pas utilisées comme selon la condition rendue.

quant au positionnement parmi les éléments, il s'agit simplement d'appliquer le bon CSS. C'est au-delà de la portée du JSF :) au moins, <h:panelGroup layout="block"> rend un <div> , donc cela devrait être suffisant.

Last mais pas moins, ce SPA (Single Page Application) approche n'est pas SEO friendly. Toutes les pages ne sont pas indexables par les moteurs de recherche ni bookmarkables par les utilisateurs finaux, vous pouvez avoir besoin de bidouiller avec l'histoire HTML5 dans le client et fournir un côté serveur de repli. En outre, dans le cas de pages avec formulaires, la même instance vue scoped bean serait réutilisée à travers toutes les pages, résultant en un comportement d'établissement de la portée non intuitif lorsque vous retournez à une page déjà visitée. Je suggérerais d'aller avec l'approche de modèle à la place comme indiqué dans la deuxième partie de cette réponse: comment inclure un autre XHTML dans XHTML en utilisant JSF 2.0 Facelets? Voir aussi comment naviguer dans JSF? Comment faire pour que L'URL reflète la page actuelle (et non la précédente) .

58
répondu BalusC 2017-09-13 06:44:08

si vous ne voulez rafraîchir qu'une partie de la page, il n'y a que 2 façons d'y aller (pour le web en général, pas seulement JSF). Vous devez utiliser des cadres ou Ajax. JSF 2 supporte ajax nativement, vérifiez la balise f: ajax pour mettre à jour seulement 1 composant sans recharger la page entière.

2
répondu GBa 2011-08-18 14:14:01

Netbeans fournit un assistant qui crée la mise en page proposée avec un minimum d'effort en utilisant JSF. Ainsi, la meilleure façon de commencer est de jeter un coup d'oeil à Assistant de modèle de Facelets et de regarder la source générée.

0
répondu lu4242 2011-08-18 19:01:20