web-dev-qa-db-fra.com

La boîte de dialogue «appendTo» de Primefaces, à quoi sert-elle?

C'est peut-être une question idiote, mais dans <p:dialog> De Primefaces, il y a une propriété qui a appelé appendTo qui décrit dans le manuel:

Ajoute la boîte de dialogue à l'élément défini par l'expression de recherche donnée.

Je ne peux pas réaliser à quoi cela sert?

21
Anatoly

Dans le Guide de l'utilisateur PrimeFaces (actuellement p. 185):

Ne placez pas de boîte de dialogue à l'intérieur des tables, les conteneurs aiment les divs avec un positionnement relatif ou avec un débordement non visible défini, dans des cas comme ceux-ci, ces fonctionnalités peuvent être rompues. Ce n'est pas une limitation mais un résultat du modèle DOM. Par exemple, la boîte de dialogue à l'intérieur d'une unité de disposition, tabview, accordéon sont quelques exemples. Il en va de même pour confirmDialog.

Vous pouvez surmonter cela en utilisant appendTo="@(body)" et votre dialog sera attaché en tant qu'enfant du <body> noeud.

L'une des options principales de dialog est modal et vous pourriez rapidement vous retrouver avec votre boîte de dialogue derrière la superposition si vous n'utilisez pas appendTo comme indiqué ci-dessous:

enter image description here

Voir aussi http://forum.primefaces.org/viewtopic.php?f=3&t=16504


Remarques:

28
Mathieu Castets

Les documents PrimeFaces sont un peu clairsemés sur ce point. appendToBody/appendTo (avant 5.0) résout (ou tente de résoudre) un problème où un composant PrimeFaces n'obtient pas le bon z-Index, ce qui signifie qu'il n'apparaît pas avant ou derrière les autres éléments du comme il se doit. Cependant, cette fonctionnalité est problématique car elle peut provoquer d'autres problèmes comme l'action p: commandbutton ne fonctionne pas dans p: dialog

tl; dr:

N'utilisez pas appendTo/appendToBody. Au lieu de cela, les boîtes de dialogue (avec ConfirmDialog et OverlayPanel) doivent toujours être à la racine de la hiérarchie des composants, en tant que descendants directs de <h:body>. Cela les fera fonctionner de manière fiable. Dans ce cas, l'utilisation de appendTo/appendToBody n'est pas nécessaire.

Un bon moyen d'y parvenir est d'avoir un (ou plusieurs) fichiers XHTML séparés pour ces composants ("dialogs.xhtml"), qui est ensuite inclus dans votre fichier ou modèle XHTML principal (par exemple en utilisant <ui:include>). Une autre solution consiste à utiliser un <ui:define> en combinaison avec un <ui:insert> si vous souhaitez que les boîtes de dialogue restent dans le fichier XHTML où elles sont utilisées.

Lisez la suite pour plus de détails :-)


Le problème

Certains composants PrimeFaces (tels que les boîtes de dialogue) doivent être affichés au-dessus d'autres éléments.

Par exemple:

Si tu utilises <p:dialog ...modal="true">, et pour rendre la boîte de dialogue visible, vous obtenez une boîte de dialogue au premier plan, apparaissant au-dessus du reste de la page, le reste de la page étant recouvert d'un calque transparent. Vous pouvez le voir par exemple dans le PF Showcase for dialogs (bouton "Modal").

Dans les coulisses, c'est-à-dire dans le DOM de la page, deux choses se produisent:

  • un nouveau <div> (la "superposition modale") est créée à la fin du <body>. Cette div obtient les styles CSS: z-index: 1000; position: absolute; opacity: .30;. Cela le rend transparent et couvre toute la page, pour obtenir l'effet "modal".
  • la div (existante, mais invisible) de la boîte de dialogue elle-même est rendue visible et obtient le style z-index: 1001; position:fixed;. Notez que le z-index est un plus grand que la superposition modale, ainsi la boîte de dialogue apparaît au-dessus de la superposition.

Cependant , cela ne fonctionne pas toujours. La raison en est un aspect de CSS appelé contexte d'empilement . Les détails sont un peu complexes, mais en gros, cela dit que le z-index d'un élément de page n'est comparé qu'aux autres éléments du même élément parent. En particulier, un élément peut apparaître derrière un autre élément même s'il a un z-index supérieur, si l'élément avec le z-index élevé est contenu dans un élément avec un z-index inférieur.

La version courte (sûre) est: Pour être certain que z-index fonctionne comme prévu, tous les éléments concernés doivent être frères et sœurs dans le DOM.

Maintenant, dans cette situation particulière, la superposition modale doit se trouver tout en haut de la hiérarchie DOM (c'est-à-dire à l'intérieur de <body>), sinon il ne peut pas apparaître de manière fiable au-dessus du reste de la page. Cependant, le div de la boîte de dialogue elle-même est quelque part plus profond dans le DOM (correspondant à la position du <p:dialog> tag dans le XHTML source). Nous avons maintenant un problème.

En pratique, cela signifie que la superposition peut apparaître au-dessus de la boîte de dialogue, la masquant et la bloquant ainsi. De même, si la boîte de dialogue n'est pas modale, elle peut apparaître derrière d'autres éléments de la page.

La chose insidieuse à propos de ce problème est qu'il dépend de la structure du reste de la page (en particulier, si le reste de la page utilise CSS qui crée un nouveau contexte d'empilement). Donc <p:dialog> peut sembler fonctionner initialement, puis apparaît soudainement de manière incorrecte après un changement ailleurs.

Comment "appendTo" aide

Comme expliqué ci-dessus, le problème se produit car le code HTML rendu pour le composant PrimeFaces se trouve quelque part au fond du DOM, alors qu'il devrait être un enfant direct de <body> pour que le z-index fonctionne correctement.

Lorsque appendToBody/appendTo est utilisé, PrimeFaces inclura Javascript dans la page rendue qui simplement déplace le nœud DOM du composant PrimeFaces à la fin de <body> (en utilisant la fonction appendTo de JQuery). De cette façon, le composant est au bon endroit dans le DOM et le z-index fonctionne.

Le problème avec l'utilisation de "appendTo"

Alors que la réorganisation DOM effectuée par appendTo résout le problème avec CSS et z-index, elle introduit un autre problème (potentiel):

Le DOM côté client ne correspond plus à l'état de page côté serveur maintenu par JSF (appelé view).

Maintenant, l'une des principales caractéristiques de JSF est qu'il s'attend à ce que la structure HTML/DOM côté client corresponde à la vue côté serveur - après tout, JSF a construit le HTML à partir de cette vue. Si cette règle est violée (généralement en manipulant le côté client DOM), vous obtenez toutes sortes de problèmes étranges, tels que JSF ignorant les champs de formulaire ou les valeurs dans une soumission, ou écrasant une partie de vos modifications sur AJAX mises à jour.

Dans ce cas, les problèmes causés par le déplacement du nœud DOM du composant PrimeFaces incluent:

  • Si le composant PrimeFaces fait partie d'un <h:form>, il ne fonctionnera pas correctement (car il ne sera pas à l'intérieur du <form> tag côté client en raison du déplacement).
    Ceci est en fait mentionné dans les documents PrimeFaces, avec la solution de contournement: Au lieu de mettre le composant dans un formulaire, mettez un formulaire à l'intérieur le composant - alors le formulaire se déplacera avec le composant.
  • Si la zone où JSF a rendu initialement le composant PrimeFaces est mise à jour à l'aide de la fonction AJAX de JSF, JSF supprimera la zone à mettre à jour du DOM, puis restituera le composant, car il ne sait pas qu'il a été déplacé autre part.
    Dans les anciennes versions de PrimeFaces, cela faisait apparaître le composant deux fois dans le DOM (avec le même id), ce qui posait des problèmes avec les soumissions ultérieures. Ce problème a été résolu pour PrimeFaces 4.0 ( problème 5636: la boîte de dialogue appendToBody & dynamic ne supprime pas l'ancien élément dom ), mais s'est reproduite dans 5.0 ( problème # 367 ).

Cela montre que ce type de manipulation DOM "derrière le dos de JSF" est assez risqué et doit être évité - donc mon conseil de ne pas utiliser appendTo/appendToBody.

20
sleske