Limpando formulários e componentes no JSF 2.2
Conheça as novas funcionalidades do JSF 2.2 para limpar a árvore de componentes
JSF é um framework Web MVC com natureza stateful na qual mantém todo o estado no lado servidor. Este estado é mantido em cada componente visual de um formulário. O componente h:inputText
, por exemplo, mantém o valor entrado pelo usuário, assim como detalhes se o valor foi convertido e validado corretamente durante o ciclo de vida. Os demais componentes visuais seguem o mesmo modelo e podem armazenar diferentes tipos de informações. E todos estes componentes de uma página são armazenados em um estrutura em árvore chamada de árvore de componentes.
Quando submetemos um formulário com todos os campos válidos o próprio JSF se encarrega de limpar o estado de cada componente para que este mesmo formulário possa ser renderizado com o estado mais recente da aplicação, isto é, o estado dos atributos dos managed beans. No entanto, ao submetermos um formulário com 1 ou mais campos inválidos, alguns componentes acabam em um estado inconsistente, um estado sujo, pois o ciclo de vida parou na metade do caminho para estes componentes. Este estado não reflete os valores dos managed beans e, consequentemente, informações desatualizadas são exibidas para o usuário do sistema.
Um formulário com componentes sujos ocorre com muita frequência quando trabalhamos com uma única página física (XHTML) e navegamos via AJAX escondendo e exibindo componentes visuais, pois dessa forma nós estamos reutilizando a mesma árvore de componentes a todo instante. Reutilizar uma árvore é como reutilizar um objeto em sessão, se não limparmos o objeto adequadamente ele pode acabar em um estado inválido nas próximas requisições!
Limpar os dados do managed bean resolve somente parte do problema. É preciso ir mais longe, precisamos também limpar o estado de cada componente sujo. Até o JSF 2.1, para limpar um formulário tínhamos que fazê-lo programaticamente, como abaixo:
public void limpa(UIComponent component) {
if (component instanceof EditableValueHolder) {
EditableValueHolder evh = (EditableValueHolder) component;
evh.setSubmittedValue(null);
evh.setValue(null);
evh.setLocalValueSet(false);
evh.setValid(true);
}
if(component.getChildCount()>0){
for (UIComponent child : component.getChildren()) {
this.limpa(child);
}
}
}
Ou com a ajuda de algum conjunto de componentes, como por exemplo o OmniFaces e seu ResetInputAjaxActionListener:
<h:commandButton value="Atualizar" action="#{bean.atualiza}">
<f:ajax execute="input1" render="outroInput" />
<f:actionListener type="org.omnifaces.eventlistener.ResetInputAjaxActionListener" />
</h:commandButton>
Estas soluções ainda são as melhores - se não as únicas - opções para a maioria dos projetos que trabalham com JSF 2.1 ou inferior.
Resetando componentes no JSF 2.2
Somente depois de algumas issues importantes (#1129 e #2576) e muitas reclamações foi que expert group resolveu adicionar a funcionalidade para resetar o estado dos componentes no JSF 2.2 através do atributo resetValues
na tag f:ajax
:
<h:commandLink value="Salvar" action="#{bean.salvar}">
<f:ajax render="@form" resetValues="true"/>
</h:commandLink>
Se o resetValues
for setado para true
, o JSF limpará todos os componentes de input definidos no atributo render
da tag f:ajax
. Esta limpeza é feita antes de gerar o response parcial da página.
Vale salientar que para utilizar este novo atributo é necessário declarar as novas namespaces do JSF 2.2:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<!-- ... -->
</html>
Se você esquecer de declarar as novas namespaces a sua IDE não poderá auto-completar seu código.
Novos métodos também foram inseridos na API das classes UIViewRoot e EditableValueHolder. O mesmo código Java utilizado anteriormente para limpar um componente em particular poderia ser facilmente substituído por este:
EditableValueHolder evh = (EditableValueHolder) this.uiInput;
evh.resetValue(); // novo método
Caso você tenha acesso aos IDs dos componentes que deseja resetar, você pode utilizar o novo método resetValues
da UIViewRoot:
FacesContext ctx = FacesContext.getCurrentInstance();
List<String> clientIds = Lists.newArrayList("form:input1", "form:input2");
UIViewRoot view = ctx.getViewRoot();
view.resetValues(ctx, clientIds); // reseta os componentes da lista
Estes métodos não foram inseridos por acaso, já que internamente o JSF invoca o método UIViewRoot.resetValues
quando o atributo resetValues
é definido como true
na tag f:ajax
.
E se não uso AJAX?
Ter um formulário com componentes sujos não deveria ser um problema se trabalhamos com navegação entre páginas, já que estamos sempre mudando de XHTML, o que por sua vez força o JSF a recriar novas árvores de componentes.
Apesar disso, há casos em que o problema pode ocorrer e precisaremos limpar a árvore sem o uso de AJAX. Por esse motivo, o JSF 2.2 também introduziu a tag f:resetValues
:
<h:commandButton value="Limpar" action="#{bean.reset}" immediate="true">
<f:resetValues render="form:input1 form:input2"/>
</h:commandButton>
O que esta tag basicamente faz é registrar um action listener no componente de ação a fim de resetar todos os componentes declarados no atributo render
. Repare que os IDs informados no render
são os client IDs dos componentes gerados pelo JSF, portanto, valores especiais como @form
da f:ajax
não são suportados!
Ciclo de vida ainda é importante
Além das novas tags e API para limpar componentes, o JSF 2.2 também trouxe diversas outras melhorias para a especificação, como o upload de arquivos e suporte a HTML5. Com estes novos recursos alguns frameworks e componentes de terceiros passam a ser opcionais em nossos projetos.
Embora a limpeza dos componentes tenha sido resolvida no JSF 2.2, ainda assim é preciso ter um conhecimento sólido sobre sua árvore de componentes e seu ciclo de vida, pois sem estes dois conceitos em mente é provável que muitos dos problemas do dia a dia se tornem verdadeiros desafios seguidos de muitas dores de cabeça.
Caso queira aprender mais sobre o assunto, o ciclo de vida, a árvore de componentes e muitas das novidades do JSF 2.2 são estudadas com bastante profundidade no nosso curso de JSF 2 com Spring.
E você? Já conhecia os novos recursos do JSF 2.2 para limpar a árvore de componentes?
Desenvolvedor e instrutor na TriadWorks