jsf 2 - body - La propiedad ''appendTo'' del diálogo de Primefaces, ¿para qué sirve?
appendto dialog primefaces (2)
Tal vez sea una pregunta tonta, pero en el <p:dialog>
de appendTo
hay una propiedad que se llama appendTo
que se describe en el manual como:
Anexa el cuadro de diálogo al elemento definido por la expresión de búsqueda dada.
¿No puedo darme cuenta para qué sirve?
De la Guía del usuario de PrimeFaces (actualmente p. 185):
No coloque el diálogo dentro de las tablas, a los contenedores les gustan los divs con posicionamiento relativo o con desbordamiento no visible definido, en casos como estos, la funcionalidad podría estar rota. Esto no es una limitación sino un resultado del modelo DOM. Por ejemplo, un cuadro de diálogo dentro de una unidad de diseño, tabview, acordeón son un par de ejemplos. Lo mismo se aplica a confirmDialog también.
Puede superar esto utilizando appendTo="@(body)"
y su dialog
se adjuntará como un elemento secundario del nodo <body>
.
Una de las opciones de dialog
principal es modal
y podría terminar rápidamente con su cuadro de diálogo detrás de la superposición si no está utilizando el appendTo
como se muestra a continuación:
Consulte también http://forum.primefaces.org/viewtopic.php?f=3&t=16504
Notas:
- Antes de PrimeFaces 5.0, el atributo a establecer era
appendToBody="true"
. Esto fue cambiado por 5.0. - Si su
dialog
contiene algunos botones, no se olvide de rodearlos con<h:form>
(vea el cuadro de diálogo Construir correctamente para Primefaces )
Los documentos de PrimeFaces son un poco escasos en este punto. appendToBody
/ appendTo
(antes de 5.0) resuelve (o intenta resolver) un problema donde un componente PrimeFaces no obtiene el índice z correcto, lo que significa que no aparece antes o detrás de otros elementos de la manera correcta. Sin embargo, esta característica es problemática porque puede causar otros problemas como p: la acción del botón de comando no funciona dentro de p: dialog
tl; dr:
No utilice appendTo
/ appendToBody
. En su lugar, los diálogos (junto con ConfirmDialog y OverlayPanel) deben estar siempre en la raíz de la jerarquía de componentes, como un descendiente directo de <h:body>
. Esto hará que funcionen de forma fiable. En ese caso, usar appendTo
/ appendToBody
es necesario.
Una buena manera de lograr esto es tener uno (o varios) archivos XHTML separados para estos componentes ("dialogs.xhtml"), que luego se incluyen en su archivo o plantilla XHTML principal (por ejemplo, utilizando <ui:include>
). Otra solución es usar un <ui:define>
en combinación con un <ui:insert>
si desea que los cuadros de diálogo permanezcan en el archivo XHTML donde se usan.
Siga leyendo para más detalles :-)
El problema
Algunos componentes de PrimeFaces (como los diálogos) se deben mostrar sobre otros elementos.
Por ejemplo:
Si usa <p:dialog ...modal="true">
y hace que el diálogo esté visible, aparece un cuadro de diálogo en primer plano, que aparece sobre el resto de la página, con el resto de la página cubierta por una capa transparente . Puede ver esto, por ejemplo, en el Showcase de PF para diálogos (botón "Modal").
Detrás de escena, es decir, en el DOM de la página, suceden dos cosas:
- se crea un nuevo
<div>
(la "superposición modal") al final del<body>
. Esta div obtiene los estilos CSS:z-index: 1000; position: absolute; opacity: .30;
z-index: 1000; position: absolute; opacity: .30;
. Esto hace que sea transparente y que cubra toda la página, para obtener el efecto "modal". - el div (existente, pero invisible) del diálogo se hace visible, y obtiene el estilo
z-index: 1001; position:fixed;
z-index: 1001; position:fixed;
. Tenga en cuenta que el índice z es uno más grande que la superposición modal, por lo que el cuadro de diálogo aparece sobre la superposición.
Sin embargo , esto no siempre funciona. La razón de esto es un aspecto de CSS llamado contexto de apilamiento . Los detalles son un poco complejos, pero básicamente dice que el índice z de un elemento de página solo se compara con otros elementos dentro del mismo elemento principal. En particular, un elemento puede aparecer detrás de otro elemento aunque tenga un índice z más alto, si el elemento con el índice z alto está contenido en un elemento con un índice z más bajo .
La versión corta (segura) es: para estar seguro de que el índice z funciona como se esperaba, todos los elementos en cuestión deberían ser hermanos en el DOM .
Ahora, en esta situación particular, la superposición modal debe estar justo en la parte superior de la jerarquía DOM (es decir, dentro de <body>
), de lo contrario no puede aparecer de manera confiable sobre el resto de la página. Sin embargo, la división del diálogo en sí está en algún lugar más profundo en el DOM (correspondiente a la posición de la etiqueta <p:dialog>
en el XHTML de origen). Ahora tenemos un problema.
En la práctica, esto significa que la superposición puede aparecer sobre el cuadro de diálogo, lo que lo oculta y lo bloquea. De manera similar, si el diálogo no es modal, puede aparecer detrás de otros elementos en la página.
Lo insidioso de este problema es que depende de la estructura del resto de la página (específicamente, si el resto de la página usa CSS que crea un nuevo contexto de apilamiento). Por lo tanto, puede parecer que <p:dialog>
funciona inicialmente, luego aparece repentinamente incorrectamente después de un cambio en otro lugar.
Cómo ayuda ''appendTo''
Como se explicó anteriormente, el problema ocurre porque el HTML procesado para el componente PrimeFaces está en algún lugar en el DOM, mientras que tendría que ser un hijo directo de <body>
para que el índice z funcione correctamente.
Cuando se appendToBody
/ appendTo
, PrimeFaces incluirá Javascript en la página representada que simplemente mueve el nodo DOM del componente PrimeFaces al final de <body>
(usando la función appendTo de JQuery). De esa manera, el componente está en el lugar correcto en el DOM, y z-index funciona.
El problema con el uso de ''appendTo''
Mientras que la reorganización de DOM realizada por appendTo
resuelve el problema con CSS y z-index, introduce otro problema (potencial):
El DOM del lado del cliente ya no corresponde al estado de la página del lado del servidor mantenido por JSF (llamada la vista ).
Ahora, una de las características centrales de JSF es que espera que la estructura HTML / DOM del lado del cliente se corresponda con la vista del lado del servidor; después de todo, JSF construyó el HTML a partir de esa vista. Si se viola esa regla (generalmente mediante la manipulación del lado del cliente de DOM), obtendrá todo tipo de problemas extraños, como que JSF ignore campos o valores de formulario en un envío, o que sobrescriba parte de sus modificaciones en las actualizaciones de AJAX.
En este caso, los problemas causados por mover el nodo DOM del componente PrimeFaces incluyen:
- Si el componente PrimeFaces es parte de un
<h:form>
, no funcionará correctamente (porque no estará dentro de la etiqueta<form>
del lado del cliente debido al movimiento).
En realidad, esto se menciona en los documentos de PrimeFaces, junto con la solución: en lugar de poner el componente en un formulario, coloque un formulario dentro del componente, entonces el formulario se moverá con el componente. - Si el área donde JSF representó originalmente el componente PrimeFaces se actualiza utilizando la función AJAX de JSF, JSF eliminará el área para actualizar desde el DOM y luego procesará el componente nuevamente, ya que no sabe que se movió a otro lugar.
En versiones anteriores de PrimeFaces, esto hacía que el componente apareciera dos veces en el DOM (con el mismoid
), lo que causó problemas con los envíos posteriores. Esto se solucionó para PrimeFaces 4.0 ( Problema 5636: Dialog appendToBody & dynamic no elimina el elemento dom antiguo ), pero volvió a ocurrir en 5.0 ( problema # 367 ).
Esto muestra que este tipo de manipulación de DOM "detrás de la espalda de JSF" es bastante arriesgada y debe evitarse; por lo tanto, mi consejo es no usar appendTo
/ appendToBody
.