UIForm con prependId="falso" rompe<f: ajax render>
forms jsf (1)
Tengo una pregunta sobre la idea detrás del hecho, que solo UIForm
tiene el atributo prependId
. ¿Por qué el atributo no está especificado en la interfaz NamingContainer
? Probablemente ahora diga que se debe a la compatibilidad con versiones anteriores, pero preferiría romper la compatibilidad y permitir que los usuarios que implementan esa interfaz también implementen métodos para lo anterior.
El problema principal desde mi punto de vista sobre el prependId en el componente UIForm
es que romperá findComponent()
esperaría que si uso prependId
, el comportamiento de NamingContainer
cambiaría, no solo relacionado con el renderizado sino también al querer buscar componentes en el árbol de componentes.
Aquí un simple ejemplo:
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
Ahora cuando quiero obtener el componente panelGroup esperaría pasar el "group"
cadenas al método findComponent()
, pero no encontrará nada, en su lugar tengo que usar "test:group"
.
El problema concreto con eso es cuando se usa ajax con prependId="false"
. La etiqueta ajax espera en los atributos actualización y proceso, que los valores se preocupen de nombrar contenedores. Es un poco extraño que cuando uso prependId="false"
tenga que especificar el id completo o la ruta, pero está bien.
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
<h:form id="test1" prependId="false">
<h:commandButton value="go">
<f:ajax render="test:group"/>
</h:commandButton>
</h:form>
Bien, este código se renderizará sin problemas pero no actualizará panelGroup porque no puede encontrarlo. El PartialViewContext
contendrá solo el id "group"
como elemento de los renderIds. No sé si se espera esto, probablemente así sea, pero no conozco el código. Ahora llegamos al punto donde el método findComponent()
no puede encontrar el componente porque la expresión pasada como parámetro es "group"
donde el método esperaría que "test:group"
encuentre el componente.
Una solución es escribir tu propio findComponent()
que es la forma en que elegí tratar este problema. En este método, manejo un componente que es un NamingContainer
y tiene la propiedad prependId configurada en falso como un UIComponent
normal. Tendré que hacer eso para cada UIComponent
que ofrezca un atributo prependId y que sea malo. La reflexión ayudará a evitar la definición estática de tipos, pero todavía no es una solución realmente limpia.
La otra forma sería introducir el atributo prependId en la interfaz NamingContainer
y cambiar el comportamiento de findComponent()
para que funcione como se describió anteriormente.
La última solución propuesta sería cambiar el comportamiento de la etiqueta ajax para pasar la identificación completa, pero esto solo resolvería el problema de ajax y no los problemas programáticos detrás de la implementación de findComponent()
.
¿Qué piensas sobre eso y por qué diablos se implementa así? No puedo ser el primero en tener este problema, pero no pude encontrar temas relacionados?
De hecho, UIComponent#findComponent()
como lo hace <f:ajax render>
falla al usar <h:form prependId="false">
. Este problema se conoce y es un "No se soluciona": problema de especificación de JSF 573 .
En mi humilde opinión, nunca deberían haber agregado el atributo prependId
al UIForm
durante las edades de JSF 1.2. Simplemente se hizo para mantener j_security_check
usuarios de j_security_check
que quisieran usar un formulario JSF con componentes de entrada JSF para eso ( j_security_check
requiere nombres de campo de entrada exactos j_username
y j_password
que no pudieron ser modificados por la configuración). Pero no se dieron cuenta exactamente de que durante JSF 1.2 se introdujo otra mejora que le permite seguir usando <form>
para eso en lugar de apegarse a <h:form>
. Y luego, los puristas de CSS / jQuery comienzan a abusar de prependId="false"
para evitar el escape del carácter separador :
en sus selectores de CSS mal elegidos.
Simplemente no use prependId="false"
, alguna vez.
Para j_security_check
, simplemente use <form>
o el nuevo Servlet 3.0 HttpServletRequest#login()
. Consulte también Realizar autenticación de usuario en Java EE / JSF utilizando j_security_check .
Para los selectores de CSS, en caso de que necesite absolutamente un selector de ID (y por lo tanto no un selector de clase más reutilizable), simplemente ajuste el componente de interés en un HTML simple <div>
o <span>
.