Método commandButton / commandLink / ajax action / listener não chamado ou valor de entrada não definido / atualizado

345

Às vezes, quando se utiliza <h:commandLink>, <h:commandButton>ou <f:ajax>, a action, actionListenerou listenermétodo associado à tag simplesmente não estão sendo invocado. Ou, as propriedades do bean não são atualizadas com os UIInputvalores enviados .

Quais são as possíveis causas e soluções para isso?

Muhammad Hewedy
fonte

Respostas:

687

Introdução

Sempre que um UICommandcomponente ( <h:commandXxx>, <p:commandXxx>etc) falha ao chamar o método de ação associado ou um UIInputcomponente ( <h:inputXxx>, <p:inputXxxx>etc) falha ao processar os valores enviados e / ou atualizar os valores do modelo, e você não vê nenhuma exceção googlável e / ou avisos no log do servidor, também não quando você configura um manipulador de exceção ajax de acordo com o tratamento de exceção em solicitações JSF ajax , nem quando você define o parâmetro de contexto abaixo em web.xml,

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

e você também não vê nenhum erro e / ou aviso no Google no console JavaScript do navegador (pressione F12 no Chrome / Firefox23 + / IE9 + para abrir o conjunto de ferramentas para desenvolvedores da Web e, em seguida, abra a guia Console ) e, em seguida, trabalhe na lista abaixo de possíveis causas.

Causas Possíveis

  1. UICommande os UIInputcomponentes devem ser colocados dentro de um UIFormcomponente, por exemplo <h:form>(e, portanto, não HTML simples <form>), caso contrário, nada poderá ser enviado ao servidor. UICommandOs componentes também não devem ter type="button"atributo, caso contrário, será um botão morto, útil apenas para JavaScript onclick. Consulte também Como enviar valores de entrada de formulário e chamar um método no bean JSF e <h: commandButton> não inicia uma postagem .

  2. Você não pode aninhar vários UIFormcomponentes um no outro. Isso é ilegal em HTML. O comportamento do navegador não é especificado. Cuidado com os arquivos incluídos! Você pode usar UIFormcomponentes em paralelo, mas eles não se processam durante o envio. Você também deve tomar cuidado com o antipadrão "Forma de Deus"; certifique-se de não processar / validar acidentalmente todas as outras entradas (invisíveis) da mesma forma (por exemplo, ter um diálogo oculto com as entradas necessárias da mesma forma). Consulte também Como usar <h: form> na página JSF? Formulário único? Múltiplos formulários? Formulários aninhados? .

  3. Nenhum UIInputerro de validação / conversão de valor deveria ter ocorrido. Você pode usar <h:messages>para mostrar qualquer mensagem que não seja mostrada por nenhum <h:message>componente específico de entrada . Não se esqueça de incluir o idde <h:messages>no <f:ajax render>, se houver, para que ele seja atualizado também nos pedidos do ajax. Consulte também h: messages não exibe mensagens quando p: commandButton é pressionado .

  4. Se UICommandou UIInputcomponentes forem colocados dentro de um componente de iteração, como <h:dataTable>, <ui:repeat>etc, será necessário garantir que exatamente o mesmo valuecomponente de iteração seja preservado durante a fase de aplicar valores da solicitação de envio de formulário. O JSF reiterará sobre ele para encontrar o link / botão clicado e os valores de entrada enviados. Colocar o bean no escopo da visualização e / ou garantir que você carregue o modelo de dados no @PostConstructbean (e, portanto, não em um método getter!) Deve corrigi-lo. Consulte também Como e quando devo carregar o modelo do banco de dados para h: dataTable .

  5. Se UICommandou UIInputcomponentes forem incluídos por uma fonte dinâmica como <ui:include src="#{bean.include}">, então, você precisará garantir que exatamente o mesmo #{bean.include}valor seja preservado durante o tempo de construção da exibição da solicitação de envio do formulário. O JSF o reexecutará durante a construção da árvore de componentes. Colocar o bean no escopo da visualização e / ou garantir que você carregue o modelo de dados no @PostConstructbean (e, portanto, não em um método getter!) Deve corrigi-lo. Consulte também Como incluir o conteúdo dinâmico do ajax-refresh dynamic pelo menu de navegação? (SPA JSF) .

  6. O renderedatributo do componente e todos os seus pais e o testatributo de qualquer pai <c:if>/ mãe <c:when>não devem ser avaliados falsedurante a fase de aplicar valores de solicitação da solicitação de envio do formulário. O JSF o verificará novamente como parte da proteção contra solicitações adulteradas / invadidas. Armazenar as variáveis ​​responsáveis ​​pela condição em um @ViewScopedbean ou garantir que você esteja pré-inicializando corretamente a condição em @PostConstructum @RequestScopedbean deve corrigi-lo. O mesmo se aplica ao disabledatributo do componente, que não deve ser avaliado truedurante a fase de aplicar valores de solicitação. Consulte também Ação CommandButton do JSF não invocada , O envio do formulário no componente renderizado condicionalmente não é processado eh: commandButton não está funcionando depois que eu o envolvo em um <h: panelGroup renderizado> .

  7. O onclickatributo do UICommandcomponente e o onsubmitatributo do UIFormcomponente não devem retornar falseou causar um erro de JavaScript. No caso de, <h:commandLink>ou <f:ajax>também, não há erros de JS visíveis no console de JS do navegador. Normalmente, pesquisar a mensagem de erro exata no Google já dará a resposta. Consulte também Adicionando / carregando manualmente resultados do jQuery com PrimeFaces nos UnEaught TypeErrors .

  8. Se você estiver usando o Ajax via JSF 2.x <f:ajax>ou, por exemplo <p:commandXxx>, PrimeFaces , verifique se possui um <h:head>no modelo mestre em vez do <head>. Caso contrário, o JSF não poderá incluir automaticamente os arquivos JavaScript necessários que contêm as funções do Ajax. Isso resultaria em um erro de JavaScript como "mojarra não está definido" ou "PrimeFaces não está definido" no console JS do navegador. Consulte também o listener de ação h: commandLink não é chamado quando usado com f: ajax e ui: repeat .

  9. Se você estiver usando Ajax, e os valores apresentados acabam sendo null, em seguida, certifique-se de que os UIInpute UICommandcomponentes de interesse são cobertos pelo <f:ajax execute>ou por exemplo <p:commandXxx process>, caso contrário não será executado / processados. Consulte também Valores de formulário enviados não atualizados no modelo ao incluir <f: ajax> em <h: commandButton> e Noções básicas sobre processo / atualização do PrimeFaces e atributos de execução / renderização do JSF f: ajax .

  10. Se os valores enviados ainda acabarem sendo null, e você estiver usando o CDI para gerenciar beans, certifique-se de importar a anotação de escopo do pacote correto, caso contrário, o CDI usará como padrão o @Dependentqual recria efetivamente o bean em todas as avaliações do EL expressão. Consulte também o bean @SessionScoped perde o escopo e é recriado o tempo todo, os campos se tornam nulos e qual é o escopo do Bean gerenciado padrão em um aplicativo JSF 2?

  11. Se um pai do <h:form>com o UICommandbotão de antemão está sendo processado / atualizado por uma solicitação ajax vindo de outra forma na mesma página, em seguida, a primeira ação sempre falhará no JSF 2.2 ou mais velhos. A segunda e subsequente ação funcionará. Isso é causado por um bug na manipulação de estado de exibição, relatado como problema de especificação JSF 790 e atualmente corrigido no JSF 2.3. Para versões mais antigas do JSF, você precisa especificar explicitamente o ID do <h:form>na renderdo <f:ajax>. Consulte também h: commandButton / h: commandLink não funciona no primeiro clique, funciona apenas no segundo clique .

  12. Se o conjunto <h:form>tiver sido enctype="multipart/form-data"configurado para suportar o upload de arquivos, você deverá certificar-se de estar usando pelo menos o JSF 2.2 ou se o filtro de servlet responsável por analisar solicitações de várias partes / dados de formulário está configurado corretamente, caso contrário, FacesServletserá acabam não obtendo nenhum parâmetro de solicitação e, portanto, não podem aplicar os valores da solicitação. Como configurar esse filtro depende do componente de upload de arquivo que está sendo usado. Para Tomahawk <t:inputFileUpload>, verifique esta resposta e, para o PrimeFaces <p:fileUpload>, verifique esta resposta . Ou, se você realmente não estiver carregando um arquivo, remova o atributo completamente.

  13. Certifique-se de que o ActionEventargumento de actionListenerseja um javax.faces.event.ActionEvente, portanto java.awt.event.ActionEvent, não , o que a maioria dos IDEs sugere como a primeira opção de preenchimento automático. Não ter argumentos também está errado se você usar actionListener="#{bean.method}". Se você não quiser um argumento no seu método, use actionListener="#{bean.method()}". Ou talvez você realmente queira usar em actionvez de actionListener. Consulte também Diferenças entre action e actionListener .

  14. Certifique-se de que nenhum PhaseListenerou nenhum EventListenerda cadeia de solicitação-resposta tenha alterado o ciclo de vida do JSF para ignorar a fase de ação de chamada, por exemplo, chamando FacesContext#renderResponse()or FacesContext#responseComplete().

  15. Verifique se nenhuma Filterou Servletna mesma cadeia de solicitação-resposta bloqueou a solicitação de FacesServletalguma forma. Por exemplo, filtros de login / segurança, como Spring Security. Particularmente em solicitações ajax que, por padrão, acabariam sem feedback da interface do usuário. Consulte também manipulação de solicitações Spring Security 4 e PrimeFaces 5 AJAX .

  16. Se você estiver usando um PrimeFaces <p:dialog>ou a <p:overlayPanel>, verifique se eles têm os seus próprios <h:form>. Porque, por padrão, esses componentes são realocados para o JavaScript no final do HTML <body>. Então, se eles estavam originalmente sentados dentro de a <form>, então agora não estavam mais sentados em a <form>. Consulte também p: commandbutton action não funciona dentro de p: dialog

  17. Bug na estrutura. Por exemplo, o RichFaces possui um " erro de conversão " ao usar umrich:calendar elemento da interface do usuário com um defaultLabelatributo (ou, em alguns casos, um rich:placeholdersubelemento). Esse bug impede que o método do bean seja chamado quando nenhum valor for definido para a data do calendário. O rastreamento de erros da estrutura pode ser realizado começando com um exemplo de trabalho simples e criando a página de backup até que o bug seja descoberto.

Dicas de depuração

No caso de você ainda stuck, é hora de depurar. No lado do cliente, pressione F12 no navegador da web para abrir o conjunto de ferramentas do desenvolvedor da web. Clique na guia Console para ver o cone JavaScript. Deve estar livre de erros de JavaScript. A captura de tela abaixo é um exemplo do Chrome que demonstra o caso de enviar um <f:ajax>botão ativado sem ter <h:head>declarado (conforme descrito no ponto 7 acima).

console js

Clique na guia Rede para ver o monitor de tráfego HTTP. Envie o formulário e investigue se os cabeçalhos da solicitação e os dados do formulário e o corpo da resposta estão de acordo com as expectativas. A captura de tela abaixo é um exemplo do Chrome que demonstra um envio bem-sucedido do ajax de um formulário simples com um único <h:inputText>e outro <h:commandButton>com <f:ajax execute="@form" render="@form">.

monitor de rede

(aviso: quando você publica capturas de tela de cabeçalhos de solicitação HTTP como acima em um ambiente de produção, embaralhe / ofusque qualquer cookie de sessão na captura de tela para evitar ataques de seqüestro de sessão!)

No lado do servidor, verifique se o servidor foi iniciado no modo de depuração. Coloque um ponto de interrupção de depuração em um método do componente JSF de interesse que você espera que seja chamado durante o processamento do envio do formulário. Por exemplo, no caso de UICommandcomponente, isso seria UICommand#queueEvent()e no caso de UIInputcomponente, isso seria UIInput#validate(). Basta percorrer a execução do código e inspecionar se o fluxo e as variáveis ​​são conforme as expectativas. Abaixo da captura de tela, há um exemplo do depurador do Eclipse.

servidor de depuração

BalusC
fonte
11
seu segundo ponto me fez pensar - por um longo tempo. Acabei de descobrir que uma tag f: view no meu arquivo principal foi a causa da maioria dos meus problemas. E provavelmente porque renderiza um formulário, certo?
Paulo Guedes
2
@pauloguedes Não consigo encontrar nada que indique que f: view processa um formulário. Meu entendimento é que é apenas um contêiner. Na minha experiência, f: view não processa nenhum elemento.
Lucas
@balusc Um pequeno esclarecimento sobre o ponto 4, se o commandLink não estiver no dataTable em si, isso ainda importa?
Lucas
obrigado, o ponto é o ponto: colocar o bean no escopo da visualização e / ou garantir que você carregue o modelo de dados no (post) construtor do bean (e, portanto, não no método getter!) deve corrigi-lo.
Merveotesi
2
@Kukeltje: que teria jogado uma exceção EL (já abrangidos pela parágrafo 1º na resposta)
BalusC
54

Se você h:commandLinkestiver dentro de um, h:dataTablehá outra razão pela qual o h:commandLinkpode não funcionar:

A fonte de dados subjacente que está vinculada à h:dataTabletambém deve estar disponível no segundo ciclo de vida JSF que é acionado quando o link é clicado.

Portanto, se a fonte de dados subjacente tiver um escopo de solicitação, h:commandLinkisso não funcionará!

jbandi
fonte
2
Ok, isso não estava totalmente claro para mim. Espero que minha resposta seja útil de qualquer maneira, já que, no meu caso, pelo menos não estava lidando explicitamente com UICommand / UIData. A "solução" foi a promoção de um bean de apoio de pedido escopo de escopo de sessão ...
jbandi
11
Eu segundo comentário de Jens ... definir meu bean RequestScoped como SessionScoped fez a diferença nos meus dataTable - obrigado
Zack Macomber
28

Embora minha resposta não seja 100% aplicável, mas a maioria dos mecanismos de pesquisa o encontra como o primeiro hit, decidi publicá-lo.

Se você estiver usando o PrimeFaces (ou alguma API semelhante) p:commandButtonou p:commandLink, é provável que você tenha esquecido de adicionar explicitamente process="@this"aos componentes de comando.

Como o Guia do usuário do PrimeFaces afirma na seção 3.18, os padrões para processe updatesão ambos @form, o que praticamente se opõe aos padrões que você pode esperar do JSF f:ajaxou RichFaces simples , que são execute="@this"e render="@none"respectivamente.

Levei muito tempo para descobrir. (... e acho que é pouco inteligente usar padrões diferentes do JSF!)

Kawu
fonte
6
O padrão para o PrimeFaces processé @form. Portanto, se a ação não é invocada dessa maneira, mas ocorre ao usar @this, o ponto 3 da minha resposta provavelmente se aplica.
precisa saber é o seguinte
3
Isto não pode ser. Eu tinha um p:commandButtonque não invocou o método actionListener até eu adicionar process="@this". Além disso, o Guia do usuário do PrimeFaces lista explicitamente os padrões mencionados na seção 3.18 e 3.19. Está aqui: primefaces.googlecode.com/files/primefaces_users_guide_3_4.pdf ... talvez os padrões tenham sido alterados?
Kawu
8
É provável que haja um erro na documentação. Remova process="@this"e adicione <p:messages autoUpdate="true">(ou apenas leia o log do servidor para mensagens na fila, mas não exibidas) e você verá que realmente ocorreu um erro de conversão / validação.
BalusC
Por que você removeu esta questão stackoverflow.com/questions/60673695/…
Kukeltje 14/03
Eu pensei que não poderia fornecer muito valor agora ... eu o cancelei.
Kawu 15/03
9

Eu mencionaria mais uma coisa que diz respeito ao Primefaces p:commandButton!

Quando você usa a p:commandButtonpara a ação que precisa ser executada no servidor, não é possível usá-lo, type="button"porque isso é para botões de pressão que são usados ​​para executar javascript personalizado sem causar uma solicitação ajax / não ajax ao servidor.

Para esse propósito, você pode dispensar o typeatributo (o valor padrão é "submit") ou pode usar explicitamente type="submit".

Espero que isso ajude alguém!

akelec
fonte
esse foi o meu principal problema em uma de nossas páginas, nenhum dos pontos da resposta aceita nos aproximou. Onde você encontrou essas informações?
Uriel Arvizu
Bem, eu já tive esse problema muitas vezes, pesquisei e descobri que p:commandButtontem vários valores de typeatributo e buttoné um que diz respeito a tudo sobre o lado do cliente. É um pouco difícil encontrar isso em Primefacesdoc, mas aqui é um link: developer.am/primefaces/...
akelec
Sua dica de envio resolveu meu problema que eu enfrento há dias. Muito obrigado pelo seu post!
Gpuk360 4/17
Obrigado, é um prazer. Eu deliberadamente coloquei essa resposta porque muitos de nós tivemos esse problema. Eu também tinha perdido alguns dias até perceber o que é isso.
akelec 4/17
3

Eu mesmo fiquei com esse problema e encontrei mais uma causa para esse problema. Se você não possui métodos setter no seu bean de backup para as propriedades usadas no seu * .xhtml, a ação simplesmente não é invocada.

Dnavir
fonte
5
Deveria ter resultado em uma auto-explicação PropertyNotWritableException. Se você não o viu, talvez tenha disparado uma solicitação ajax sem um manipulador de exceção ajax adequado, mas você deve vê-la nos logs do servidor.
BalusC
3
Não mostrou essa exceção até que eu fiz p: commandButton's ajax = "false".
Dnavir
Graças a Deus que salvou minha vida
exrezzo
3

Recentemente, encontrei um problema com um UICommand que não chamava em um aplicativo JSF 1.2 usando o IBM Extended Faces Components.

Eu tinha um botão de comando em uma linha de uma tabela de dados (a versão estendida, então <hx:datatable> ) e o UICommand não seria acionado a partir de determinadas linhas da tabela (as linhas que não seriam acionadas eram as linhas maiores que o tamanho de exibição da linha padrão).

Eu tinha um componente suspenso para selecionar o número de linhas a serem exibidas. O valor do respetivo campo estava em RequestScope. Os dados que apóiam a própria tabela estavam em uma espécie de ViewScope(na realidade, temporariamente em SessionScope).

Se a exibição da linha for aumentada por meio do controle, cujo valor também foi vinculado ao rowsatributo da tabela de dados , nenhuma das linhas exibidas como resultado dessa alteração poderá disparar o UICommand quando clicada.

A colocação desse atributo no mesmo escopo que os próprios dados da tabela corrigiram o problema.

Eu acho que isso é mencionado no BalusC # 4 acima, mas não apenas o valor da tabela precisava ter o escopo de View ou Session, mas também o atributo que controla o número de linhas a serem exibidas nessa tabela.

Brent C
fonte
2

Eu também tive esse problema e só comecei a me interessar pela causa raiz depois de abrir o console da web do navegador. Até isso, eu não conseguia receber nenhuma mensagem de erro (mesmo com <p:messages>). O console da web mostrou um código de status HTTP 405 voltando do <h:commandButton type="submit" action="#{myBean.submit}">.

No meu caso, tenho uma mistura de HttpServlet de baunilha, fornecendo autenticação OAuth por facelets e beans Auth0 e JSF, realizando minhas visualizações de aplicativos e lógica de negócios.

Depois de refatorar meu web.xml e remover um servlet intermediário, ele funcionou "magicamente".

Resumindo, o problema era que o middle-man-servlet estava usando RequestDispatcher.forward (...) para redirecionar do ambiente HttpServlet para o ambiente JSF, enquanto o servlet chamado anteriormente estava redirecionando com HttpServletResponse.sendRedirect (.. .).

Basicamente, o uso de sendRedirect () permitiu que o "contêiner" JSF assumisse o controle, enquanto o RequestDispatcher.forward () obviamente não era.

O que não sei é por que o facelet foi capaz de acessar as propriedades do bean, mas não pôde defini-las, e isso claramente grita por acabar com a mistura de servlets e JSF, mas espero que isso ajude alguém a evitar muitas horas de head- batendo na mesa.

Brooks
fonte
1

Diverti-me bastante ao depurar um problema em que a <h:commandLink>ação de uma pessoa richfaces datatablese recusava a disparar. A tabela costumava funcionar em algum momento, mas parou sem motivo aparente. Não deixei pedra sobre pedra, apenas para descobrir que rich:datatableestava usando o errado, rowKeyConverterque retornava nulos que richfaces felizmente usavam como chaves de linha. Isso impediu que minha <h:commandLink>ação fosse chamada.

Mustafa
fonte
0

Mais uma possibilidade: se o sintoma é que a primeira chamada funciona, mas as seguintes não, você pode estar usando o PrimeFaces 3.x com o JSF 2.2, conforme detalhado aqui: Nenhum ViewState é enviado .

Dave Mulligan
fonte
-1

Corrigi o meu problema ao colocar o:

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

No:

<h:form>
     <h:commandButton class="btn btn-danger" value = "Remove" action="#{deleteEmployeeBean.delete}"></h:commandButton>
</h:form>
Georgi Peev
fonte
Esse é o número 1 na resposta> 600 votada acima. Não há necessidade de escrevê-lo como uma resposta separada.
Kukeltje 8/02/19
-1

Esta é a solução, que é trabalhada para mim.

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

Aqui, o atributo process = "userGroupSetupForm" é obrigatório para a chamada do Ajax. actionListener está chamando um método do @ViewScope Bean. Também atualizando a mensagem de growl, Datatable: userGroupList e Form: userGroupSetupForm.

Rajib Kumer Ghosh
fonte
-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
fonte
Desculpe, mas isso é, na minha humilde opinião, totalmente falso. Você declara efetivamente que 2 caixas de diálogo precisam estar em sua própria forma para funcionar. -Lo com 99% de certeza tinha um problema diferente que você resolvido e para o qual você agora que esta é a solução ...
Kukeltje
Esta é a página incluída. Talvez isso possa causar problemas. Você deve testá-lo antes da votação.
Kenan Gökbak
Não, você deveria ter criado um exemplo reproduzível mínimo antes de postar (e só então eu posso testar) ... E sim inclui pode resultar em problemas com diálogos e formulários, mas o problema ainda não é o que você deseja resolver aqui . Você primeiro exemplo é perfeitamente bem e o segundo está com 100% de certeza não é uma solução de um problema inexistente
Kukeltje
De qualquer forma. Minha aplicação está funcionando bem. Eu acho que não é importante onde caixas de diálogo no formulário. Eu tenho que criar uma segunda forma para resolver outro problema.
Kenan Gökbak 12/07/19
Seu aplicativo pode estar funcionando, mas isso não é claro / visível de um problema original e da sua 'solução. Além disso, você diz _ "Eu acho que não é importante onde as caixas de diálogo estão no formulário". _Mas na sua resposta parece ser importante onde elas estão. Uma contradição que sustenta minha afirmação. Desculpe, mas sua resposta é a planície errado ... (não há outro downvote nele já)
Kukeltje