commandButton / commandLink / ajax action / listener method no invocado o valor de entrada no establecido / actualizado

345

A veces, cuando se utiliza <h:commandLink>, <h:commandButton>o <f:ajax>, el action, actionListenero listenersimplemente no se invoca el método asociado con la etiqueta. O las propiedades del bean no se actualizan con los UIInputvalores enviados .

¿Cuáles son las posibles causas y soluciones para esto?

Muhammad Hewedy
fuente

Respuestas:

687

Introducción

Siempre que un UICommandcomponente ( <h:commandXxx>, <p:commandXxx>, etc.) no puede invocar el método de acción asociados, o un UIInputcomponente ( <h:inputXxx>, <p:inputXxxx>, etc.) no puede procesar los valores enviados y / o actualizar los valores de modelo, y usted no está viendo ninguna excepción googlable y / o advertencias en el registro del servidor, tampoco cuando configura un controlador de excepciones ajax según el manejo de excepciones en solicitudes JSF ajax , ni cuando establece el parámetro de contexto siguiente en web.xml,

<context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
</context-param>

y tampoco está viendo ningún error o advertencia de Google en la consola JavaScript del navegador (presione F12 en Chrome / Firefox23 + / IE9 + para abrir el conjunto de herramientas de desarrollador web y luego abra la pestaña Consola ), luego revise la lista a continuación de las posibles causas.

Posibles Causas

  1. UICommandy los UIInputcomponentes deben colocarse dentro de un UIFormcomponente, por ejemplo <h:form>(y, por lo tanto, no HTML simple <form>), de lo contrario no se puede enviar nada al servidor. UICommandlos componentes tampoco deben tener type="button"atributo, de lo contrario será un botón muerto que solo es útil para JavaScript onclick. Consulte también Cómo enviar valores de entrada de formulario e invocar un método en JSF bean y <h: commandButton> no inicia una devolución de datos .

  2. No puede anidar múltiples UIFormcomponentes entre sí. Esto es ilegal en HTML. El comportamiento del navegador no está especificado. ¡Cuidado con los archivos de inclusión! Puede usar UIFormcomponentes en paralelo, pero no se procesarán entre sí durante el envío. También debe tener cuidado con el antipatrón "Forma de Dios"; asegúrese de no procesar / validar involuntariamente todas las demás entradas (invisibles) en la misma forma (por ejemplo, tener un diálogo oculto con las entradas requeridas en la misma forma). Consulte también ¿Cómo usar <h: form> en la página JSF? Forma individual? Formas múltiples? Formas anidadas? .

  3. No UIInputdebería haberse producido ningún error de validación / conversión de valor. Puede usar <h:messages>para mostrar cualquier mensaje que no se muestre en ningún <h:message>componente específico de entrada . No olvide incluir el idde <h:messages>en el <f:ajax render>, si lo hay, para que también se actualice en las solicitudes de ajax. Consulte también h: messages no muestra mensajes cuando se presiona p: commandButton .

  4. Si se colocan UICommando UIInputcomponentes dentro de un componente iterativo como <h:dataTable>, <ui:repeat>etc., entonces debe asegurarse de que valuese conserve exactamente el mismo componente iterativo durante la fase de solicitud de valores de solicitud de la solicitud de envío de formulario. JSF reiterará sobre él para encontrar el enlace / botón cliqueado y los valores de entrada enviados. Poner el bean en el alcance de la vista y / o asegurarse de cargar el modelo de datos @PostConstructdel bean (y, por lo tanto, no en un método getter) debería solucionarlo. Consulte también Cómo y cuándo debo cargar el modelo de la base de datos para h: dataTable .

  5. Si una fuente dinámica incluye componentes UICommando UIInputcomponentes <ui:include src="#{bean.include}">, entonces debe asegurarse de que #{bean.include}se conserve exactamente el mismo valor durante el tiempo de creación de la vista de la solicitud de envío de formulario. JSF lo volverá a ejecutar durante la construcción del árbol de componentes. Poner el bean en el alcance de la vista y / o asegurarse de cargar el modelo de datos @PostConstructdel bean (y, por lo tanto, no en un método getter) debería solucionarlo. Consulte también ¿Cómo ajax-refresh dynamic incluye contenido por menú de navegación? (JSF SPA) .

  6. El renderedatributo del componente y todos sus elementos testprimarios y el atributo de cualquier elemento primario <c:if>/ <c:when>no deben evaluarse falsedurante la fase de solicitud de valores de solicitud del formulario de solicitud de envío. JSF lo volverá a verificar como parte de la protección contra solicitudes manipuladas / pirateadas. Almacenar las variables responsables de la condición en un @ViewScopedbean o asegurarse de que está preinicializando adecuadamente la condición @PostConstructde un @RequestScopedbean debería solucionarlo. Lo mismo se aplica al disabledatributo del componente, que no debe evaluarse truedurante la fase de solicitud de valores de solicitud. Consulte también la acción JSF CommandButton no invocada , el envío del formulario en el componente condicionalmente procesado no se procesa yh: commandButton no funciona una vez que lo envuelvo en un <h: panelGroup renderizado> .

  7. El onclickatributo del UICommandcomponente y el onsubmitatributo del UIFormcomponente no deberían retornar falseni causar un error de JavaScript. No debería, en caso de <h:commandLink>o <f:ajax>también haber errores JS visibles en la consola JS del navegador. Por lo general, buscar en Google el mensaje de error exacto ya le dará la respuesta. Consulte también Agregar / cargar manualmente jQuery con resultados de PrimeFaces en TypeErrors no capturados .

  8. Si está utilizando Ajax a través de JSF 2.xo, <f:ajax>por ejemplo <p:commandXxx>, PrimeFaces , asegúrese de tener una <h:head>plantilla maestra en lugar de la <head>. De lo contrario, JSF no podrá incluir automáticamente los archivos JavaScript necesarios que contienen las funciones de Ajax. Esto daría lugar a un error de JavaScript como "mojarra no está definido" o "PrimeFaces no está definido" en la consola JS del navegador. Ver también h: commandLink actionlistener no se invoca cuando se usa con f: ajax y ui: repeat .

  9. Si está utilizando Ajax, y los valores enviados terminan siendo null, entonces asegúrese de que los componentes UIInputy UICommandde interés estén cubiertos por <f:ajax execute>o <p:commandXxx process>, por ejemplo , de lo contrario no se ejecutarán / procesarán. Consulte también Valores de formulario enviados no actualizados en el modelo al agregar <f: ajax> a <h: commandButton> y Entender el proceso / actualización de PrimeFaces y los atributos JSF f: ajax execute / render .

  10. Si los valores enviados aún terminan siendo null, y está utilizando CDI para administrar beans, entonces asegúrese de importar la anotación del alcance desde el paquete correcto, de lo contrario, CDI volverá a los valores predeterminados para @Dependentrecrear efectivamente el bean en cada evaluación individual de EL expresión. Consulte también @SessionScoped bean pierde alcance y se recrea todo el tiempo, los campos se vuelven nulos y ¿Cuál es el alcance de Bean administrado predeterminado en una aplicación JSF 2?

  11. Si un padre del <h:form>con el UICommandbotón se ha procesado / actualizado previamente por una solicitud ajax proveniente de otro formulario en la misma página, entonces la primera acción siempre fallará en JSF 2.2 o anterior. La segunda y posteriores acciones funcionarán. Esto se debe a un error en el manejo del estado de la vista que se informa como problema 790 de especificación JSF y actualmente se soluciona en JSF 2.3. Para versiones anteriores de JSF, debe especificar explícitamente el ID de <h:form>en el renderde <f:ajax>. Consulte también h: commandButton / h: commandLink no funciona en el primer clic, solo funciona en el segundo clic .

  12. Si se <h:form>ha enctype="multipart/form-data"configurado para admitir la carga de archivos, debe asegurarse de que está utilizando al menos JSF 2.2, o que el filtro de servlet que es responsable de analizar las solicitudes de datos multiparte / formulario está configurado correctamente; de ​​lo contrario FacesServlet, terminan sin obtener ningún parámetro de solicitud y, por lo tanto, no pueden aplicar los valores de solicitud. La forma de configurar dicho filtro depende del componente de carga de archivos que se utilice. Para Tomahawk <t:inputFileUpload>, verifique esta respuesta y para PrimeFaces <p:fileUpload>, verifique esta respuesta . O, si en realidad no está cargando un archivo, elimine el atributo por completo.

  13. Asegúrese de que el ActionEventargumento de actionListenersea javax.faces.event.ActionEventy, por lo tanto java.awt.event.ActionEvent, no , que es lo que la mayoría de los IDE sugieren como primera opción de autocompletar. No tener argumento es malo también si lo usas actionListener="#{bean.method}". Si no quieres una discusión en tu método, úsalo actionListener="#{bean.method()}". O tal vez realmente quieras usar en actionlugar de actionListener. Consulte también Diferencias entre action y actionListener .

  14. Asegúrese de que ninguno PhaseListenero ninguno EventListeneren la cadena de solicitud-respuesta haya cambiado el ciclo de vida de JSF para omitir la fase de acción de invocación, por ejemplo, llamando FacesContext#renderResponse()o FacesContext#responseComplete().

  15. Asegúrese de que ninguna Filtero Servleten la misma cadena de solicitud-respuesta haya bloqueado la solicitud de FacesServletalguna manera. Por ejemplo, filtros de inicio de sesión / seguridad como Spring Security. Particularmente en las solicitudes ajax que, de forma predeterminada, terminarían sin comentarios de la interfaz de usuario. Consulte también Spring Security 4 y PrimeFaces 5 AJAX gestión de solicitudes .

  16. Si está utilizando PrimeFaces <p:dialog>o a <p:overlayPanel>, asegúrese de que tengan los suyos <h:form>. Debido a que estos componentes son reubicados por JavaScript de manera predeterminada al final de HTML <body>. Entonces, si originalmente estaban sentados dentro de a <form>, ahora ya no se sentarían en a <form>. Ver también p: commandbutton action no funciona dentro de p: dialog

  17. Error en el marco. Por ejemplo, RichFaces tiene un " error de conversión " cuando utiliza un rich:calendarelemento de la interfaz de usuario con un defaultLabelatributo (o, en algunos casos, un rich:placeholdersubelemento). Este error evita que se invoque el método del bean cuando no se establece ningún valor para la fecha del calendario. El seguimiento de los errores del marco se puede lograr comenzando con un ejemplo de trabajo simple y construyendo la página nuevamente hasta que se descubra el error.

Sugerencias de depuración

En caso de que sigas pegado, es hora de depurar. En el lado del cliente, presione F12 en el navegador web para abrir el conjunto de herramientas de desarrollador web. Haga clic en la pestaña Consola para ver el código JavaScript. Debe estar libre de errores de JavaScript. La captura de pantalla siguiente es un ejemplo de Chrome que demuestra el caso de enviar un <f:ajax>botón habilitado sin haber <h:head>declarado (como se describe en el punto 7 anterior).

consola js

Haga clic en la pestaña Red para ver el monitor de tráfico HTTP. Envíe el formulario e investigue si los encabezados de solicitud y los datos del formulario y el cuerpo de la respuesta son según las expectativas. Debajo de la captura de pantalla hay un ejemplo de Chrome que muestra un envío ajax exitoso de un formulario simple con un solo <h:inputText>y un solo <h:commandButton>con <f:ajax execute="@form" render="@form">.

monitor de red

(advertencia: cuando publique capturas de pantalla de encabezados de solicitud HTTP como las anteriores de un entorno de producción, ¡asegúrese de codificar / ofuscar cualquier cookie de sesión en la captura de pantalla para evitar ataques de secuestro de sesión!)

En el lado del servidor, asegúrese de que el servidor se inicie en modo de depuración. Coloque un punto de interrupción de depuración en un método del componente JSF de interés al que espera que se le llame durante el procesamiento del envío del formulario. Por ejemplo, en el caso del UICommandcomponente, sería UICommand#queueEvent()y en el caso del UIInputcomponente, sería UIInput#validate(). Simplemente realice la ejecución del código e inspeccione si el flujo y las variables son según las expectativas. La captura de pantalla siguiente es un ejemplo del depurador de Eclipse.

servidor de depuración

BalusC
fuente
1
tu segundo punto me hizo pensar, durante mucho tiempo. Me acabo de enterar de que una etiqueta f: view en mi archivo principal fue la causa de la mayoría de mis problemas. Y probablemente porque representa un formulario, ¿verdad?
Paulo Guedes
2
@pauloguedes No puedo encontrar nada que diga que f: view representa un formulario. Tengo entendido que es solo un contenedor. En mi experiencia, f: view no representa ningún elemento.
Lucas
@balusc Una pequeña aclaración sobre el punto 4, si el commandLink no está en la tabla de datos, ¿sigue siendo importante?
Lucas
gracias, el punto es el punto: poner el bean en el alcance de la vista y / o asegurarse de cargar el modelo de datos en el constructor (post) del bean (¡y por lo tanto no en el método getter!) debería solucionarlo.
merveotesi
2
@Kukeltje: eso habría arrojado una excepción EL (ya cubierto por el primer párrafo en la respuesta)
BalusC
54

Si h:commandLinkestá dentro de un, h:dataTablehay otra razón por la que h:commandLinkpodría no funcionar:

El origen de datos subyacente que está vinculado al h:dataTabledebe también estar disponible en el segundo ciclo de vida JSF que se activa cuando se hace clic en el enlace.

Entonces, si el origen de datos subyacente tiene un alcance de solicitud, ¡ h:commandLinkno funciona!

jbandi
fuente
2
Ok, eso no estaba del todo claro para mí. Espero que mi respuesta sea útil de todos modos, ya que en mi caso al menos no estaba tratando explícitamente con UICommand / UIData. La "solución" fue la promoción de un bean de respaldo desde la solicitud-alcance a un ámbito de sesión ...
jbandi
1
Segundo comentario de Jens ... configurar mi bean RequestScoped como SessionScoped marcó la diferencia en mi tabla de datos - gracias
Zack Macomber
28

Si bien mi respuesta no es 100% aplicable, pero la mayoría de los motores de búsqueda lo encuentran como el primer éxito, decidí publicarlo de todos modos:

Si está utilizando PrimeFaces (o alguna API similar) p:commandButtono p:commandLink, es probable que haya olvidado agregar explícitamente process="@this"a sus componentes de comando.

Como dice la Guía del usuario de PrimeFaces en la sección 3.18, los valores predeterminados para processy updateson ambos @form, lo que se opone bastante a los valores predeterminados que podría esperar de JSF simple f:ajaxo RichFaces, que son execute="@this"y render="@none"respectivamente.

Me llevó mucho tiempo descubrirlo. (... ¡y creo que es bastante incómodo usar valores predeterminados que son diferentes de JSF!)

Kawu
fuente
66
El valor predeterminado para PrimeFaces processes @form. Entonces, si la acción no se invoca de esta manera, pero lo hace cuando se usa @this, lo más probable es que se aplique el punto 3 de mi respuesta.
BalusC
3
Esto no puede ser. Tuve una p:commandButtonque no invocó el método actionListener hasta que agregué process="@this". Además, la Guía del usuario de PrimeFaces enumera explícitamente los valores predeterminados que mencioné en la sección 3.18 y 3.19. Está aquí: primefaces.googlecode.com/files/primefaces_users_guide_3_4.pdf ... ¿tal vez se modificaron los valores predeterminados?
Kawu
8
Es probable que sea un error en la documentación. Elimine process="@this"y agregue <p:messages autoUpdate="true">(o simplemente lea el registro del servidor para mensajes en cola pero no mostrados) y verá que en realidad se ha producido un error de conversión / validación.
BalusC
¿Por qué eliminar esta pregunta stackoverflow.com/questions/60673695/...
Kukeltje
Pensé que podría no proporcionar mucho valor ahora ... lo recuperé.
Kawu
9

¡Mencionaría una cosa más que concierne a Primefaces p:commandButton!

Cuando usa un p:commandButtonpara la acción que debe hacerse en el servidor, no puede usarlo type="button"porque es para botones que se usan para ejecutar JavaScript personalizado sin causar una solicitud ajax / non-ajax al servidor.

Para este propósito, puede dispensar el typeatributo (el valor predeterminado es "submit") o puede usarlo explícitamente type="submit".

¡Espero que esto ayude a alguien!

akelec
fuente
este era mi problema principal en una de nuestras páginas, ninguno de los puntos en la respuesta aceptada nos acercó, ¿dónde encontraste esta información?
Uriel Arvizu
Bueno, he tenido ese problema muchas veces, e investigué y descubrí que p:commandButtontiene varios valores de typeatributo, y buttones uno que se refiere a todo sobre el lado del cliente. Es un poco difícil encontrar esto en el Primefacesdocumento, pero aquí hay un enlace: developer.am/primefaces/…
akelec
Su sugerencia de envío resolvió mi problema que he estado enfrentando durante días. ¡Muchas gracias por tu publicación!
gpuk360
Gracias, es un placer. Deliberadamente pongo esta respuesta porque muchos de nosotros tuvimos ese problema. También había perdido unos días hasta que me di cuenta de qué se trataba.
akelec
3

Me atasqué con este problema y encontré una causa más para este problema. Si no tiene métodos de establecimiento en su bean de respaldo para las propiedades utilizadas en su * .xhtml, entonces la acción simplemente no se invoca.

Dnavir
fuente
55
Debería haber resultado en una explicación bastante clara PropertyNotWritableException. Si no lo vio, tal vez activó una solicitud ajax sin un controlador de excepciones ajax adecuado, pero debería verlo en los registros del servidor.
BalusC
3
No mostró esa excepción hasta que hice p: commandButton's ajax = "false".
Dnavir
GRACIAS A DIOS que me salvaste la vida
exrezzo
3

Recientemente me encontré con un problema con un UICommand que no invoca en una aplicación JSF 1.2 que utiliza Componentes de caras extendidas de IBM.

Tenía un botón de comando en una fila de una tabla de datos (la versión extendida, por lo tanto <hx:datatable>) y el UICommand no se disparaba desde ciertas filas de la tabla (las filas que no se dispararían eran las filas mayores que el tamaño de visualización de fila predeterminado).

Tenía un componente desplegable para seleccionar el número de filas para mostrar. El valor que respalda este campo estaba en RequestScope. Los datos que respaldan la tabla en sí estaban en una especie de ViewScope(en realidad, temporalmente en SessionScope).

Si la visualización de la fila se incrementó a través del control cuyo valor también estaba vinculado al rowsatributo de la tabla de datos , ninguna de las filas mostradas como resultado de este cambio podría disparar el UICommand al hacer clic.

Al colocar este atributo en el mismo alcance que los datos de la tabla, se solucionó el problema.

Creo que se alude a esto en BalusC # 4 anterior, pero no solo el valor de la tabla tenía que tener un alcance de Vista o Sesión, sino también el atributo que controla el número de filas para mostrar en esa tabla.

Brent C
fuente
2

También tuve este problema y solo comencé a afinar la causa raíz después de abrir la consola web del navegador. Hasta ese momento, no pude recibir ningún mensaje de error (incluso con <p:messages>). La consola web mostró un código de estado HTTP 405 que regresaba de <h:commandButton type="submit" action="#{myBean.submit}">.

En mi caso, tengo una combinación de HttpServlet de vainilla que proporcionan autenticación OAuth a través de facetas y beans Auth0 y JSF que llevan a cabo las vistas de mi aplicación y la lógica empresarial.

Una vez que refactoré mi web.xml, y eliminé un servlet de intermediario, entonces "mágicamente" funcionó.

En pocas palabras, el problema era que el servlet de intermediario estaba usando RequestDispatcher.forward (...) para redirigir desde el entorno HttpServlet al entorno JSF, mientras que el servlet que se estaba llamando antes se redirigía con HttpServletResponse.sendRedirect (.. .).

Básicamente, el uso de sendRedirect () permitió que el "contenedor" JSF tomara el control, mientras que RequestDispatcher.forward () obviamente no lo era.

Lo que no sé es por qué la facelet pudo acceder a las propiedades del frijol pero no pudo establecerlas, y esto claramente grita por eliminar la mezcla de servlets y JSF, pero espero que esto ayude a alguien a evitar muchas horas de cabeza. a la mesa golpeando.

Arroyos
fuente
1

Me divertí mucho depurando un problema en <h:commandLink>el que la acción de un se richfaces datatablenegaba a disparar. La mesa solía funcionar en algún momento, pero se detuvo sin razón aparente. No dejé ninguna piedra sin mover, solo para descubrir que rich:datatableestaba usando el error rowKeyConverterque devolvió nulos que richfaces felizmente usaban como teclas de fila. Esto evitó que mi <h:commandLink>acción fuera llamada.

Mustafa
fuente
0

Una posibilidad más: si el síntoma es que la primera invocación funciona, pero las siguientes no, puede estar utilizando PrimeFaces 3.x con JSF 2.2, como se detalla aquí: no se envía ViewState .

Dave Mulligan
fuente
-1

Solucioné mi problema al colocar el:

<h:commandButton class="btn btn-danger" value = "Remove" action="#{deleteEmployeeBean.delete}"></h:commandButton>

En:

<h:form>
     <h:commandButton class="btn btn-danger" value = "Remove" action="#{deleteEmployeeBean.delete}"></h:commandButton>
</h:form>
Georgi Peev
fuente
Ese es el n. ° 1 en la>> 600 respuesta votada. No es necesario escribirlo como una respuesta separada.
Kukeltje
-1

Esta es la solución, que me funcionó.

<p:commandButton id="b1" value="Save" process="userGroupSetupForm"
                    actionListener="#{userGroupSetupController.saveData()}" 
                    update="growl userGroupList userGroupSetupForm" />

Aquí, el atributo process = "userGroupSetupForm" es obligatorio para la llamada Ajax. actionListener está llamando a un método desde @ViewScope Bean. También se actualiza el mensaje de gruñido, Datatable: userGroupList y Form: userGroupSetupForm.

Rajib Kumer Ghosh
fuente
-2
<ui:composition>  
  <h:form id="form1">
    <p:dialog id="dialog1">
      <p:commandButton value="Save" action="#{bean.method1}" /> <!--Working-->
    </p:dialog>
  </h:form>

  <h:form id="form2">
    <p:dialog id="dialog2">
      <p:commandButton value="Save" action="#{bean.method2}" /> <!--Not Working-->
    </p:dialog>
  </h:form>
</ui:composition>

Resolver;

<ui:composition>  
  <h:form id="form1">
    <p:dialog id="dialog1">
      <p:commandButton value="Save" action="#{bean.method1}" />   <!-- Working  -->
    </p:dialog>

    <p:dialog id="dialog2">
      <p:commandButton value="Save" action="#{bean.method2}" />   <!--Working  -->
    </p:dialog>
  </h:form>
  <h:form id="form2">
    <!-- ..........  -->
  </h:form>
</ui:composition>
Kenan Gökbak
fuente
Lo siento, pero esto es, en mi humilde opinión, totalmente falso. Usted efectivamente declara que 2 diálogos necesitan estar en su propia forma para funcionar. Usted con un 99% de certeza tenía un problema diferente que resolver y para el que ahora piensa que esta es la solución ...
Kukeltje
Esta es la página incluida. Quizás esto pueda causar un problema. Deberías probarlo antes de votar.
Kenan Gökbak
No, debería haber creado un ejemplo reproducible mínimo antes de publicar (y solo entonces puedo probar) ... Y sí, incluir puede dar lugar a problemas con diálogos y formularios, pero el problema todavía no es lo que parece querer resolver aquí . Su primer ejemplo está perfectamente bien y el segundo es con 100% de certeza, no una solución de un problema inexistente
Kukeltje
De todas formas. Mi aplicación funciona bien. Creo que no es importante el cuadro de diálogo en el formulario. Tengo que crear una segunda forma para resolver otro problema.
Kenan Gökbak
Su aplicación puede estar funcionando, pero eso no está claro / visible a partir de un problema original y su solución. Además, usted dice _ "Creo que no es importante el cuadro de diálogo en el formulario". _Pero en su respuesta parece importante dónde están. Una contradicción que respalda mi afirmación. Lo sentimos, pero su respuesta es claramente incorrecta ... (ya hay otro
voto negativo