Atualizar valores do selectOneMenu depois de inserir um novo num dialog

24 respostas
J

Pessoal,

Tenho um selectOneMenu preenchido com valore do BD. Como pode acontecer de não ter o valor que o usuario quer nessa lista, criei um link do lado para que seja aberto um dialog e o usuario possa incluir o valor que deseja. O problema é que após a inserção no BD (está salvando direitinho) o selectOneMenu não é atualizado e não exibe o novo valor incluido pelo usuario, só exibe depois que eu executo o projeto de novo.

Alguém pode me ajudar a resolver isso?

CODIGO:

<h:selectOneMenu id="categoria" value="#{produtoController.produto.categoria}"
                                         required="true">                                                
                            <f:selectItems value="#{categoriaController.listaCategoriasAtivas}"/>                        
                            <f:converter converterId="categoriaConverter"/>
                        </h:selectOneMenu>
                        <p:spacer width="3"/>
                        <p:commandButton icon="ui-icon-plusthick"
                                         alt="Incluir uma nova categoria"
                                         title="Incluir uma nova categoria"
                                         update=":formNovaCategoria:dadosCategoria" 
                                         oncomplete="incluirCategoriaDialog.show();"                                         
                                         style="width: 28px; height: 28px;"/>  


<p:dialog header="Incluir nova categoria" widgetVar="incluirCategoriaDialog" 
                  width="550" height="250" 
                  resizable="true" closable="true" showEffect="slide" hideEffect="slide">                      

            <h:form id="formNovaCategoria">

                <h:outputText value="Campos com (*) são de preenchimento obrigatório!"
                              style="font-weight: bold;"/>
                <p:separator/>

                <h:panelGrid id="dadosCategoria" columns="2">                    
                    <h:outputLabel for="descricao" value="Descrição (*):"/>
                    <h:inputText id="descricao" value="#{categoriaController.categoria.descricao}"
                                 size="40" maxlength="100"/>                                                     

                    <h:outputLabel for="ativo" value="Ativo:"/>
                    <h:selectOneMenu id="ativo" value="#{categoriaController.categoria.ativo}">
                        <f:selectItem itemValue="true" itemLabel="Sim"/>
                        <f:selectItem itemValue="false" itemLabel="Não"/>                        
                    </h:selectOneMenu>                    

                </h:panelGrid>                                

                <br/>
                <p:commandButton image="ui-icon ui-icon-disk" value="Salvar"
                                 update=":formPrincipal:categoria"
                                 oncomplete="incluirCategoriaDialog.hide();"
                                 action="#{categoriaController.salvar}"/>                
                <p:commandButton image="ui-icon ui-icon-arrowthickstop-1-w" value="Fechar"
                                 onclick="incluirCategoriaDialog.hide()"/>   

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

Como já falei está salvando direitinho no BD, só não atualiza depois da inclusa o selectOneMenu.
Tive que criar um outro h:form, pois os campos que estão no dialog têm, o mesmo nome dos campos do form principal.
Já alterei varias vezes a propriedade update dos buttons, mas nada.

Espero que tenha sido claro e que alguem possa me ajudar.

24 Respostas

J

Alguem pode me ajudar?

R

No richfaces eu colocaria um <a4j:outputPanel> com ajaxRendered=“true”,não sei como fica isso no Prime.

E

Você atualiza a sua listaCategoriasAtivas após gravar no banco ?

J

Acho que não esta atualizando a lista de categorias ativas após inserir no banco. Como faria isso?

J

Alguem? Por favor

J

Sera que alguem pode me ajudar a resolver esse problema? Preciso disso urgente e até agora não achei nada que me ajudasse.
Só preciso que a lista que está carregada na minha combobox (selectOneMenu) seja atualizada após a inserção de um nov registro, através do dialog.

Desde já agradeço.

N

eu faria da seguinte maneira:

xhtml:

<h:selectOneMenu id="categoria" value="#{produtoController.produto.categoria}"  
                                         required="true">                                                  
          <f:selectItems value="#{categoriaController.listaCategoriasAtivas}"/>  
</h:selectOneMenu>

bean:

private List<SelectItem> listaCategoriasAtivas;

public void carregaListaCategoriasAtivas(){
   List<Categorias> lista = new CategoriasDaoImp.list(); //cria uma lista com os dados do banco
   listaCategoriasAtivas = new ArrayList<SelectItem>();

   for(Categorias c : lista) {
       listaCategoriasAtivas.add(new SelectItem(c.getId, c.getNome);
   }
}

Toda vez que o usuário adicionar uma nova categoria, dentro do método que salva a nova categoria, você chama esse metodo pra recarregar a lista.

J

Já fiz isso e não resolveu.

Meu bean ficou assim:

public List<SelectItem> getListaCategoriasAtivas() {
        if (listaCategoriasAtivas == null) {
            listaCategoriasAtivas = new ArrayList<SelectItem>();
            List<Categoria> lista = categoriaDao.listarAtivas();

            for (Categoria cat : lista) {
                listaCategoriasAtivas.add(new SelectItem(cat, cat.getDescricao()));
            }
        }
        return listaCategoriasAtivas;
    }

public String salvar() {                           
        this.categoriaDao.saveOrUpdate(this.categoria);
       
        this.categoria = new Categoria();

         return null;
    }
        this.getListaCategoriasAtivas();

Não atualiza o selectOneMenu ainda

J

Consegui resolver.

Além de chamar o metodo para listar as categorias de novo eu mudei meu escopo para request (troquei a anotação @SessionScoped para @RequestScoped)

Valeu

N

Que bom cara! Eu uso sempre o @ViewScoped.

Não sei se você mudou, mas não é aconselhavel fazer consultas ao banco dentro dos get/set do Bean/Controller devido ao ciclo de vida do JSF, dependendo do bean, vai deixar sua aplicação bem lenta, digo por experiencia própria rsrs

J

Achei que tinha resolvido, mas estou com problemas ainda. Como tinha feito o cadastro dentro de um dialog, alterei para request e funcionou, o problema é que agora fui fazer dentro de um arquivo separado, pois o usuario poderá incluir via dialog (atalho rapido) ou atraves do menu principal (que chama um arquivo). Quando vou salvar, a partir do arquivo princiapl, usando RequestScoped, salva, mas não edita, na hora de editar ele salva de novo. Vou tentar agora com View Scoped, pra ver o que acontece.

Eu ainda não alterei o que você falou, continuo chamando o metodo list do dao através do meu getLista, como devo melhorar isso? Voce acha melhor eu ter um metodo listar() que vai ser chamado dentro do meu get()? Por exemplo:
getLista(){
 this.listar().
 return lista.
}

public List<> listar(){
 this.dao.list();
}
N

Se você criar um método e chamá-lo dentro do get, continuara praticamente a mesma coisa. Você pode criar um metodo que popula o selectOneMenu e chamá-lo no final do metodo salvar, chame o metodo também no construtor do bean para que ao carregar a pagina ele já traga o selectOneMenu atualizado.

J

Entendi.

Já faço dessa maneira, carregando no construtor, mas carregando uma lista (List) normal e não carregnado SelectItens, achei que meu construtor ficaria com muitos metodos, mas vou mudar isso.
Estou com muita duvida na utilização de ViewScoped, quando coloquei essa anotação no meu controller, ao clicar em editar um objeto eu perco os dados do mesmo, ao trocar de pagina, poderia me dar algum exemplo. Estou lendo esse blog - http://blog.gilliard.eti.br/tag/view-scope/ - mas estou perdido

N

Esse editar é um botão/link? Cole aqui o código do botão ou até a página inteira

J

Pagina inicial:

<p:dataTable id="categorias" var="categoria" value="#{categoriaController.listaCategoriasParaDataTable}"                             
                             paginator="true" rows="12"
                             paginatorTemplate="{FirstPageLink} {PreviousPageLink} 
                             {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"                              
                             rowsPerPageTemplate="12,24,36"                                                                     
                             emptyMessage="Nenhuma categoria cadastrada!">                       
                                        
                    <p:column style="text-align: left; width: 55px;"> 
                        <f:facet name="header">  
                            C&oacute;d.
                        </f:facet> 
                        <h:outputText value="#{categoria.id}" style="color: black;" rendered="#{categoria.ativo}"/>  
                        <h:outputText value="#{categoria.id}" style="color: blue;" rendered="#{!categoria.ativo}"/>  
                    </p:column>  

                    <p:column style="text-align: left;">  
                        <f:facet name="header">  
                            Categoria
                        </f:facet>
                        <h:outputText value="#{categoria.descricao}" style="color: black;" rendered="#{categoria.ativo}"/>  
                        <h:outputText value="#{categoria.descricao}" style="color: blue;" rendered="#{!categoria.ativo}"/>  
                    </p:column> 

                    <p:column style="text-align: center;">  
                        <f:facet name="header">  
                            Ativa
                        </f:facet>
                        <h:outputText value="Sim" style="color: black;" rendered="#{categoria.ativo}"/>  
                        <h:outputText value="N&atilde;o" style="color: blue;" rendered="#{!categoria.ativo}"/>  
                    </p:column> 

                    <p:column style="text-align: center; width: 100px;"> 
                        
                        <p:commandButton image="ui-icon-pencil"
                                         alt="Editar os dados da categoria de produtos" 
                                         title="Editar os dados da categoria de produtos" 
                                         action="#{categoriaController.prepararParaEditar}"                                         
                                         ajax="false" immediate="true"                                       
                                         style="height: 23px; width: 25px;">
                            <f:setPropertyActionListener 
                                value="#{categoria}" target="#{categoriaController.categoriaSelecionada}" />
                        </p:commandButton>                       
                    </p:column>

CONTROLLER:

@ManagedBean(name = "categoriaController")
@ViewScoped
public class CategoriaController {

    private Categoria categoria;
    private Categoria categoriaSelecionada;
    private CategoriaDao categoriaDao;

    private List<SelectItem> listaCategoriasParaCombobox;    

    private List<Categoria> listaCategoriasParaDataTable;
    private String filtro;
    private String tipoFiltro;

    public CategoriaController() {
        this.categoria = new Categoria();
        this.categoriaSelecionada = new Categoria();
        this.categoriaDao = new CategoriaDaoImp();
        this.listarCategoriasAtivasParaCombobox();
        this.listaCategoriasParaDataTable = this.categoriaDao.list("ativas");
    }

    public Categoria getCategoria() {
        return categoria;
    }

    public void setCategoria(Categoria categoria) {
        this.categoria = categoria;
    }

    public Categoria getCategoriaSelecionada() {
        return categoriaSelecionada;
    }

    public void setCategoriaSelecionada(Categoria categoriaSelecionada) {
        this.categoriaSelecionada = categoriaSelecionada;
    }

   
    public List<SelectItem> getListaCategoriasParaCombobox() {                
        return this.listaCategoriasParaCombobox;
    }

    public List<Categoria> getListaCategoriasParaDataTable() {
        return this.listaCategoriasParaDataTable;
    }           

    public void listarCategoriasAtivasParaCombobox() {                
        
        if (listaCategoriasParaCombobox == null) {
            listaCategoriasParaCombobox = new ArrayList<SelectItem>();
            List<Categoria> lista = categoriaDao.list("ativas");

            for (Categoria cat : lista) {              
                listaCategoriasParaCombobox.add(new SelectItem(cat, cat.getDescricao()));
            }
        }                
    }
      
   
    public String incluirNovaCategoria(){ 
        this.categoria = new Categoria();
        
        return "manterCategoria";
    }    
    
    public String prepararParaEditar(){
        this.categoria = categoriaSelecionada;
        
        return "manterCategoria";
    }     

    public void salvar() throws IOException {
               
        this.categoriaDao.saveOrUpdate(this.categoria);

        this.categoria = new Categoria();

        this.listarCategoriasAtivasParaCombobox();

        String url = "categoria.sgm";

        FacesContext fc = FacesContext.getCurrentInstance();
        ExternalContext ec = fc.getExternalContext();

        ec.redirect(url);
    }

Editar/cadastrar categoria

<h:form id="formPrincipal" style="font-size: 16px;"> 

                <p:focus for="descricao"/>

                <h:panelGrid id="dadosCategoria" columns="3">

                    <!--Somente na edição dos dados da categoria que o campo código é mostrado-->
                    <h:outputLabel for="codigo" value="C&oacute;digo:" rendered="#{categoriaController.categoria.id != null}"/>
                    <h:inputText id="codigo" value="#{categoriaController.categoria.id}" 
                                 disabled="true" size="10" rendered="#{categoriaController.categoria.id != null}"/>  
                    <p:column rendered="#{categoriaController.categoria.id != null}"/>

                    <h:outputLabel for="descricao" value="Categoria (*):"/>
                    <h:inputText id="descricao" value="#{categoriaController.categoria.descricao}"
                                 required="true" size="80" maxlength="100"
                                 requiredMessage="Por favor, digite um nome para a categoria."/>  
                    <p:column/>

                    <h:outputLabel for="ativo" value="Ativo:"/>
                    <h:selectOneMenu id="ativo" value="#{categoriaController.categoria.ativo}">
                        <f:selectItem itemValue="true" itemLabel="Sim"/>
                        <f:selectItem itemValue="false" itemLabel="N&atilde;o"/>                        
                    </h:selectOneMenu>
                    <p:column/>                   

                </h:panelGrid> 

                <h:messages styleClass="erros"/>

                <p:separator/>

                <p:commandButton image="ui-icon ui-icon-disk" value="Salvar"                                     
                                 action="#{categoriaController.salvar}" ajax="false"/>                
                <p:commandButton image="ui-icon ui-icon-arrowthickstop-1-w" value="Voltar"
                                 onclick="javascript:history.back(1)"/>
                
            </h:form>
J

Se estiver algum erro, pode me falar, por favor.

Serei muito grato se puder me ajudar, estou o dia inteiro quebrando a cabeça com esse problema: estava tudo funcionando, sempre usei o request scope, aí de repente parou de editar, somente salva, se eu tentar editar o objeto categoria, automaticamente é criado um novo. Se eu fico alterando os escopo, às vezes nem inclui. Esses escopos estão interferindo no meu projeto todo, pois, como falei, tenho um atalho para cadastrar um categoria, que não atualiza o selectOneMenu, dependendo do escopo. Até o login, no caso o logout, dá erro, dependendo do escopo. Tento colocar tudo com session, dá erro, se eu colocar tudo com request, dá erro. Não sei mais o que faço. Tentei adicionar o Ajax4Jsf e modificar algumas coisas, mas quando tento adicionar o RichFaces, para poder usar o Ajax4Jsf, dá erro no projeto e não consigo mais rodar, diz que o módulo não foi implementado, enfim, só está dando erro, e não acho as soluções.

N

Explique-me uma coisa, quando você clica em editar, ele recarrega a mesma página? Se for isso, você realmente perde o objeto porque seu bean esta como ViewScoped, ou seja, ele dura apenas naquela view que você está, cada vez que vc recarregar a página, ele vai instanciar tudo novamente. Uma solução seria você colocar esse editar em um dialog. Se você já está fazendo isso, no commandButton, chame o metodo preparaEditar no actionListener e nao na action.

J

Na verdade, ele chama uma nova pagina. Eu exibo as categorias em um dataTable (categoria.xhtml) se o usuário clicar em editar em alguma linha dentro dessa tabela, eu o redireciono para uma nova pagina, chamado manterCategoria.xhtml.
O escopo mais indicado é o View mesmo? Você acha melhor eu manter o view scope e ao invés de redirecionar, abrir um dialog para a edição?

Acho que vou tenta fazer isso, porque com request ou com session está com problemas.

N

Então cara, aí acho que já é questão de gosto rs. Nos meus projetos eu só uso ViewScoped, se preciso passar pra outra página e continuar com o mesmo objeto, eu jogo esse objeto na sessão e pego na outra página, mas quando faço alguma coisa igual você fez, com editar e tal, sempre faço com dialog até pra ficar menos arquivos .xhtml no projeto, mas como eu disse, é questão de gosto rs. E quanto a manter ou não, sinceramente, nunca usei o RequestScoped, apenas vi alguns materias falando sobre, e como até agora o viewScoped tem me atendido muito bem, nisso não tenho como opinar.

J

Vou tentar fazer dentro de um dialog, utilizando o view scope, e amanhã posto o resultado.

Depois, por favor, teria como mo mostrar um exemplo de como coloca o que quer na sessão para recuperar em outra página?

VOcê chegou a ver algum erro no meu controller? Alguma dica? Algo que pode melhorar? Ou estou no caminho?

Muito obrigado.

N

Tá ótimo cara, tá no caminho sim =)

J

Pessoal,

Continuo com o mesmo problema. Como havia falado, quando coloquei o RequestScoped no meu controller funcionou, o problema é que a troca de escopo implicou em outros erros, tive então que refazer minhas telas e comecei a usar o ViewScoped, só que agora o selectOneMenu não está sendo atualizado, após cadatro no BD.

O que quero é o seguinte:
O selectOneMenu está sendo preenchido com valores vindos do BD, do lado tem um link para um dialog que possibilita ao usuário cadastrar um novo valor, caso ainda não tenha o que ele quer listado no combobox. Após o cadastro no BD e o fechamento do dialog, o valor cadastrado já deve aparecer automaticamente no selectOneMenu, ou seja, após o cadastro no BD o selectOneMenu deve ser atualizado, mas não estou conseguindo fazer isso.

Já alterei o update do botão, após o cadastro no BD eu chamo o método que carrega a lista de novo, já tentei com valueChangeListener e com binding, mas até agora não conseguir implementar isso.

Se alguém puder me ajudar, agradeço.

Combobox e link para dialog:

<p:selectOneMenu id="listaCategorias" value="#{produtoController.produto.categoria}" converter="categoriaConverter"
            required="true" requiredMessage="Por favor, selecione uma categoria.">
                     <f:selectItem itemLabel="Selecione..."/>
                     <f:selectItems value="#{categoriaController.listaCategoriasParaCombobox}"/>                                                                               
</p:selectOneMenu> 

 <p:spacer width="8"/>                      

 <p:commandLink value="+ Nova Categoria"                                        
       title="Inlcuir uma nova categoria"
       onclick="incluirCategoriaDialog.show()"
       update=":formNovaCategoria:dadosCategoria"/>

Dialog:

<p:dialog header="Incluir uma nova categoria" widgetVar="incluirCategoriaDialog" 
                      minWidth="650" minHeight="200" resizable="true" closable="true"                       
                      showEffect="slide" hideEffect="slide">                                              

                <h:form id="formNovaCategoria" style="font-size: 16px;">

                    <p:focus for="descricao"/>

                    <h:outputText value="Campos com (*) s&atilde;o de preenchimento obrigat&oacute;rio!"
                                  style="font-size: 14px; font-style: italic;"/>

                    <p:separator/>

                    <h:panelGrid id="dadosCategoria" columns="2">                    
                        
                        <h:outputLabel for="descricao" value="Categoria (*):"
                                       styleClass="labelNegrito"/>
                        <h:inputText id="descricao" value="#{categoriaController.categoria.descricao}"
                                     maxlength="30" size="50"
                                     required="true" 
                                     requiredMessage="Por favor, digite um nome para a categoria de produtos."/>                          

                        <h:outputLabel for="ativo" value="Ativa:"
                                       styleClass="labelNegrito"/>
                        <h:selectOneMenu id="ativo" value="#{categoriaController.categoria.ativo}">
                            <f:selectItem itemValue="true" itemLabel="Sim"/>
                            <f:selectItem itemValue="false" itemLabel="N&atilde;o"/>                        
                        </h:selectOneMenu>
                        
                    </h:panelGrid>                                                
    
                    <h:messages styleClass="erros"/>                                       

                    <p:separator/>                                

                    <p:commandButton image="ui-icon ui-icon-disk" value="Salvar"                                                                          
                                     actionListener="#{categoriaController.salvarDoDialogDeProdutos}"                                     
                                     oncomplete="incluirCategoriaDialog.hide();"
                                     update=":formManterProduto"/> 
                    
                    <p:commandButton image="ui-icon ui-icon-arrowthickstop-1-w" value="Fechar"
                                     onclick="incluirCategoriaDialog.hide()"
                                     immediate="true"/>   

                </h:form>

            </p:dialog>

CONTROLLER:

@ManagedBean(name = "categoriaController")
@ViewScoped
public class CategoriaController {
public void salvarDoDialogDeProdutos(){
        this.categoriaDao.save(categoria);
              
        this.carregarListaDeCategoriasAtivasParaCombobox();
    }

public final void carregarListaDeCategoriasAtivasParaCombobox() {
        
        if (listaCategoriasParaCombobox == null) {
            listaCategoriasParaCombobox = new ArrayList<SelectItem>();
            List<Categoria> lista = categoriaDao.list("ativas");

            for (Categoria cat : lista) {
                 listaCategoriasParaCombobox.add(new SelectItem(cat, cat.getDescricao()));
            }
        }
    }
}
N
JeffersonJCosta:
Pessoal, CONTROLLER:
@ManagedBean(name = "categoriaController")
@ViewScoped
public class CategoriaController {
public void salvarDoDialogDeProdutos(){
        this.categoriaDao.save(categoria);
              
        this.carregarListaDeCategoriasAtivasParaCombobox();
    }

public final void carregarListaDeCategoriasAtivasParaCombobox() {
        
        if (listaCategoriasParaCombobox == null) {
            listaCategoriasParaCombobox = new ArrayList<SelectItem>();
            List<Categoria> lista = categoriaDao.list("ativas");

            for (Categoria cat : lista) {
                 listaCategoriasParaCombobox.add(new SelectItem(cat, cat.getDescricao()));
            }
        }
    }
}

JeffersonJCosta, ele não está atualizando porque vc tem um if(listaCategoriasParaCombobox == null) na hora de popular a lista do combo, ou seja, quando vc inserir mais uma categoria e passar por esse método, listaCategoriasParaCombobox já não vai ser mais null por já ter sido instanciada.

Você pode tirar esse if, porque você sempre vai ter que instanciar a lista a cada atualização, se não a cada atualização da lista, os itens iam se duplicar. Não tinha reparado nesse if quando você mandou o código perguntando se estava tudo certo nele rs, deve ter sido por eu estar programando ao mesmo tempo aqui rs.

J

Valeu pelo toque.

Era só isso mesmo, estava quebrando a cabeça e era uma boeira (sempre é assim né?)

Muito obrigado.

Criado 5 de março de 2012
Ultima resposta 22 de mar. de 2012
Respostas 24
Participantes 4