hfdwrsimbolo.jpg


DWR – Directed Web Remoting

 

Combos Aninhadas

 

Primeiramente quero agradecer aos leitores por todos os comentários, e-mails de agradecimentos e críticas que tenho recebido. Obrigado a todos.

 

Tenho recebido vários e-mails de usuários com elogios, críticas e dúvidas e com esse grande número de leitores venho recebendo algo em comum, muitos tem dúvidas e/ou querem saber como fazer combos aninhadas, vendo essa demanda resolvi fazer algo por esses leitores que tanto me prestigiam. Então esse artigo irá abordar o que muitos me perguntam:

 

-Como fazer combos aninhadas com o DWR ?

 

PS1: Vamos utilizar nomes de funções, métodos, parâmetros e variáveis em inglês, pois esse artigo será também utilizado para a vídeo aula da Java Magazine e para a mesma, esse padrão em inglês tem que ser seguido.

 

Preparando o ambiente e ferramentas

Vamos criar um projeto java e web, utilizar o banco de dados MySql para nossos dados.

 

Segue abaixo o nosso ambiente:

 

IDE: MyEclipse 5.1.1GA

ContainerWeb: Tomcat 5.5.17

DWR: Versão 2.0.1

Banco de Dados: MySql Server 5.0.24, MySql Client 5.0.11

JAVA: JKD5.0 ou superior.

 

Criando o banco

Para criar o banco que iremos utilizar basta executar o sql que esta para download aqui: sqlDownload.(Recomendo que rode pelo MySQL Administrator, e o mesmo está dentro do projeto na pasta “bd”)

 

Informações do banco de dados

Banco: bddwrjm

Tabelas: users, permissions, user_permissions, characteristics

 

hfdwrcafig01.jpg 

 

Estrutura do projeto

Para você não perder tempo tentando entender da camada de Negócio para baixo, vou explicar agora rapidamente, como está nossa estrutura para podermos partir para o que realmente interessa.

 

Quando você rodar seu Dump(arquivo sql, aconselho a usar o MySQL Administrator) talvez você precise configurar um arquivo para que a sua classe de conexão consiga acessar o seu banco. O arquivo você deve atualizar é a classe ConnectDAO, localizado em: com.jm.dao.

 

Explicando a estrutura

A nossa estrutura esta dividida em:

·         Classe de Negócio(NgcBusinessGeneral): Esta será a classe que vai fazer as chamadas aos seus DAO’s e executar alguma regra de negócio.

·         Classe de acesso ao banco(ConnectDAO): Classe que se conectar ao banco.

·         Classes de Persistência(UsersDAO, PermissionsDAO): Classes responsáveis por executar os sql no banco.

·         Classe de controler do DWR(FacadeAjax) : Essa será a classe que vai se comunicar com sua classe de negócio e retornar para o seu javascript.

·         Página de exibição dos exemplos(combo.jsp): Página JSP para exibir os resultados.

·         JavaScript de exemplos(combos.js): JavaScript com os as chamadas DWR.

 

Com essas informações já podemos dar início ao nosso exemplo, não se prenda nas funcionalidades e como foram implementadas, vamos abstrair isso, vamos observar apenas como o DWR vai trabalhar, ou seja, vamos observar o nosso FacadeAjax e JS’s, pois da camada de negócio para baixo pode ser implementada da forma que você desejar ou que já esta implementada. Você vai observar também que vamos trabalhar muito com beans e List(java.util.List), então se o seu sistema já trabalha com esses tipos de objetos você verá que será bem tranqüilo, mas não que dizer se você usa Map’s(java.util.Map) ele não irá funcionar, o DWR trabalha com praticamente todos os principais tipos do Java.

 

No nosso exemplo eu já deixei montado uma grid com todos os usuários cadastrados, para que você observe os resultados dos exemplos.

 

Iniciando os Exemplos

 

Exemplo 1. Carregando uma combo a partir de uma outra combo.

 

Esse é o mais simples, você terá uma combo que vai possuir alguns valores, ao selecionar um desses valores ele vai passar para o FacadeAjax através de uma função chamada selectPermissiosUsers(this.value); e o mesmo vai enviar a chamada para a classe de negócio que vai ao banco, executa o select e é retornado o resultado solicitado para ser populada a segunda combo. Veja abaixo.

 

HTML

Example 1:

Users: <select id="comboUsers" onchange="selectPermissiosUsers(this.value);">

</select>

Permissions: <select id="comboPermissionsUsers"></select>

Listagem 01 – HTML cujo foi definido uma tag <select> com id igual a “comboUsers”, e abaixo um segundo <select> com id igual a “comboPermissionsUsers” onde será carregado o resultado baseado no id do usuário carregado na primeira combo(“comboUsers”).

 

Javascript

function selectPermissiosUsers(idValue){

        var bean = {id:idValue};

       

        FacadeAjax.getPermissionsUsers(bean,{

               callback:function(list){

                                                               DWRUtil.removeAllOptions("comboPermissionsUsers");

DWRUtil.addOptions("comboPermissionsUsers", list,"id_permission", "permission");

               },

errorHandler:function(errorString, exception) {

               setMsgError(errorString, 'block');

},

               timeout:50000

        });            

}

Listagem 02 – Chamada do DWR para recuperar uma lista de permissões através de um usuário selecionado em uma combo. Utilizando o addOptions() ele gera uma combo com os valores trazidos do banco.

 

JAVA(FacadeAjax)

public List<BeanPermissions> getPermissionsUsers(BeanUsers beanUsuario) throws Throwable{

              

List<BeanPermissions> listPermissionsUsers = BusinessGeneral.getInstancia().getPermissionsUsers(beanUsuario);

              

        return listPermissionsUsers;

}

 

Listagem 03 – Método da classe FacadeAjax que retorna um List de Beans do tipo BeanPermissions.

 

Resultado da execução do Exemplo 1:

 

hfdwrcafig02.jpg 

Figura 01 – As duas combos, uma já carregada com uma lista de usuários e a outra aguardando ser carregada as permissões deste usuário.

 

hfdwrcafig03.jpg 

Figura 02 – Selecionando um usuário para carregar as suas permissões na próxima combo. O resultado da segunda combo são todas as permissões daquele usuário.

 

hfdwrcafig04.jpg 

Figura 03 – Combo de permissões carregada com as permissões do usuário selecionado.

 

Exemplo 2. Carregando duas combos e uma grid.

 

Esse exemplo é um pouco mais complexo, desta vez vamos ter o mesmo cenário do primeiro exemplo, uma combo cujos valores são carregados no load da página, e que ao selecionar um valor desta, ela carrega a segunda combo através da função selectPermissiosUsers2(this.value); que é igual a função selectPermissiosUsers(this.value); só alterando o id passado nas funções removeAllOptions() e addOptions().

 

Mas desta vez vamos ao selecionar algum dado da segunda combo(“comboPermissionsUsers2”) carregar um grid.

 

HTML

Example 2:

Users: <select id="comboUsers2" onchange="selectPermissiosUsers2

(this.value);"></select>

    Permissions: <select id="comboPermissionsUsers2"

 onchange="getListAllUsersPermissions(this.value);"></select>

    <br><br>

<table id="tableUser" border="0" align="left" cellpadding="4" cellspacing="0"

 style="border: 1px solid black; display: none">

   <thead>

     <tr style="background-color: white;">

         <td colspan="4" style="color: black; font-weight: bold;"

 align="center">Permissions for Users</td>

     </tr>

     <tr style="background-color: gray;">

         <td style="color: white; font-weight: bold">Id</td>

         <td style="color: white; font-weight: bold">Name</td>

         <td style="color: white; font-weight: bold">Login</td>

         <td style="color: white; font-weight: bold">Permissions</td>

       </tr>

   </thead>

   <tbody id="tbodyUsers2"></tbody>

</table>

Listagem 04 – HTML muito parecido com o da Listagem 01, mais que seu id foi alterado com outro valor, e abaixo das tags <select> temos uma tabela que esta escondida(style="border:

 1px solid black; display: none">) onde será carregado um grid com os dados gerados a partir do valor da segunda combo(comboPermissionsUsers2). Esses dados serão carregados na tag <tbody>(“ tbodyUsers2”) com a função addRows().

 

Javascript

function selectPermissiosUsers2(idValue){

        var bean = {id:idValue};

        FacadeAjax.getPermissionsUsers(bean,{

               callback:function(list){

                   DWRUtil.removeAllOptions("comboPermissionsUsers2");

DWRUtil.addOptions("comboPermissionsUsers2",list,"id_permission",   "permission");

               },

               errorHandler:function(errorString, exception) {setMsgError(errorString, 'block');},

               timeout:50000

               ,async:false

        });    

}

Listagem 05 – Chamada para o método getPermissionsUsers que carrega as permissões do usuário selecionado.

 

function getListAllUsersPermissions(valueId){

       

        var bean = {id_permission:valueId};  

       

        FacadeAjax.getAllUserPermissions(bean,{

               callback:function(list){

  var table = document.getElementById("tableUser");

                 table.style.display = "block";

                              

                 DWRUtil.removeAllRows("tbodyUsers2");

                 limparTBody();

                              

                 var cellFuncs = [

                       function(bean) { return bean.id; },

                       function(bean) { return bean.name; },

                       function(bean) { return bean.login; },

                       function(bean) { var resultado = "<ol id='olListCombo" +

                                        bean.id + "'></ol>";

                       setTimeout(function(){

DWRUtil.removeAllOptions("olListCombo" + bean.id);

DWRUtil.addOptions("olListCombo" + bean.id, bean.listPermissions, "permission");

},200);

                       return resultado;

                 }

 ];

                              

DWRUtil.addRows("tbodyUsers2", list, cellFuncs,{escapeHtml:false});

                              

               },

errorHandler:function(errorString, exception)

{

setMsgError(errorString, 'block');

},

               timeout:50000

               ,async:false

        });

}

Listagem 06 – Função getListAllUsersPermissions que é chamada ao selecionar um tipo de permissão na combo de permissões(“comboPermissionsUsers2”), acessa o método da classe FacadeAjax.getAllUserPermissions() retornando um List de beans do tipo BeanUsers. Com o seu retorno ela adiciona esse List na tabela utilizando o addRows().

 

JAVA(FacadeAjax)

public List<BeanUsers> getAllUserPermissions(BeanPermissions

beanPermission) throws Throwable {

              

List<BeanUsers> listUsers =

BusinessGeneral.getInstancia().getAllUserPermissions(beanPermission);

              

return listUsers;

}

Listagem 07 – Método da classe FacadeAjax que retornar um List de BeanUsers com uma lista de usuários que possuem aquela permissão selecionada.

 

Resultado da execução do Exemplo 2:

 

hfdwrcafig05.jpg 

Figura 04 – As duas combos, uma já carregada com uma lista de usuários e a outra aguardando ser carregada as permissões deste usuário.

 

hfdwrcafig06.jpg 

Figura 05 – Selecionando um usuário para carregar as suas permissões na próxima combo. O resultado da segunda combo são todas as permissões daquele usuário.

 

hfdwrcafig07.jpg 

Figura 06 – Selecionando um tipo de permissão para executar um select no banco e retornar todos os usuários que possuem aquele tipo de permissão.

 

hfdwrcafig08.jpg 

Figura 07 – Resultado do select que retornar uma lista de usuários que possuem a permissão selecionada em comum.

 

Exemplo 3. Preenchendo um formulário a partir de um valor de uma combo.

 

Acho que esse é o exemplo mais clássico mais mesmo assim resolvi fazê-lo.

 

Temos um formulário que está vazio, e queremos a partir de um determinado dado de uma combo, preencher esse formulário.

 

HTML

Exemplo 3:

Users: <select id="comboUsers3" onchange="javascript:getUserTable(this.value);"></select>

<br>

<form id="form" name="form" action="">

<table border="1">

   <thead>

        <tr>

                <td colspan="3">Table User</td>

        </tr>

   </thead>

   <tbody>

        <tr>

               <td>ID</td>

               <td><input type="text" id="id"/></td>

        </tr>

        <tr>

               <td>Nome</td>

               <td><input type="text" id="name"/></td>

        </tr>

        <tr>

               <td>Login</td>

               <td><input type="text" id="login"/></td>

        </tr>

        <tr>

               <td>Password</td>

               <td><input type="text" id="pass"/></td>

        </tr>

   </tbody>

</table>    

</form>

Listagem 08 – HTML que possui um <select> onde será carregado os usuários da mesma forma como nos outros exemplos.

 

Abaixo do <select> temos um form e uma tabela neste form, com os id’s dos inputs tendo o mesmo nome das propriedades do BeanUsers.

 

Javascript

function getUserTable(idUsers){

        var bean = {id:idUsers};

       

        FacadeAjax.getUsers(bean, {

               callback:function(bean){

                       DWRUtil.setValues(bean);

               },

               errorHandler:function() {

setMsgError(errorString, 'block');

},

               timeout:5000,

        });

}

Listagem 09 – Ao selecionar a combo(“comboUsers3”) a mesma dispara a chamada para a função do javascript(“getUserTable(this.value)”) que irá fazer a chamada para o método da classe FacadeAjax chamado “getUsers()” que espera como parâmetro um bean do tipo BeanUsers, e retornar um BeanUsers com o valor do usuário selecionado na combo(“comboUsers3”) para ser preenchido no formulário.

 

JAVA(FacadeAjax)

public BeanUsers getUsers(BeanUsers beanUsers) throws Throwable {

              

List<BeanUsers> listUsers = BusinessGeneral.getInstancia().getUsers(beanUsers);

              

        return listUsers.get(0);

}

Listagem 10 – Método da classe FacadeAjax que retorna um BeanUsers.

 

Resultado da execução do Exemplo 3:

 

hfdwrcafig09.jpg 

Figura 08 – Combo carregada com os usuários do banco, e o formulário em branco.

 

hfdwrcafig10.jpg 

Figura 09 – Selecionando o usuário que terá seus dados carregados no formulário.

 

hfdwrcafig11.jpg 

Figura 10 – Formulário sendo preenchido com os dados do usuário selecionado.

 

Conclusão

Com esses exemplos podemos verificar a facilidade com o que podemos não só carregar combos a partir de outras, mas também podemos ter várias ações a partir de uma primeira, utilizando as funções aninhadas, além de ficar bem mais simples esse trabalho podemos tratar com facilidade o retorno, erros, erro por tempo(timeout) e decidirmos se a sua chamada javascript vai ser assíncrona ou síncrona.

 

Espero que este artigo tenha ajudado ao entendimento de chamadas dependentes e claro, no entendimento de combos aninhadas.

 

Existem várias outras funções no nosso exemplo, que podem ser vistas no projeto que esta para download logo mais abaixo.

 

Todas as funções javascript e métodos java estão comentadas para melhor entendimento no JavaDoc da aplicação que está localizado dentro do projeto.

 

Baixar projeto aqui.

 

Obrigado e Boa Sorte.

 

Handerson Frota

handersonbf@gmail.com

www.handersonfrota.com.br

Leia também