[Resolvido,Vraptor] Problema com combobox aninhado

Olá estou aprendendo a usar o vraptor e estou fazendo um projetinho para aprender…

Bom estou com o seguinte problema:

Eu tenho um no meu html que é suprido por uma ${atividadeList } vindo do servidor

agora eu preciso que o outro ${subAtividadeList } seja alimentado quando uma atividade for selecionada.

Não tenho muitos conhecimentos avançados em javascript e ajax por isso estou pedindo ajuda.

não sei nada de Json

obrigado :slight_smile:

Acho que DWR resolve o seu problema, nao sei muita coisa sobre isso, mas ja fiz manutencao em metodos que usam isso, e funciona exatamente como voce quer.

A melhor forma de fazer isso é com JavaScript mesmo.

Você tem jQuery nesse seu projeto? Ele vai ajudar bastante.

Vamos fazer com um exemplo básico: Estado e Cidades.

Primeiramente, devemos carregar todos os estados:

<select id="estado" name="estado">
	<c:forEach items="${estadoList}" var="e">
		<option value="${e.uf}">${e.name}</option>
	</c:forEach>
</select>
<select id="cidade" name="cidade">
</select>
<!--// coloca a url onde vamos buscar as cidades em uma variável aqui -->
<script>
	var urlCidades = '<c:url value="/ajax/cidades/" />';
</script>

Depois, precisamos dizer ao jQuery que queremos buscar as cidades quando a combobox de estado sofrer alterações:
Coloque o JavaScript sempre em um arquivo separado.

$('#estado').on('change', function(){
	var ufSelecionada = $(this).val();
	$.ajax({
		url: urlCidades,
		data: {uf:ufSelecionada},
		type : 'get',
		dataType: 'json',
		success : function(cidades) {
			$('#cidade').empty(); // Precisa limpar a combo antes.
			// no java vc faz cidades.get(0).getName() e cidades.get(0).getId(),
			// Com JSON vc vai fazer cidades[0].name e cidades[0].id
			for (var i = 0; i < cidades.length; i++){
				$('#cidade').append('<option value="' + cidades[i].id + '">' + cidades[i].name + '</option>');
			}
		}
	});
});

Depois, precisamos criar a action que vai carregar as cidades baseado no estado que foi selecionado:

@Get("/ajax/cidades/") // Mesma URL lá de cima.
public void carregaCidades (String uf){ // Variável está com o mesmo nome que a passada em data: {uf:ufSelecionada}
	List<Cidade> cidades = new ArrayList<Cidade>();
	// Carrega cidades baseada na uf selecionada...
	result.use(Results.json()).withoutRoot().from(cidades).serialize();
}

O JSON, nesse caso, tem esse formato:
[
{id: 1, name: ‘São Paulo’}
]

Espero ter ajudado, qualquer dúvida, é só perguntar.

Muito boa a solução!

Existem umas melhorias de performance. Mas são só algumas alterações. Desse jeito está bem cru…

apanhei um pouco aqui mas consegui muito obrigado :slight_smile:

apesar de que esse método me pareceu um pouco lento.

Então vamos melhorá-lo drasticamente:

$.ajax({
	url: urlCidades,
	data: {uf:ufSelecionada},
	type : 'get',
	dataType: 'json',
	success : function(cidades) {
		$('#cidade').empty(); // Precisa limpar a combo antes.

		// O método append é muito lento. O ideal seria executá-lo uma única vez.

		var options = [];
		for (var i = 0; i < cidades.length; i++){
			// Então colocamos todos os options dentro de um array.
			options.push('<option value="' + cidades[i].id + '">' + cidades[i].name + '</option>');
		}

		// E depois, unimos todos os options em uma única chamada ao método append:
		$('#cidade').append(options.join('')); // Esse parâmetro que é passado, é o delimitador de cada item do array. No caso, não queremos delimitadores.
	}
});

Dá para melhorar ainda mais:

$.ajax({
	url: urlCidades,
	data: {uf:ufSelecionada},
	type : 'get',
	dataType: 'json',
	success : function(cidades) {
		// o jQuery gasta um pouco de tempo para encontrar o elemento quando a gente faz essa busca, então seria legal se chamássemos o elemento uma vez só.
		// Para isso, precisamos carregar as options antes:

		var options = [];
		for (var i = 0; i < cidades.length; i++){
			options.push('<option value="' + cidades[i].id + '">' + cidades[i].name + '</option>');
		}

		// Aqui usamos um recurso bem legal do jQuery, ele retorna o próprio elemento em alguns métodos:
		$('#cidade').empty().append(options.join('')); // Assim, primeiro limpamos e depois adicionamos os options.
	}
});

Much better :smiley:

Vlw ai bro u own

Dá para melhorar ainda mais, heheheh:

$.ajax({
	url: urlCidades,
	data: {uf:ufSelecionada},
	type : 'get',
	dataType: 'json',
	success : function(cidades) {
		var options = [];
		for (var i = 0; i < cidades.length; i++){
			options.push('<option value="' + cidades[i].id + '">' + cidades[i].name + '</option>');
		}

		$('#cidade').html(options.join('')); // Com html, o jQuery já faz o empty e o append, mas de uma forma mais performática...
	}
});

Pessoal acho que vão poder me ajudar .

Tenho um formulário de atualização de imóveis, dentro dele existe um combobox que irá trazer todos os tipos de imóveis gravados no banco.
Mas o problema vem ai, ele não traz esses tipos.
Meu métodos em minha dao e controller estão corretos e funcionando perfeitamente, mas meu combo não.

<select id="tipoImovel" name="imovel.tipo"> <option>Selecione</option> <c:forEach items="${tipoImovelList}" var="tipo"> <option value="${tipo.id}">${tipo.tipo}</option> </c:forEach> </select>

DAO:

public List<TipoImovel> listar() { return sessao.createCriteria(TipoImovel.class).list(); }

Controller

public List<TipoImovel> listar(){ return dao.listar(); }

essa lista está vindo populada do banco?

isso deveria funcionar, mas tenta ao invés de retornar a lista no método, usar:

result.include("tiposImovel", dao.listar());

e usar esse nome no c:forEach

Também não da certo Lucas. Uma dúvida, no caso eu tenho que passar alguma uri para este método da minha controller ? Não seria necessário né ?

o jsp está com a taglib c declarada?

qdo vc abre o código fonte da página aparece o <c:forEach?

Declarada !

NÃO ! Quando faço a inspeção de elemento pelo chrome o <c:forEach não aparece, apenas o select e o option = selecione

Declarada !

NÃO ! Quando faço a inspeção de elemento pelo chrome o <c:forEach não aparece, apenas o select e o option = selecione

tem certeza que existem elementos nessa lista?

tentou imprimir ela num log ou algo do tipo?

Lucas resolvi o problema através do método include mesmo, acho que aquela hora que voce me mostrou devo ter colocado algo errado, trocado algum parametro por isso estava dando erro.

Obrigado pela ajuda !