Validação cliente utilizando o plugin Validation do JQuery
Autor: Vinícius Pitta Lima de Araújo | Publicado: 2008-04-05T17:54:00-03:00

Atualmente eu estou desenvolvendo uma aplicação WEB em JAVA utilizando o framework struts 2 e a biblioteca javascript YUI para a interface com o usuário. Apesar do trabalho inicial para deixar tudo redondinho (curva de apredizagem), os dois estão dando ótimos resultados. O struts 2, que não é baseado no struts 1, está mais simples e fácil de configurar além de ter ganhado mais flexibilidade e estar melhor estruturado. O ponto fraco é que a documentação deixa muito a desejar, possui poucos detalhes e os exemplos são muito simplistas. Isso me rendeu muitas dores de cabeça e bastante trabalho de pesquisa pra conseguir botar algumas coisinhas simples para funcionar. O YUI é uma ótima biblioteca javascript para montar interfaces com o usuário ricas. Funciona razoavelmente bem com a maioria dos navegadores e é simples de usar. Simplicidade pra mim é essêncial e o YUI tem uma grande vantagem: é possível criar os componentes (menus, dialogos, botões, etc) através do markup além da opção de fazer tudo via javascript. Dessa forma seu código fica mais légivel e semântico na hora do desenvolvimento e você tem um controle maior do HTML. O ponto fraco é que quando alguma coisa não funciona você tem que funçar com atenção para encontrar o erro e existem alguns poucos bugzinhos na versão 2.4.1 que atrapalham mas são contornáveis.

Combinando tudo isso eu consegui uma boa solução para minha interface com o usuário porém restaram algumas brechas. Apesar de o struts ter, desde a primeira versão, uma boa solução de validação que gera, inclusive, validação do lado cliente, eu não estava completamente satisfeito. Se você tem telas simples que funcionam com apenas uma action, o struts 2 te atende perfeitamente neste quesito. Porém quando as coisas começam a ficar mais complexas e sofisticadas, o custo de personalizar a validação cliente para atender às suas necessidades cresce. No struts 2 a validação cliente ficou nos temas. Se você quiser alterar o javascript de validação cliente terá que editar o arquivo form-close-validate.ftl do tema XHTML. Eu considerei muito trabalhoso edita-lo para atender meus requisitos de validação cliente. Eu precisava de uma solução mais prática e simples. Uma rápida busca no google e eu encontrei uma solução além das minhas expectativas:
o plugin Validation do JQuery.

O JQuery é, basicamente, uma biblioteca javascript que facilita a manipulação do DOM via javascript. Ele permite a navegação (atravessamento) de forma simplificada através de uma linguagem simples de seleção. O JQuery dota seus objetos DOM de funcionalidades que facilitam seu acesso e manipulação e permite, através de plugins, a adição de fucionalidades de forma não intrusiva. O Validation é um plugin para JQuery para validação de formulários HTML.

Utilizando o Validation
A utilização do Validation consiste basicamente na definição das regras de validação do seu formulário. Você pode também personalizar as mensagens de erro, como elas são apresentadas e controlar a aparência dos campos com erro. Tudo no Validation pode ser personalizado, sua documentação é bem completa e a página do plugin possui uma coleção completa de demos com diversas situações comuns. O Validation faz validação por campos, porém você pode implementar suas próprias regras de validação criando validações mais complexas baseadas no estado do formulário. Existem 3 formas de definir as regras de validação de um campo:

Javascript: Você define todas as regras de validação do formulário através do método validate e pode também personalizar outros comportamentos da validação;
Class CSS: Associe ao campo classes CSS correspondentes aos métodos de validação (Ex.: required, number, date, etc);
Atributos HTML: Se o validation encontrar no seu campo o atributo maxlength, por exemplo, ele irá transforma-lo automáticamente numa regra de validação.


Eu não vou me prender aos detalhes da utilização do Validation. Os exemplos da página do plugin são bastante instrutivos e você não terá dificuldade para acompanha-los. Irei abordar alguns pontos que podem ser armadilhas na sua utilização. Se você está usando o framwork struts 2, provavelmente está colocando seus beans, que representam objetos de dominio, nas actions e utilizando a notação OGNL para acessa-los. Nos exemplos do Validation o atributo id dos campos é sempre igual ao atributo name. No seus forms, provavelmente, isso não é verdade. Por isso fique atento para usar o name dos campos na definição das regras de validação caso você utilize a definição em javascript. Veja o exemplo abaixo:


&lt;%@ taglib prefix="s" uri="/struts-tags" %&gt;

&lt;html&gt;

 &lt;head&gt;

 &lt;title&gt;Exemplo validação com Validation&lt;/title&gt;
 &lt;script type="text/javascript" src="js/jquery-1.2.1.min.js"&gt;&lt;/script&gt;
 &lt;script type="text/javascript" src="js/jquery.validate.js" &gt;&lt;/script&gt;
 &lt;script type="text/javascript"&gt;
  $().ready(function() {
  $("#pessoaForm").validate({
  rules : {
  "pessoa.nome" : "required",
  "pessoa.paisOrigem" : "required"
  },
  messages : {
  "pessoa.nome" : "O nome é obrigatório para o cadastro.",
  "pessoa.nome" : "O país de origem é obrigatório para o cadastro."
  }
  });
  });
 &lt;/script&gt;
 &lt;/head&gt;
 &lt;body&gt;
  &lt;s:form id="pessoaForm"&gt;
   &lt;s:textfield id="nome" name="pessoa.nome" label="Nome" required="true" /&gt;
   &lt;s:select id="pais"  name="pessoa.paisOrigem" label="País de Origem"  required="true" list="paises" /&gt;
   &lt;s:submit /&gt;
  &lt;/s:form&gt;
 &lt;/body&gt;
&lt;/html&gt;



Você pode também personalizar as mensagens de erro utilizando markup. Para isso você deverá personalizar as propriedades errorContainer,errorLabelContainer
e wrapper. Você pode ainda alterar a forma como as mensagens de erro são inseridas e a classe de erro que é adicionada aos campos com erro. Se você utilizar o elemento padrão para representar a mensagem de erro, o label, a relação entre a mensagem de erro e o campo será feita através do atributo for. O atributo for deve conter um id válido, por isso, neste caso, ao invés do valor do atributo name do campo, você utilizará o atributo id. Na verdade o Validation identificará a mensagem se você utilizar o valor do atributo name, porém esse seria um uso semanticamente incorreto do tag. Veja o exemplo abaixo:


&lt;%@ taglib prefix="s" uri="/struts-tags" %&gt;
&lt;html&gt;
 &lt;head&gt;
 &lt;title&gt;Exemplo validação com Validation&lt;/title&gt;
 &lt;script type="text/javascript" src="js/jquery-1.2.1.min.js"&gt;&lt;/script&gt;
 &lt;script type="text/javascript" src="js/jquery.validate.js" &gt;&lt;/script&gt;
 &lt;script type="text/javascript"&gt;
  $().ready(function() {
   $("#pessoaForm").validate({
    rules : {
    "pessoa.nome" : "required",
    "pessoa.paisOrigem" : "required"
    },
    errorContainer : $("#errosDeValidacao"),
    errorLabelContainer : $("#errosDeValidacao > ul"),
    wrapper: "li"
    });
  });
 &lt;/script&gt;
 &lt;/head&gt;
 &lt;body&gt;
  &lt;div id="errosDeValidacao"&gt;
   &lt;p&gt;Não foi possísvel continuar devido ao(s) seguinte(s) erro(s) de validação &lt;/p&gt;
   &lt;ul&gt;
    &lt;li&gt;&lt;label for="nome" class="error"&gt;O nome é obrigatório para o cadastro.&lt;/label&gt;&lt;/li&gt;
    &lt;li&gt;&lt;label for="pais" class="error"&gt;O país de origem é obrigatório para o cadastro.&lt;/label&gt;&lt;/li&gt;
   &lt;/ul&gt;
  &lt;/div&gt;
  &lt;s:form id="pessoaForm"&gt;
   &lt;s:textfield id="nome" name="pessoa.nome" label="Nome" required="true" /&gt;
   &lt;s:select id="pais"  name="pessoa.paisOrigem" label="País de Origem"  required="true" list="paises" /&gt;
   &lt;s:submit /&gt;
  &lt;/s:form&gt;
 &lt;/body&gt;
&lt;/html&gt;


Exibindo a mensagem de erro com o YUI
Como estou utilizando o YUI para criar uma interface com usuário rica nada mais natural que exibir as mensagens de erro de validação como um dialogo do YUI. Para que isso seja possível é preciso estar atento apenas a um detalhe: o Validation exibe/esconde os erros de validação alternando a propriedade CSS display do errorContainer entre os valores block e none respectivamente. Isso não funcionará com nosso dialogo. Ao invés disso precisamos invocar os métodos show e hide do dialogo. Isso será feito personalizando o método showErrors do Validation. Observe os comentários no código.

&lt;%@ taglib prefix="s" uri="/struts-tags" %&gt;
&lt;html&gt;
 &lt;head&gt;
  &lt;title&gt;Exemplo validação com Validation&lt;/title&gt;
  &lt;script type="text/javascript" src="js/jquery-1.2.1.min.js"&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src="js/jquery.validate.js" &gt;&lt;/script&gt;
  &lt;link rel="stylesheet" type="text/css" href="yui/build/fonts/fonts-min.css" /&gt;
  &lt;link rel="stylesheet" type="text/css" href="yui/build/button/assets/skins/sam/button.css" /&gt;
  &lt;link rel="stylesheet" type="text/css" href="yui/build/container/assets/skins/sam/container.css" /&gt;
  &lt;script type="text/javascript" src="yui/build/utilities/utilities.js"&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src="yui/build/button/button.js"&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src="yui/build/container/container.js"&gt;&lt;/script
  &lt;script type="text/javascript"&gt;
   YAHOO.util.Event.onDOMReady(function() {
    //registra o namespace
    YAHOO.namespace("net.viniciusaraujo.dialogos");
    //cria a instância do dialogo com 600px de largura, fixado no centro da tela com o icone de aviso.
    YAHOO.net.viniciusaraujo.dialogos.dlErros = new YAHOO.widget.SimpleDialog("errosDeValidacao",
     {  width: "600px",
      fixedcenter: true,
      visible: false,
      draggable: true,
      close: true,
      icon: YAHOO.widget.SimpleDialog.ICON_WARN,
      constraintoviewport: true,
      //cria um botão com o rótulo OK cuja ação é esconder o dialogo
      buttons: [    
        { text:"OK", handler: function() {this.hide();}, isDefault:true }
       ]
     });
    YAHOO.net.viniciusaraujo.dialogos.dlErros.render();
    //sempre que o dialogo for fechado todos os itens de erro serão escondidos
    YAHOO.net.viniciusaraujo.dialogos.dlErros.hideEvent.subscribe(function() {
     esconderErros();
    });
   });

   //essa função esconde os intes de erro da lista.
   function esconderErros() {
    //esconde todos os itens da lista de erro alternando a propriedade CSS display para 'none'.
    //isso é feito para evitar que erros que foram corrigidos apareçam novamente no dialogo de erro
    var itensListaErros = $("#errosDeValidacao &gt; div.bd &gt; ul &gt; li");
    for (var i = 0; i &lt; itensListaErros.length; i++) {
     $(itensListaErros[i]).css("display", "none");
    }
   }

   $().ready(function() {
    $("#pessoaForm").validate({
     rules : {
     "pessoa.nome" : "required",
     "pessoa.paisOrigem" : "required"
     },
     errorContainer : $("#errosDeValidacao"),
     errorLabelContainer : $("#errosDeValidacao &gt; ul"),
     wrapper: "li",
     showErrors: function(errorMap, errorList) {
      //a mensagem de erro agora é personalizada de acordo com o número de erros.
      var erros = this.numberOfInvalids();
      if (erros) {
        var mensagem = erros == 1 ?
         "Foi encontrado um erro no formulário" :
         "Foram encontrados " + erros + " erros no formulário";
        $("#errosDeValidacao &gt; div.bd p").html(mensagem);
        //esconde os erros anterios.
        esconderErros();
        //executa o procedimento padrão do Validation para exibir os erros de validação
        this.defaultShowErrors();
        //exibe o dialogo de erro 
        YAHOO.net.viniciusaraujo.dialogos.dlErros.show();
      }
     }
    });
   });
  &lt;/script&gt;
 &lt;/head&gt;
 &lt;body&gt;
  &lt;div id="errosDeValidacao"&gt;
   &lt;div class="hd"&gt;Erro&lt;/div&gt;
   &lt;div class="bd"&gt;
    &lt;p&gt;Não foi possísvel continuar devido ao(s) seguinte(s) erro(s) de validação &lt;/p&gt;
    &lt;ul&gt;
     &lt;li&gt;&lt;label for="nome" class="error"&gt;O nome é obrigatório para o cadastro.&lt;/label&gt;&lt;/li&gt;
     &lt;li&gt;&lt;label for="pais" class="error"&gt;O país de origem é obrigatório para o cadastro.&lt;/label&gt;&lt;/li&gt;
    &lt;/ul&gt;
   &lt;/div&gt;
  &lt;/div&gt;
  &lt;s:form id="pessoaForm"&gt;
   &lt;s:textfield id="nome" name="pessoa.nome" label="Nome" required="true" /&gt;
   &lt;s:select id="pais"  name="pessoa.paisOrigem" label="País de Origem"  required="true" list="paises" /&gt;
   &lt;s:submit /&gt;
  &lt;/s:form&gt;
 &lt;/body&gt;
&lt;/html&gt;


Referências

struts 2
JQuery
Validation
Yahoo User Interface