Powered By Blogger

quarta-feira, 2 de março de 2016

Utilizando o propriedade TREE do Primefaces 5.3

Opa, sobrou um tempinho vamos lá atualizar o Blog, quem sabe isso pode ajudar alguém ai.

Estes dias precisei utilizar o  com uma particularidade, que era poder arrastar e soltar o componente, para a outra caixa. tipo um .

O maior problema desta utilização é a possibilidade, de se arrastar o filho e trazer o pai automaticamente.
A implementação ficaria, algo parecido com isso.

 <body>  
      <h:form id="form">  
           <p:growl id="msgs" showDetail="true" />  
           <h:panelGrid columns="1" cellpadding="4" cellspacing="4" width="100%"  
                border="0">  
                <p:row>  
                     <p:outputLabel value="#{msg['perfil2']} " />  
                     <p:outputLabel value=" #{perfilMB.perfil.nome}" />  
                </p:row>  
                <p:separator />  
           </h:panelGrid>  
           <h:panelGrid columns="3">  
                <p:tree id="tree1" value="#{perfilMB.tree}" var="node" selectionMode="single" selection="#{perfilMB.selectedNode1}"  
         draggable="true" droppable="true" dragdropScope="demo">  
            <p:ajax event="dragdrop" listener="#{perfilMB.onDragDrop}" update=":form:msgs" />  
            <p:treeNode>  
              <h:outputText value="#{node}" />  
            </p:treeNode>  
          </p:tree>  
                <img  
                     src="#{facesContext.externalContext.request.contextPath}/resources/imagens/transfer.png"  
                     border="0" />  
                <p:tree id="tree2" value="#{perfilMB.tree2}" var="node" selectionMode="single" selection="#{perfilMB.selectedNode2}"  
         draggable="true" droppable="true" dragdropScope="demo">  
            <p:ajax event="dragdrop" listener="#{perfilMB.onDragDrop}" update=":form:msgs" />  
            <p:treeNode>  
              <h:outputText value="#{node}" />  
            </p:treeNode>  
          </p:tree>  
           </h:panelGrid>  
      </h:form>  
 </body>  


A parte do ManagerBean, possui 2 métodos recursivos, que montam a árvore de acordo com os dados retornados da base de dados.

 public void montaArvore(){  
           tree = new DefaultTreeNode();  
           List<FuncionalidadeORM> lstMenu = new ArrayList<FuncionalidadeORM>(funcService.buscaMenusPai());  
           for (FuncionalidadeORM func : lstMenu) {  
                if (func.getFuncPai() == null) {  
                     TreeNode no = new DefaultTreeNode(func.getNome(), null);  
                     for (FuncionalidadeORM func1 : funcService.SubMenus(func.getId())) {  
                          if(funcService.SubMenus(func1.getId()).isEmpty()){  
                               TreeNode item = new DefaultTreeNode(func1.getNome(), null);  
                               no.getChildren().add(item);  
                          }else{  
                               TreeNode subItem = new DefaultTreeNode(func1.getNome(), null);  
                               subItem = geraSubmenu(func1);  
                               no.getChildren().add(subItem);  
                          }  
                     }  
                     tree.getChildren().add(no);  
                }  
           }  
      }  
      private TreeNode geraSubmenu(FuncionalidadeORM principal) {  
           TreeNode subItem = new DefaultTreeNode(principal.getNome(),null);  
           for (FuncionalidadeORM func1 : funcService.SubMenus(principal.getId())) {  
                if(funcService.SubMenus(func1.getId()).isEmpty()){  
                     TreeNode item = new DefaultTreeNode(func1.getNome(), null);  
                     subItem.getChildren().add(item);  
                }else{  
                     subItem.getChildren().add(geraSubmenu(func1));  
                }  
           }  
           return subItem;  
      }  


O método capaz de fazer a funcionalidade de arrastar e soltar, é bastante simples.

public void onDragDrop(TreeDragDropEvent event) {
        TreeNode dragNode = event.getDragNode();
        TreeNode dropNode = event.getDropNode();
        int dropIndex = event.getDropIndex();
         
        FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Dragged " + dragNode.getData(), "Dropped on " + dropNode.getData() + " at " + dropIndex);
        FacesContext.getCurrentInstance().addMessage(null, message);
    }


Espero que possa ser útil, qualquer dúvida só chamar ai.


terça-feira, 12 de janeiro de 2016

SelectManyCheckbox do Primefaces, carregando uma lista de Entidades.

   Precisei fazer o SelectManyCheckbox, para o conjunto de informações que estavam na base de dados, informar todas as possibilidade de Níveis, e no momento da Edição trazer preenchido os mesmo.


O problema se deu, na edição, quando havia a necessidade de trazer as informações editadas. 
Ex. alterar as opções de níveis. 
Quando iria persistir no banco, era informado o erro de LazyInitializationException.

Por que o erro LazyInitializationException acontece?

Toda vez que uma consulta é feita no banco dados o JPA irá trazer todas as informações da classe. A exceção dessa regra é quando falamos de lista. Imagine que a classe Anúncio tem uma lista de 70,000 emails para ao qual ele será enviado. Caso você quisesse exibir apenas o nome desse anúncio na tela do usuário, imagina o trabalho que seria para o servidor se o JPA trouxesse todos os 70,000 emails em anexo?
O JPA desenvolveu uma funcionalidade chamada de Lazy Loading para os atributos de uma classe. O Lazy Loading nada mais é do que, a informação desejada só será trazida do banco de dados quando ela for acessada.
É exatamente no momento da solicitação de acesso a uma coleção lazy que o erro acontece. O JPA/Hibernate tenta acessar o banco de dados para buscar a informação que foi definida como Lazy, mas a conexão foi fechada. Por isso que a exceção acontece, pela falta de uma conexão aberta.

Fonte: http://uaihebert.com/quatro-solucoes-para-lazyinitializationexception/3/


Acima segue, meu código com o SelectManyCheckbox, com todas as suas propriedades, criei um converter para que possa converter os objetos da minha lista, em objetos do componente. E até ai, tudo certo, carregava a lista e na hora de alterar, e persistir vinha o bendito erro, o Hibernate.
Depois de tanto procurar, achei no fórum do Primefaces, que é preciso informar a <f:attribute> e informar o tipo da lista que será enviado, foi até questionado se isso seria uma falha do Primefaces, ou do Hibernate, houve até uma discussão no fórum dizendo que não seria um problema do Primefaces, vendo que o mesmo não acontece quando utilizado sem o Hibernate.

Abaixo, segue o converter, pra quem quiser dar uma olhada.


E a forma como resolver o problema, com a propriedade <f:attribute>



Referências:

http://uaihebert.com/quatro-solucoes-para-lazyinitializationexception/

http://forum.primefaces.org/viewtopic.php?f=3&t=40551&p=128049&hilit=selectManyCheckbox+hibernate#p128049