6
respostas

Problemas com DataTable - Selection

Olá, vou descrever minha dúvida e logo após colocar o código(após ver o código e ler minha dúvida pela segunda vez, acho que ficará mais claro):

Estou tentando usar o DataTable - Selection do primefaces(usando como exemplo o próprio show case do framework, porém quando eu clico na "lupa" para exibir o model, ao invés de chamar só o target do botão usuarioBean.selectedUsuario

f:setPropertyActionListener value="#{usuario}"
                            target="#{usuarioBean.selectedUsuario}" />

Ele chama meu método inicial da montagem do datatable "getUsuarios", diversas vezes:

<p:dataTable value="#{usuarioBean.usuarios}" var="usuario">

Por fim quando vai abrir o modal, ele chama o método getSelectUsario uma vez retornando null.

Quando vai carregar a pagina a primeira vez, esse método getSelectUsario e o setSelectUsuario são chamados algumas vezes também, dessa vez retornando os valores das linhas do meu datatable... Ou seja, acredito que meu código esteja muito desorganizado quando a montagem dessa árvore de componentes.

Seguem os códigos de minha página e do ManagedBean:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:p="http://primefaces.org/ui">

<ui:composition template="../templates/_template.xhtml">
    <ui:define name="conteudo">
        <h:form id="opcoesUsuario">
            <p:fieldset legend="Escolha sua opção">
                <h:panelGrid columns="2">
                    <p:commandButton value="Incluir Usuário" id="incluirUsuario"
                        action="#{usuarioBean.telaIncluir}" icon="fa fa-plus-circle" />
                    <p:commandButton value="Pesquiar Usuário" id="pesquisarUsuario"
                        action="#{usuarioBean.pesquisarUsuario}" icon="fa fa-search-plus" />
                </h:panelGrid>
            </p:fieldset>
        </h:form>
        <br />
        <br />
        <h:form id="form">
            <h:messages />
            <p:dataTable value="#{usuarioBean.usuarios}" var="usuario">
                <p:column headerText="Nome">
                    <h:outputText value="#{usuario.pessoaFisica.noPessoa}" />
                </p:column>
                <p:column headerText="Matricula">
                    <h:outputText value="#{usuario.pessoaFisica.nrMatricula}" />
                </p:column>
                <p:column headerText="Email">
                    <h:outputText value="#{usuario.pessoaFisica.dsEmail}" />
                </p:column>
                <p:column headerText="Cargo">
                    <h:outputText value="#{usuario.noCargo}" />
                </p:column>
                <p:column style="width:32px;text-align: center">
                    <p:commandButton update=":form:detalheUsuario"
                        oncomplete="PF('usuarioDialog').show()" icon="ui-icon-search"
                        title="View">
                        <f:setPropertyActionListener value="#{usuario}"
                            target="#{usuarioBean.selectedUsuario}" />
                    </p:commandButton>
                </p:column>
            </p:dataTable>

            <p:dialog header="Usuário" widgetVar="usuarioDialog" modal="true"
                showEffect="fade" hideEffect="fade" resizable="false">
                <p:outputPanel id="detalheUsuario" style="text-align:center;">
                    <p:panelGrid columns="2"
                        rendered="#{not empty usuarioBean.selectedUsuario}"
                        columnClasses="label,value">

                        <h:outputText value="Nome:" />
                        <h:outputText value="#{usuario.pessoaFisica.noPessoa}" />

                        <h:outputText value="Matricula" />
                        <h:outputText value="#{usuario.pessoaFisica.nrMatricula}" />

                        <h:outputText value="Email:" />
                        <h:outputText value="#{usuario.pessoaFisica.dsEmail}" />

                        <h:outputText value="Cargo" />
                        <h:outputText value="$#{usuario.noCargo}" />

                    </p:panelGrid>
                </p:outputPanel>
            </p:dialog>
        </h:form>
    </ui:define>
</ui:composition>
</html>

UsuarioBean:

@Controller
@Scope("request") 
public class UsuarioBean {

    @Autowired
    private UsuarioService usuarioService;

    @Autowired
    private OrgaoService orgaoService;

    private Usuario usuario = new Usuario();

    private Usuario selectedUsuario;


    public Usuario getSelectedUsuario() {
        return selectedUsuario;
    }

    public void setSelectedUsuario(Usuario selectedUsuario) {
        this.selectedUsuario = selectedUsuario;
    }

    public Usuario getUsuario() {
        return usuario;
    }

    public void setUsuario(Usuario usuario) {
        this.usuario = usuario;
    }

    public void gravar(){
        System.out.println("Entrou no método Gravar");
    }

    public String pesquisarUsuario(){
        return "pesquisa";
    }

    public String telaIncluir(){
        return "incluir";
    }

    public String telaInicial(){
        return "index";
    }

    public List<Orgao> getOrgaos(){
        return orgaoService.getAll();
    }

    public List<Usuario> getUsuarios(){
        return usuarioService.getAll();
    }

    public String salvar(){
        usuario.setDsSenha("blbalaslasf");
        usuarioService.incluirUsuario(usuario);
        return "Index";
    }

}
6 respostas

Oi Edmilson, tudo bem ?

Pelo que entendi, seu problema é um pouquinho mais chato, pois receio que o que está acontecendo é que toda vez que você faz um click, você ative um form, que por sua vez faz uma nova requisição, e como o escopo é de request, você fica criando um novo bean sempre.

O que você pode fazer é trocar o escopo do seu bean para @ViewScoped pois ele manterá o seu bean vivo enquanto você fica naquela página.

Olá Matheus,

primeiramente obrigado pela atenção.

Fiquei com algumas dúvidas, a primeira é:

No código

                <p:column style="width:32px;text-align: center">
                    <p:commandButton update=":form:detalheUsuario"
                        oncomplete="PF('usuarioDialog').show()" icon="ui-icon-search"
                        title="View">
                        <f:setPropertyActionListener value="#{usuario}"
                            target="#{usuarioBean.selectedUsuario}" />
                    </p:commandButton>
                </p:column>

na tag update=":form:detalheUsuario" o que deveria ser recarregado não é só o componente "detalheUsuario" que deveria ser recarregado?

A segunda dúvida é a seguinte: Para eu usar o ViewScope no Spring eu vou ter que criar um escopo customizado para o Spring?

Como comentado no link: https://www.primefaces.org/port-jsf-2-0s-viewscope-to-spring-3-0/

A justificativa de tá usando anotações do Spring e não do JSF é que o backend usa dele para injetar os services e daos e quando fui misturar as anotações no bean, o service não tava sendo instanciado com a anotação @autowired.

Edmison vamos lá, oque está acontecendo com você, a sua primeira duvida, veja o seu código irmão,

  <h:form id="form">
            <h:messages />
            <p:dataTable value="#{usuarioBean.usuarios}" var="usuario">
                <p:column headerText="Nome">
                    <h:outputText value="#{usuario.pessoaFisica.noPessoa}" />
                </p:column>
                <p:column headerText="Matricula">
                    <h:outputText value="#{usuario.pessoaFisica.nrMatricula}" />
                </p:column>
                <p:column headerText="Email">
                    <h:outputText value="#{usuario.pessoaFisica.dsEmail}" />
                </p:column>
                <p:column headerText="Cargo">
                    <h:outputText value="#{usuario.noCargo}" />
                </p:column>
                <p:column style="width:32px;text-align: center">
                    <p:commandButton update=":form:detalheUsuario"
                        oncomplete="PF('usuarioDialog').show()" icon="ui-icon-search"
                        title="View">
                        <f:setPropertyActionListener value="#{usuario}"
                            target="#{usuarioBean.selectedUsuario}" />
                    </p:commandButton>
                </p:column>
            </p:dataTable>

            <p:dialog header="Usuário" widgetVar="usuarioDialog" modal="true"
                showEffect="fade" hideEffect="fade" resizable="false">
                <p:outputPanel id="detalheUsuario" style="text-align:center;">
                    <p:panelGrid columns="2"
                        rendered="#{not empty usuarioBean.selectedUsuario}"
                        columnClasses="label,value">

                        <h:outputText value="Nome:" />
                        <h:outputText value="#{usuario.pessoaFisica.noPessoa}" />

                        <h:outputText value="Matricula" />
                        <h:outputText value="#{usuario.pessoaFisica.nrMatricula}" />

                        <h:outputText value="Email:" />
                        <h:outputText value="#{usuario.pessoaFisica.dsEmail}" />

                        <h:outputText value="Cargo" />
                        <h:outputText value="$#{usuario.noCargo}" />

                    </p:panelGrid>
                </p:outputPanel>
            </p:dialog>
        </h:form>

Você ta dando um update dentro do seu form então não necessariamente você precisa do : depois do update.

  <p:commandButton update=":form:detalheUsuario" //está assim.
  <p:commandButton update="form:detalheUsuario" // deixa assim ok?

E sim irá atualizar apenas o seu detalheUsuario. Ok a questão de não mostrar é que você está usando o usuario da sua lista. E isso não vai rolar, não sei como que ta o seu bean, mais o meu chute é você fazer algo parecido com isso.

 <p:dialog header="Usuário" widgetVar="usuarioDialog" modal="true"
                showEffect="fade" hideEffect="fade" resizable="false">
                <p:outputPanel id="detalheUsuario" style="text-align:center;">
                    <p:panelGrid columns="2"
                        rendered="#{not empty usuarioBean.selectedUsuario}"
                        columnClasses="label,value">

                        <h:outputText value="Nome:" />
                        <h:outputText value="#{usuarioBean.usuario.pessoaFisica.noPessoa}"/> // FAZ ESSE TESTE e retorna aqui para ver se deu.


            </p:dialog>

Uma outra coisa oque achei estranho no seu código é isso.

<f:setPropertyActionListener value="#{usuario}"
                            target="#{usuarioBean.selectedUsuario}" />
                    </p:commandButton>

 private Usuario selectedUsuario;

Você vai levar nullpointer por causa disso, da onde tirou essa variavel? selectedUsuario? kkk troca isso, deixa assim.

<f:setPropertyActionListener value="#{usuario}"
                            target="#{usuarioBean.usuario}"  // muda aqui/>
                    </p:commandButton>

 private Usuario selectedUsuario; // e apaga aqui.

E também apaga o seu rendered, do componente panelGrid,

       rendered="#{not empty usuarioBean.selectedUsuario}"

Testa la e retorna aqui kkk

Seguinte, alterei o @Scope("view") utilizando o view e criei o viewScope dando um implementando o do Spring .

Fiz também as alterações sugeridas pelo Alisson Fernando e agora está carregado os dados direitinho no modal.

O único problema que não foi resolvido, é que quando clico no

                    <p:commandButton update="form:detalheUsuario"
                        oncomplete="PF('usuarioDialog').show()" icon="ui-icon-search"
                        title="View">
                        <f:setPropertyActionListener value="#{usuario}"
                            target="#{usuarioBean.usuario}" />
                    </p:commandButton>

Ele continua invocando o método getUsuarios do dataTable, várias vezes.

<p:dataTable value="#{usuarioBean.usuarios}" var="usuario">

Cara ele invoca o método usuarios mais oque que acontece?

Deixa ver se eu consigo explicar melhor:

    <h:form id="form">
            <h:messages />
            <p:dataTable value="#{usuarioBean.usuarios}" var="usuario">
                <p:column headerText="Nome">
                    <h:outputText value="#{usuario.pessoaFisica.noPessoa}" />
                </p:column>
                <p:column headerText="Matricula">
                    <h:outputText value="#{usuario.pessoaFisica.nrMatricula}" />
                </p:column>
                <p:column headerText="Email">
                    <h:outputText value="#{usuario.pessoaFisica.dsEmail}" />
                </p:column>
                <p:column headerText="Cargo">
                    <h:outputText value="#{usuario.noCargo}" />
                </p:column>
                <p:column style="width:32px;text-align: center">
                    <p:commandButton update="form:detalheUsuario"
                        oncomplete="PF('usuarioDialog').show()" icon="fa fa-search-plus"
                        title="View">
                        <f:setPropertyActionListener value="#{usuario}"
                            target="#{usuarioBean.usuario}" />
                    </p:commandButton>
                </p:column>
            </p:dataTable>

            <p:dialog header="Usuário" widgetVar="usuarioDialog" modal="true"
                showEffect="fade" hideEffect="fade" resizable="false">
                <p:outputPanel id="detalheUsuario" style="text-align:center;">
                    <p:panelGrid columns="2"
                        rendered="#{not empty usuarioBean.usuario}"
                        columnClasses="label,value">

                        <h:outputText value="Nome:" />
                        <h:outputText value="#{usuarioBean.usuario.pessoaFisica.noPessoa}" />

                        <h:outputText value="Matricula" />
                        <h:outputText
                            value="#{usuarioBean.usuario.pessoaFisica.nrMatricula}" />

                        <h:outputText value="Email:" />
                        <h:outputText value="#{usuarioBean.usuario.pessoaFisica.dsEmail}" />

                        <h:outputText value="Cargo" />
                        <h:outputText value="$#{usuarioBean.usuario.noCargo}" />

                    </p:panelGrid>
                </p:outputPanel>
            </p:dialog>
        </h:form>

Esse é o código de meu datatable, que tem como uma de suas colunas o commandButtom que vai exebir o meu modal:

                <p:column style="width:32px;text-align: center">
                    <p:commandButton update="form:detalheUsuario"
                        oncomplete="PF('usuarioDialog').show()" icon="fa fa-search-plus"
                        title="View">
                        <f:setPropertyActionListener value="#{usuario}"
                            target="#{usuarioBean.usuario}" />
                    </p:commandButton>
                </p:column>

Quando eu clico nesse buttom, ele chama diversas vezes o método "dessa linha de código" getUsuarios da sua própria datatable

<p:dataTable value="#{usuarioBean.usuarios}" var="usuario">

O problema disso é que toda vez que ele é chamado a consulta ao banco para montar o grid é executado, não sei se agora consegui ser mais claro com meu problema.

A questão é como não invocar tantas vezes esse método, ou melhor, entender o porque ele não invoca apenas a exibição do modal.