[RESOLVIDO]Combo estado/cidade vraptor

Bem, estou procurando moh tempão como efetuar colocar um combo entre estado e cidade e de acordo com o estado, listar todas as cidades, tenho o metodo que chama todas as cidades passando o id do estado, já está funcionando direitim, mais nao sei fazer isso com jsp, infelizmente ainda venho de uma dependencia de JSF ;/ e queria saber se algum de vcs sabem como implementar isso com vraptor. basicamente estou querendo fazer o seguinte:

<select id="estadosSelect" name="pessoa.perfil.estado">
   <option>Selecione</option>
   <c:forEach items="${estados}" var="estado">
      <option value="${estado}">${estado.nome}</option>
   </c:forEach>
</select>

<select id="cidadesSelect" name="pessoa.perfil.estado.cidade">
   <option>Selecione</option>
   <c:forEach items="${cidades}" var="cidade">
      <option value="${cidade}">${cidade.nome}</option>
   </c:forEach>
</select>

de forma que ao passar o estado acima ele carregasse as cidades abaixo. mais nao faço a minima ideia de como fazer. e a maioria dos links que vi o pessoal dizendo onde tinha o material, os links estão off.

essa é um dos problemas que enfrento por ainda nao migrar totalmente para o vraptor.

Fala cara,

eu também venho do JSF e realmente, ele facilita muito quando a gente trabalha com ajax e view em geral…
Mas peca muito no desempenho… Bom sobre o que vc quer fazer, eu acabei de ver um tópico legal
sobre isso… Foge do que você quer fazer, mas talvez te ajude:

vou olhar d34d, toda ajuda é bem vinda, é pq infelizmente estou tendo que entender Java Script, e tenho muito problemas em entender como o JS pega determinados valores. mais vou olhar sim e continuar olhando essa thread aqui para ver novas respostas.

Você precisa fazer isso com jQuery e ajax:
1: Inicalizar a combo de cidades vazia.

&lt;select id="cidadesSelect" name="pessoa.perfil.estado.cidade"&gt;
&lt;/select&gt;

2: Arrumar a combo de estados

&lt;select id="estadosSelect" name="pessoa.perfil.estado"&gt;  
   &lt;option&gt;Selecione&lt;/option&gt;  
   &lt;c:forEach items="${estados}" var="estado"&gt;  
      &lt;option value="${estado.id}"&gt;${estado.nome}&lt;/option&gt;  &lt;!-- // o value tem que ser o ID do estado... --&gt;
   &lt;/c:forEach&gt;  
&lt;/select&gt;

3: No quando a combo de estados mudar, deve fazer uma busca ajax para pegar os options da cidade.

$(document).ready(function(){
   $('#estadosSelect').on('change', function(){
      var self = $(this);
      var selecionado = self.val(); // pega o ID do estado
      $.ajax({
         url:'/url/para/a/action',
         data:{estado:selecionado}, // Passa a variável ao server. O nome do parâmetro tem que ser estado, pois foi o nome colocado aqui.
         dataType:'json', // O Server vai retornar um JSON
         success:function(data){
            // Precisa transformar de json para objeto html
            var options = [];
            options.push(' &lt;option&gt;Selecione&lt;/option&gt; '); // colocando a primeira option...
            for (var i = 0; i &lt; data.length; i++) {
               options.push('&lt;option value="'+data[i].id+'"&gt;'+data[i].nome+'&lt;/option&gt;');
            }
            
            // Agora precisa juntar esses options dentro da combo de cidades
            $('#cidadesSelect').html(options.join(''));
         },
         error:function(){
            alert('erro');
         }
      });
   });
});

4: Criar a sua action que vai retornar um JSON com as cidades.

@Get("/url/para/a/action")
public void getCidades(Long estado) {
   List&lt;Cidade&gt; cidades = cidadeDao.getPorEstado(estado); // Carrega as cidades que estão nesse estado...
   result.use(Results.json()).withoutRoot().from(cidades).serialize(); // Transforma a lista em JSON
}

Perfect!
x]

Acho que da pra colocar '[Resolvido]'
no tópico ein ?

Boa Guerreiro !
x]

Antes de mais nada quero agradeçer pela ajuda de vcs, rapida e muito didática.

Rafael Guerreiro vou testar essa aplicação agora a noite, pq ja peguei outro modulo aqui, ai volto aqui para te responder. mais ficou bem detalhado dessa forma, axo que vai dar tudo certo

mas antes de tudo me tira uma duvida:

data:{estado:selecionado}, // Passa a variável ao server. O nome do parâmetro tem que ser estado, pois foi o nome colocado aqui.

esse estado, ele veio de onde? do ${estado} ?

esse: get

@Get("/url/para/a/action")  
public void getCidades(Long estado) { 
...
//

precisa ser …/a/action.json") ? ou dessa forma acima mesmo?

Tem que entender o padrão de objetos do Javascript. Funciona assim:

var objeto = { atributo1 : 'valor 1', atributo2 : 123 };
Ou seja, isso:

{estado:selecionado}

é um objeto aonde o valor do atributo “estado” está na variável “selecionado”, que foi setada acima.
Repare na linha 4 do segundo passo, onde a gente arrumou a EL para pegar o ID do estado e não o toString de estado…

Quanto à segunda pergunta, o path do get não precisa, NESSE CASO, terminar com .json (fica ao seu critério)…

outra coisa: quando vc faz o:

var self = $(this); 

o que vc está pegando com a variavel self ?

esse: data:{estado:selecionado}, //aqui tem que ser estado pq no getCIdades tbm é a variavel estado, é isso?

é pq tem public void getCidades(Long estado) // tem que ser esse mesmo nome aqui é?

Quando vc faz um evento dessa forma:

O jQuery coloca um valor na variável “this” (sim, this é uma variável no javascript). O valor é justamente o elemento que desencadeou essa ação.

Quando eu faço $(this), eu quero que o jQuery me retorne uma instancia jQuery desse elemento. Para isso, ele procura esse elemento no DOM da sua página e retorna a instancia.

Para que o jQuery não fique procurando o elemento no DOM toda vez que eu precisar ver alguma coisa nesse elemento, eu mando ele jogar nessa variável e ele só busca uma vez. Ficando mais rápido e menos custoso para o browser.

[quote=maaarkin]
esse: data:{estado:selecionado}, //aqui tem que ser estado pq no getCIdades tbm é a variavel estado, é isso?

é pq tem public void getCidades(Long estado) // tem que ser esse mesmo nome aqui é?[/quote]

Exatamente!

Ok, mais tarde vou testar teu codigo direitim e com calma, pq alem de utilizar o codigo quero estudar e entender como funciona.

[quote=Rafael Guerreiro]Quando vc faz um evento dessa forma:

O jQuery coloca um valor na variável “this” (sim, this é uma variável no javascript). O valor é justamente o elemento que desencadeou essa ação.

Quando eu faço $(this), eu quero que o jQuery me retorne uma instancia jQuery desse elemento. Para isso, ele procura esse elemento no DOM da sua página e retorna a instancia.

Para que o jQuery não fique procurando o elemento no DOM toda vez que eu precisar ver alguma coisa nesse elemento, eu mando ele jogar nessa variável e ele só busca uma vez. Ficando mais rápido e menos custoso para o browser.[/quote]

Nesse caso aqui, esse this, é o OBJETO estado, ou nao?

Concordo com você! E vou te explicar tudo que eu conseguir…

[quote=maaarkin][quote=Rafael Guerreiro]Quando vc faz um evento dessa forma:

O jQuery coloca um valor na variável “this” (sim, this é uma variável no javascript). O valor é justamente o elemento que desencadeou essa ação.

Quando eu faço $(this), eu quero que o jQuery me retorne uma instancia jQuery desse elemento. Para isso, ele procura esse elemento no DOM da sua página e retorna a instancia.

Para que o jQuery não fique procurando o elemento no DOM toda vez que eu precisar ver alguma coisa nesse elemento, eu mando ele jogar nessa variável e ele só busca uma vez. Ficando mais rápido e menos custoso para o browser.[/quote]

Nesse caso aqui, esse this, é o OBJETO estado, ou nao?[/quote]
Não confunda OBJETO com ELEMENTO… Quando vc faz ‘${estado}’ você está acessando o toString da instância (no Java), ou seja, o tomcat vai lá e procura alguma variável que se chame “estado” e aciona o toString dele. Quando a página é renderizada pelo browser o tomcat não tem mais ação nenhuma, tudo foi transformado em String.

O Javascript não tem acesso aos seus objetos, por isso ele trata tudo como string… Então, o this, é o ELEMENTO do select… Se vc usa o chrome e mandar ele imprimir o elemento assim:

console.log(this); Você vai ver que ele vai te mostrar o ELEMENTO select inteiro (inclusive os filhos, que são os options)…

bem, listando está, mais está caindo no error.

vou colocar como adaptei o metodo para esse exemplo Rafael.

Pagina:

<%@ page contentType="text/html; charset=UTF-8" %>

<script>
$(document).ready(function(){  
	   $('#estadosSelect').on('change', function(){  
	      var self = $(this);  
	      var selecionado = self.val(); // pega o ID do estado  
	      $.ajax({  
	         url:'/visitante/carregaCidades/',  
	         data:{estado:selecionado}, // Passa a variável ao server. O nome do parâmetro tem que ser estado, pois foi o nome colocado aqui.  
	         dataType:'json', // O Server vai retornar um JSON  
	         success:function(data){  
	            // Precisa transformar de json para objeto html  
	            var options = [];  
	            options.push(' <option>Selecione</option> '); // colocando a primeira option...  
	            for (var i = 0; i < data.length; i++) {  
	               options.push('<option value="'+data[i].codigo+'">'+data[i].nome+'</option>');  
	            }  
	              
	            // Agora precisa juntar esses options dentro da combo de cidades  
	            $('#cidadesSelect').html(options.join(''));  
	         },  
	         error:function(){  
	            alert('erro');  
	         }  
	      });  
	   });  
	}); 
</script>

<div>
<form action="salvar" method="post">
   <fieldset>
     <legend>Adicionar Visitante</legend>
     
     <label for="nome">Rua:</label>
     <input id="nome" type="text" placeholder="nome" name="visitante.nome"/>
     
     <label for="rua">Rua:</label>
     <input id="rua" type="text" placeholder="rua" name="visitante.endereco.logradouro"/>
     
     <label for="descricao">estado:</label>
     <select id="estadosSelect" name="visitante.endereco.cidade.estado">  
	   <option>Selecione</option>  
	   <c:forEach items="${estadoList}" var="estado">  
	      <option value="${estado.codigo}">${estado.sigla}</option>  
	   </c:forEach>  
	 </select>
     
     <select id="cidadesSelect" name="visitante.endereco.cidade">  
	 
	 </select> 
     
     <br/>
     <button type="submit" class="btn">Salvar</button>
   </fieldset>
 </form>
</div>

meu controllador:

	@Get("/visitante/carregaCidades/{codigo}")  
	public void carregaCidades(Long estado) {  
	   List<Cidade> cidades = this.cidadeRep.findCitiesFromState(estado); // Carrega as cidades que estão nesse estado...  
	   result.use(Results.json()).withoutRoot().from(cidades).serialize(); // Transforma a lista em JSON  
	} 

estava analisando o codigo e no metodo nao é pra ser @Post nao?

@Get("/visitante/carregaCidades/{codigo}")Você está esperando uma variável “codigo” na sua URL…

Ou seja, a url ‘/visitante/carregaCidades/’ não existe. Por isso está errado. Existem 2 saidas:

  1. Mudar o nome da variável para estado e passar o valor na url:
// ...
$.ajax({    
             url:'/visitante/carregaCidades/' + selecionado,     // COLOQUEI O PARAMETRO AQUI.
             // data:{estado:selecionado}, // Remove essa linha
             dataType:'json',
//...

########### OU ###########

  1. Remove a variável na url e deixe TUDO como está.

vou testar aqui agora.

testei das duas formas e não deu veja como ficou da forma que testei agora:

<script>
$(document).ready(function(){  
	   $('#estadosSelect').on('change', function(){  
	      var self = $(this);  
	      var selecionado = self.val(); // pega o ID do estado  
	      $.ajax({  
	    	  url:'/visitante/carregaCidades/' + selecionado,  
	         //data:{estado:selecionado}, // Passa a variável ao server. O nome do parâmetro tem que ser estado, pois foi o nome colocado aqui.  
	         dataType:'json', // O Server vai retornar um JSON  
	         success:function(data){  
	            // Precisa transformar de json para objeto html  
	            var options = [];  
	            options.push(' <option>Selecione</option> '); // colocando a primeira option...  
	            for (var i = 0; i < data.length; i++) {  
	               options.push('<option value="'+data[i].codigo+'">'+data[i].nome+'</option>');  
	            }  
	              
	            // Agora precisa juntar esses options dentro da combo de cidades  
	            $('#cidadesSelect').html(options.join(''));  
	         },  
	         error:function(){  
	            alert('erro');  
	         }  
	      });  
	   });  
	}); 
</script>
@Get("/visitante/carregaCidades/{estado}")  
	public void carregaCidades(Long estado) {  
	   List<Cidade> cidades = this.cidadeRep.findCitiesFromState(estado); // Carrega as cidades que estão nesse estado...  
	   result.use(Results.json()).withoutRoot().from(cidades).serialize(); // Transforma a lista em JSON  
	} 

será que é porque estou usando Long?

Certo, vc testou, mas vc debugou? Descobriu o que está acontecendo?

Tente achar uma solução, caso não consiga, venha perguntar aqui.