Mostrando postagens com marcador JSF. Mostrar todas as postagens
Mostrando postagens com marcador JSF. Mostrar todas as postagens

quinta-feira, 21 de março de 2013

Layout Ajax com JSF

Esta informação está contida em outros blogs mas decidi escrevê-la aqui também porque sempre achei informações incompletas, sendo um pouco num blog e outro pouco noutro.

A ideia é criar um layout de website com área de cabeçalho, menu à esquerda e centro com conteúdo. Até aí é fácil e o Netbeans dá uma mão para a gente (na versão 7.3, crie um facelet e você verá). Neste layout, a intenção é permitir que o usuário clique no menu posicionado à esquerda e o conteúdo da página (no centro) seja atualizado sem que toda a página seja recarregada.

Primeiro, é necessário criar um controlador (bean) para manter a página corrente a ser carregada. Veja, no código abaixo, a declaração bem simples do IndexController;  perceba que o atributo currentPage é inicializado com o nome da página com o conteúdo inicial do site.

@ManagedBean
public class IndexController {

    private String currentPage = "home.xhtml"; // página com conteúdo inicial

    public String getCurrentPage() {
        return currentPage;
    }

    public void setCurrentPage(String currentPage) {
        this.currentPage = currentPage;
    }
}

Supondo que a página inicial seja index.xhtml, com o layout do site devidamente estruturado (junto com CSS), insira o código abaixo na área reservada para a descrição do menu. Aqui, o menu está bastante simples e é basicamente composto por dois links onde cada um deve abrir as páginas inserir.xhtml e listar.xhtml.

<h:form>
   <f:ajax render=":contentForm:reload">
      <h:commandlink action="#{indexController.setCurrentPage('inserir.xhtml')}" value="Inserir"/>
      <h:commandlink action="#{indexController.setCurrentPage('listar.xhtml')}" value="Listar"/>
   </f:ajax>
</h:form>

Ainda no mesmo arquivo index.xhtml, agora na área reservada para o conteúdo do website propriamente dito, insira o código abaixo.

<h:form id="contentForm">
    <h:panelGroup id="reload">
        <ui:include src="#{indexController.currentPage}"/>
    </h:panelGroup>
</h:form> 

Os códigos demonstrados acima fazem referência à 3 arquivos: home.xhtml, inserir.xhtml e listar.xhtml. Estes arquivos precisam ser criados com o conteúdo específico. Abaixo está o exemplo de como tais arquivos devem ser criados:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets">
    <ui:composition>
         Coloque aqui o conteúdo a ser exibido no website! 
    </ui:composition>
</html>

Com esta abordagem, a URL do website não modifca toda vez que o usuário clica no menu!

Agora suponha que o conteúdo exibido no website tenha um botão ou um link que leve à outra página. Naturalmente a ideia aqui é atualizar comente a área de conteúdo. O código abaixo mostra um exemplo de como seria isto:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">
    <ui:composition>
        <f:ajax render=":contentForm:reload">
            <h:commandLink value="Atualizar" action="#{indexController.setCurrentPage('/ui/alterar.xhtml')}"/>               
        </f:ajax>
    </ui:composition>
</html>

Veja que no código acima não está declarado a tag <h:form> para permitir a declaração do <h:commandLink>. Aqui, o form com o identificador 'contentForm' já fora delcarado em index.html e recebe toda a atualização da página e por isso não precisa ser declarado novamente.

Referências:

quinta-feira, 8 de março de 2012

Como Limpar um InputText no JSF a Partir do Managed Bean (Controller)

O objetivo aqui é simplesmente criar um formulário para inserir itens numa lista e atualizar os componentes automaticamente, sem ter que carregar toda a página. Em outras palavras, ao pressionar o botão para fazer a inserção, é lista é atualizada com o novo item e o campo de entrada do título item é limpo. Para tanto, utilizei JSF 2 e Primefaces 3.1. A solução foi encontrada no fórum Code Ranch, onde dois membros postaram duas soluções (Prakash Jebaraj & Gregg Bolinger) diferentes.

Solução 1
O código abaixo foi extraído dos meus testes e usei componentes do Primefaces. Aqui, somente uma entrada de texto e um botão para inserir fazem parte do foumulário para exemplificação.

<h:form id="idForm">
   <p:inputtext id="idNome" value="#{myManagedBean.nome}"/>
   <p:commandbutton actionlistener="#{myManagedBean.inserirNome(event)}" immediate="true" update="idNome" value="Inserir"/>
</h:form>

Ao pressionar o botão, o método inserirNome do meu Managed Bean é chamado, a página não é recarregada e o campo de entrada de texto é limpo.

@ManagedBean(name = "myManagedBean")
@SessionScoped
public class ManagedBean {
    
    private String nome;

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome= nome;
    }

    public void inserirNome(ActionEvent event) {
         // TODO: inserir nome em alguma lista ou base de dados
        FacesContext facesContext = FacesContext.getCurrentInstance();
        UIViewRoot uiViewRoot = facesContext.getViewRoot();
        HtmlInputText inputText = (HtmlInputText) uiViewRoot.findComponent("idForm:idNome");
        inputText.setSubmittedValue("");
        this.setNome("");
    }
}

Note que na linha 19 do código acima, a string usada para localizar o HtmlInputText é a concatenação dos identificadores da árvore de componentes da página, separado por dois pontos. Assim,  qualquer alteração nos identificadores ou na hierarquida dos componentes da página vai diretamente afetar esta solução.

Solução 2
A segunda solução não é muito diferente da primeira. Aqui, a alteração dos identificadores de componentes da página não tem impacto na solução porque o campo de entrada de texto é explicitamente associado a um elemento de interface gráfica do lado o servidor. Veja abaixo, no componente
inputText, a propriedade binding em uso, onde é feita esta associação.


<h:form id="idForm">
   <p:inputtext id="idNome" value="#{myManagedBean.nome}" binding="#{myManagedBean.uiNome}"/>
   <p:commandbutton actionlistener="#{myManagedBean.inserirNome(event)}" immediate="true" update="idNome" value="Inserir"/>
</h:form>

Desta forma, o Managed Bean precisa ter um atributo do tipo UIInput, com seus métodos get e set. Já o método inserirNome,invocado pelo actionListener do botão de inserir, tem menos código para fazer a limpeza do campo de entrada.

@ManagedBean(name = "myManagedBean")
@SessionScoped
public class ManagedBean {
    
    private String nome;
    private UIInput uiNome;

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome= nome;
    }

    public String getUiNome() {
        return uiNome;
    }

    public void setUiNome(String uiNome) {
        this.uiNome= uiNome;
    }

    public void inserirNome(ActionEvent event) {
        // TODO: inserir nome em alguma lista ou base de dados        
        this.getUiNome().setSubmittedValue("");
        this.setNome(""); 
    }
}

Esta segunda solução não está diretamente associada ao identificadores dos elementos da interface gráfica, assim, qualquer alteração de identificadores de componentes da página não vai afetar o código.

Referências:
http://www.coderanch.com/t/210589/JSF/java/Clearing-forms
https://cwiki.apache.org/confluence/display/MYFACES/Clear+Input+Components
http://www.guj.com.br/java/92758-resolvidolimpar-o-resultado-da-consulta-e-os-campos-do-formulario-com-jsf