Validação condicional com JSF 2

Quem já utilizou JSF sabe que apesar de ser uma excelente ideia, muito produtivo para determinadas coisas, acabamos esbarrando em alguns erros que parecem ridiculamente simples. Esses erros em sua maioria são causados pela falta de conhecimento do funcionamento do Framework, um conhecimento muito valioso, e que pode transformar sua opinião sobre JSF.

 - O problema

Um dos problemas recorrentes é quando se utiliza um paradigma RIA na interface, trabalhando intensamente com Ajax, considerando que isso fica trivial de ser feito com suítes de componentes como o Primefaces. Porém após fazer em 15 minutos aquela tela que você demoraria um dia só mexendo com a camada de View  você esbarra naquele ponto onde determinado campo só é válido se o outro também for, e agora, a solução mais lógica é uma EL condicional no atributo disabled, ex:


<p:growl autoUpdate="true" />

<h:form id="frmPrincipal">

        <p:inputText id="codigo"
                     value="#{mb.codigo}" />

        <p:inputText id="digitoVerificador"
                     value="#{mb.digitoVerificador}">
                     <f:validateBean disabled="#{empty param['frmPrincipal:codigo']}"/>
        </p:inputText>

        <p:commandButton action="#{mb.processeValores}" /> 
</h:form> 

Obs:  para quem não está habituado com #{param} ele é um Map dos valores enviados no request HTTP, onde normalmente em um submit constam o nome do componente como chave e seu respectivo valor submetido

Como o Jsf nos abstrai fatores não relevantes a regra da nossa aplicação, o processo de validação é determinado por um parâmetro  sendo que o nosso código no ManagedBean não precisa ficar validando e convertendo valores.

Portanto conforme o exemplo acima no parâmetro disabled do segundo input existe uma expressão condicional que determina que ele não é validado caso o valor do campo anterior esteja vazio.

Perfeito, porém ao executar o clique no botão notamos que mesmo com nenhum valor setado no campo frmPrincipal:codigo o nosso campo é validado, existe alguma coisa errada ai…

Esse problema ocorre porque a avaliação da expressão de EL é feita depois da validação ( neste caso o valor do campo disabled é o valor da expressão referente a ultima vez que o componente for renderizado que provavelmente foi quando a View foi aberta). Portanto quando a fase de validação (fase 3) ocorre os valores não foram reanalisados baseados no novos parâmetros, logo para o JSF o validador está ativo.

 - A solução 

Uma solução possível seria você implementar um validador próprio e definir condicionalmente a validação a partir do parâmetro do request, porém dessa forma além de reinventar a roda, afinal o validador da BeanValidation já existe, você vai estar criando uma classe de validação altamente acoplada ao nome do seu componente de View, logo nada reutilizável.

Existe uma outra hipótese, mais simples, mais lógica e mais legível. O pessoal do Omnifaces notou que esse é um erro muito recorrente, e apesar de ser um problema conceitual com relação ao Framework, incomodava muita gente. Então criaram um validator próprio, que visa simplificar isso, efetuando a analise do atributo disabled antes da fase de validação, de forma que assim possuímos um validador realmente condicional. Então nosso formulário ficaria assim:


<p:growl autoUpdate="true" />

<h:form id="frmPrincipal">

        <p:inputText id="codigo"
                     value="#{mb.codigo}" />

        <p:inputText id="digitoVerificador"
                     value="#{mb.digitoVerificador}">
             <o:validator validatorId="javax.faces.Bean" 
                          disabled="#{not empty param['frmPrincipal:codigo']}"/>

        </p:inputText> 

        <p:commandButton action="#{mb.processeValores}" /> 
</h:form> 

Dessa forma nossa condição será avaliada antes do processo de validação. Esse foi um exemplo bem simples, mas isso abre um leque pra inúmeras outra possibilidades, utilizando-se da produtividade que o JSF + Primefaces prove sem muitas dores de cabeça.

 - Conclusão

Apesar de neste caso possuirmos uma bela solução pré implementada, podem surgir outros problemas que muitas vezes por falta de entender o Framework  damos enormes voltas além de abusarmos do POG. Isso não é bom nem para nós nem para o futuro do projeto, por isto sempre gosto de bater em uma tecla muito importante quando se trata de usar frameworks:
“Não se limite a usar só o simples, entenda o Framework e o utilize por completo e acima de tudo, não critique o que não conhece”

Obs: para muito problemas vale dar uma olhada no showcase do Omnifaces, que é uma lib que se propõe a resolver problemas recorrentes do desenvolvimento com JSF além de facilitar a vida do desenvolvedor. Lembrando, é claro, que ela é compatível com qualquer suíte de componentes a nível de View (Primefaces, Richfaces, etc…)

 

Obrigado e espero criticas a sugestôes, afinal este é meu primeiro artigo.

 

_____________

[EDIT]

Obrigado ao colega Rafael Pontes pela correção já devidamente efetuada.

6 thoughts on “Validação condicional com JSF 2

  1. Olá Clécius,

    Quando você diz
    “Esse problema ocorre porque a avaliação da expressão de EL é feita depois da validação ( neste caso o valor do campo required é o valor da expressão referente a ultima vez que o componente for renderizado que provavelmente foi quando a View foi aberta)”

    Não é uma solução que utilizei muito na vida, mas até onde sei o atributo required é avaliado durante a fase de validação e nesse momento a EL deveria ser avaliada normalmente, pois o parâmetro já está contido no request e pode ser obtido durante o ciclo de vida.

    Você tem certeza que a primeira solução não funciona? Ou ela não funciona em algum caso específico?

    Enfim, parabéns pelo post, simples e objetivo.

    • Realmente, acabei por me equivocar ao tentar simplificar o exemplo, vou corrigir. Esse problema ocorre ao utilizar o atributo disabled do <f:validator… e outros do tipo.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>