[Resolvido] Melhor solução para listas dependentes

Galeria, é o seguinte:

Tenho um formulário com algumas listas, input etc, estes são enviados pelo controller da seguinte forma:

@Restrito
	@Get("/novo")
	public void novoChamado(){
		result.include("produtoList", produtoDAO.listaAtivos());
		result.include("tipoSolicitanteList", tiposolicitanteDAO.listaAtivos());
		result.include("motivoList", motivoDAO.listaAtivos());
		result.include("ocorrenciaList", ocorrenciaDAO.listaAtivos());
		result.include("clientesList", clientesDAO.listaAtivos());
		result.include("centroCustoClienteList", centroCustoClienteDAO.listaAtivos());
	}

OK, as listas são carregadas e populadas corretamente, mas há duas que são totalmente ligadas.

Uma é de Clientes e a próxima é do Centro de Custo do cliente, em uma relação de 1 para N.

Ai vem a dúvida, qual seria a melhor alternativa para que até que se selecione o cliente a lista de centro de custo fique desabilitada e só então seja populada apenas com os respectivos centros de custo deste cliente?

Vi alguns exemplos utilizando JSON , jQuery e Ajax, mas em sua grande maioria há apenas dois campos sendo retornados pelo controller.

Ajax é, sem dúvidas, a melhor forma de fazer isso. A não ser que essas listas sejam extremamente pequenas.

Assim vc não precisa incluir a lista de centros toda.

Use o ajax do jQuery…

Algo assim:
no on change da combo (imagino que seja uma combo) de clientes, você faz um ajax que passa como parâmetro o ID do cliente selecionado e no retorno recebe a lista de centros.

Dai é só limpar a combo e adicionar a lista como um option mesmo.

Vlw Rafael,

Agora o problema é o select não popula, mas não achei onde estou errando, segue abaixo o que estou usando:

Controller:

@Restrito
	@Get
	@Path ("/novo/buscaCentroCusto.json")
	public void carregaCentroCusto(Long cliente){
		List<CentroCustoCliente> centrocusto = centroCustoClienteDAO.listaCentroCustoCliente(cliente);
		result.use(Results.json()).withoutRoot().from(centrocusto)
		.serialize();
	}

DAO:

public List<CentroCustoCliente> listaCentroCustoCliente(Long fkidCliente){
		return this.session.createCriteria(CentroCustoCliente.class) 
	    		.add(Restrictions.eq("FKidCliente", fkidCliente))
	    		.add(Restrictions.eq("Ativo", Boolean.TRUE))
	    		.addOrder(Order.asc("NomeCentroCusto"))
	    		.list();
	}

e a View:


<select id="clienteDropdown">
		    	<option value="">Selecione o Cliente...</option>
			    	<c:forEach items="${clientesList}" var="cliente" >
			    		<option value="${cliente.IDCliente}">${cliente.nomeCliente}</option>
			    	</c:forEach>
		   		</select>

<!-- Tags da table e divs-->

   	<select id="centrocustoDropdown" disabled="disabled">
				</select>	
				<img id="loading" alt="Carregando" src="<c:url value="/imagens/Load.gif"/>"/>
		<script>
			 $(function(){
		$('#loading').hide();
		$('#clienteDropdown').change(function(){
			adjustCentroCusto();
		}).change();
			$('#loading').ajaxStart(function() {
				$(this).show();
			});
			$('#loading').ajaxStop(function(){
				$(this).hide();
			});
  		});
  				
  		function adjustCentroCusto() {
			var clienteValue = $('#clienteDropdown').val();
			var centrocustoSet = $('#centrocustoDropdown');
			if (clienteValue.length == 0)
			{
				centrocustoSet.attr("disabled", true);
				centrocustoSet.emptySelect();
			}
			else
			{
				centrocustoSet.attr("disabled", false);
				$.getJSON('/novo/buscaCentroCusto.json', {
					cliente : clienteValue
				}, function(data) {
					centrocustoSet.loadSelect(data);
				});
			}
		}
  				
  				(function($) {
				  $.fn.emptySelect = function() {
				    return this.each(function(){
				      if (this.tagName=='SELECT') this.options.length = 0;
				    });
				  }
				
				  $.fn.loadSelect = function(data) {
				    return this.emptySelect().each(function(){
				      if (this.tagName=='SELECT') {
				        var selectElement = this;
				
				        $.each(data,function(index,optionData){
				
				        var option = new Option(optionData.IDCentroCusto, optionData.CentroCusto +' - '+ optionData.nomeCentroCusto);
				        
				          if ($.browser.msie) {
				            selectElement.add(option);
				          }
				          else {
				            selectElement.add(option,null);
				          }
				        });
				      }
				    });
				  }
				})(jQuery);

O estranho é que o no evento change no clienteDropdown, ao lado do select centrocustoDropdown deveria mostrar o gif de loading enquanto o ajax estivesse rodando, mas o mesmo nem é apresentado, apesar do select abaixo deixar de ficar desabilitado e ficar ativo apesar de estar vazio.

Alguém sabe o que pode ser ?

Galera,

Acho que sei o pq não popula, mas não sei como resolver.

Usando o console na hora da chamada do json, retorna status 404:

Tem um r, está chamando buscaCentroCustro e é buscaCentroCusto

Foi mal ae, eu que digitei errado na resposta. Mas o erro está acontecendo com o “buscaCentroCusto.json” mesmo

roda a url do JSON no browser mesmo, vê o que retorna, olha o console, vê o que o vraptor está te falando.

o @Path tem esse .json no final?

Lucas,

Ajustei 3 coisas que estavam erradas pelo visto:

1º - .json no Path, mudei de @Get @Path("/buscaCentroCusto.json")
Para: @Get("/buscaCentroCusto")

2º - No get do JSON o path informado não chamava o Controller o qual o mesmo está, segue abaixo como era e como ficou:
Antes $.getJSON('<c:url value="/buscaCentroCusto"/>'
Depois $.getJSON('<c:url value="/infoChamados/buscaCentroCusto"/>'

3º - (conforme o Rafael tinha falado)Chamei a url do json no browser passando um parametro, (Chamada: http://localhost:8080/SRP/infoChamados/buscaCentroCusto?cliente=200) então vi que o mesmo estava esperando um parâmetro do tipo Long, enquanto eu mandava um do tipo Integer .

Blz todos os problemas acimas foram ajustados, pelo console o retorno do json é o seguinte(para a mesma chamada que tinha retornado erro):

[{"IDCentroCusto": 449,"CentroCusto": "1.1.169.01.01","NomeCentroCusto": "AtendeSimples_VOS Center","FKidCliente": 200,"CodExterno": 797,"Ativo": true}]

Mas então o select não popula.

o fato do select não popular agora é questão de ajustar o javascript que faz isso

Bom Galera, Vlw pelas respostas

Consegui achar o porque de não popular.

No Script que retorna os options populados inseri um if para validar o browser utilizado, conforme abaixo:

if ($.browser.msie){
				selectElement.add(option);
			}
			else 
			{
				selectElement.add(option,null);
			}

Mas a partir da versão 1.9 do jQuery (a qual eu uso) foi descontinuado essa propriedade (http://api.jquery.com/jQuery.browser/) enfim … deixei da seguinte forma:

 selectElement.add(option);

Agora popula corretamente.