Solucionado (ver solução)
Solucionado
(ver solução)
17
respostas

Combo Box dependente

Ola meus caros! Estou estudando SpringMVC e JPA e pesquisei como fazer uma combo populada com bd chamar uma outra combo relacionada a ela, por exemplo seleciono o pais na primeira combo e na segunda carrega as cidades. vi vários trechos de códigos na web com json, jquery, javascript, mas como estou iniciando nem web não compreendi muito, vocês poderiam me ajudar com algum exemplo? eu ja consegui listar elas separadas na view.

17 respostas

Oi Diego, você precisa recarregar a página toda vez que um país for selecionado, ex:

document.getElementById(" comboPais").onchange(function(element){
     document.location.href = "suaUrl?idPais="+element.id;
});

Com algo parecido com o trecho acima, você sempre vai recarregar a tela passando o id do país.. Com isso, no servidor, você pode carregar o país e suas cidades. Quando conseguir resolver desse jeito, você pode tentar dar uma fuçada e resolver com AJAX.

Diego para isso você pode estar utilizando o onchange do javascript junto com ``àjax```, vou lhe mostrar da forma que faço.

Primeiro tenho um método responsável por devolver um json de qualquer tabela do banco de dados:

@Get("json")
public void toJSON(T obj, List<ParametrosWeb> parametrosWeb) {
    List<T> list = getDao().findAll(obj.getClass(), parametrosWeb);
    this.result.use(Results.json()).from(list).serialize();
}

Feito isso tenho um javascript responsável o change de um select no caso os estados e de acordo com o estado popular o select das cidades:

jQuery('select[data-class=slCadEstado]').change(function() {
    var $select = jQuery('select[data-class=slCadCidade]').empty();
    jQuery.ajax({
        type: 'GET',
        url: pathRaiz + "/cadastro/cidade/json?parametrosWeb[0].campo=idestado.id&parametrosWeb[0].parametroInicial=" + jQuery(this).val() + "&parametrosWeb[0].orderBy=descricao&parametrosWeb[0].limit=1000",
        dataType: 'json',
        async: false,
        success: function(json) {
            jQuery.each(json.list, function(i, value) {
                var optionHTML = new Option(value.descricao, value.id);
                $select.append(optionHTML);
            });
        }
    });
});

Selects que receberam os dados via ajax:

<select class="form-data validate" data-class="slCadEstado" id="slCadastro_Estado_json_01" name="obj.endereco.idestado.id" required></select>
<select class="form-data ss validate" data-class="slCadCidade" id="slCadastro_Cidade_json_01" name="obj.endereco.idcidade.id" required></select>

Espero ter ajudado

Esse é o metodo da minha controller com as duas combos que estrou trazendo elas separadas

@RequestMapping(method = RequestMethod.GET) public ModelAndView listar() { List<Departamento> departamentos = departamentoDAO.listar(); List<Setor> setores = setorDAO.listar();

ModelAndView modelAndView = new ModelAndView("/departamento/lista"); modelAndView.addObject("departamentos", departamentos); modelAndView.addObject("setores", setores); return modelAndView;

Aqui é o DAO da classe departamento que popula uma das combos, classe pai

@Repository
@Transactional
public class DepartamentoDAO {

    @PersistenceContext
    private EntityManager manager;

    public List<Departamento> listar() {
        return manager.createQuery("select p from Departamento p").getResultList();
    }

Aqui é o DAO da classe setorque popula a outra, ela que depende da departamento

public List<Setor> listar() {
        return manager.createQuery("select s from Setor s join fetch s.departamento",Setor.class).getResultList();

Aqui a jsp

<body>

    <div>
        <h1>Lista de departamentos</h1>
        <select name="CmbDepartamento">

            <option selected="selected">---Selecione Departamento---</option>

            <c:forEach items="${departamentos}" var="departamento">
                <option>${departamento.cod_departamento}-${departamento.departamento}</option>
            </c:forEach>
        </select>
    </div>

    <div>
        <h1>Lista de setores</h1>
        <select name="CmbSetor">
            <option selected="selected">---Selecione Setor---</option>

            <c:forEach items="${setores}" var="setor">
                <option>${setor.cod_setor}-${setor.setor}</option>
            </c:forEach>
        </select>
    </div>

</body>

Alberto agora a duvida é : vou ter que criar um metodo que lista pelo id, para ai sim pegar o relacionamentos e usar nesse codigo? e outra duvida preciso importar alguma dependencia ?

@Get("json")
public void toJSON(T obj, List<ParametrosWeb> parametrosWeb) {
    List<T> list = getDao().findAll(obj.getClass(), parametrosWeb);
    this.result.use(Results.json()).from(list).serialize();
}

retificando nesse codigo

document.getElementById(" comboPais").onchange(function(element){
     document.location.href = "suaUrl?idPais="+element.id;
});

Fiz esse jquery para testar esta dando certo o item que seleciono ele mostra no alert, no spring tem alguma forma de enviar esse valor para outra controller ? fiz um metodo na dao p listar por id, mas necessito dessa informação para listar, porem n tenho ideia de como fazer rsrs

$(document).ready(function() {
        var id = $("#CmbDepartamento").change(function() {

            alert($(id).val());

    });

esse é meu metodo que lista a segunda combo

    public List<Setor> listarPorID(int id) {

        return manager.createQuery(
                "select * from Departamento as d inner join Setor as s on d.cod_departamento = s.cod_departamento where d.cod_departamento and s.cod_departamento = :id",
                Setor.class).setParameter("id", id).getResultList();

    }

Isso, você precisa de um método mapeado com @RequestMapping no seu controller para receber o id de quem vc quer carregar os filhos... E aí vc, de dentro do método do seu controller, vc chama o seu dao.

Esse método eu ja criei a unica duvida e como devolver esse id que peguei com jquery p meu método mapeado, sem o uso de form, ou seja preciso ficar na mesma view e carregar a outra combo, pode dar uma dica de como fazer esse retorno?

Diego não mexo com Spring mas associando com vraptor se eu tenho um método que recebe um id:

@Path("controller")
public class Controller {
    @Get("{id:[0-9]{0,10}}")
    public void metodo(Integer id) {
        // códigos
    }    
}

Repare que o método recebe um id que pode ser numérico de no máximo 10 dígitos, então na requisição ajax basta fazer:

jQuery.ajax({
    // códigos comentado
    url: /controller/1
    // códigos comentado
});

No vraptor eu faço assim, agora não sei te dizer se seria da mesma forma com Spring, talvez você possa passar como parâmetro o id:

jQuery.ajax({
    // códigos comentado
    url: /controller?id=1
    // códigos comentado
});

Espero ter ajudado

O Matheus obrigado vou tentar dessa forma.

De nada, fico no aguardo...

solução!

Segui as dicas que deram e consegui fazer, agora o problema é que quando seleciono a primeira combo ele deveria popular a segunda de acordo com os metodos da controller, só que ele esta duplicando as combos, e populando o resultado em uma e a outra combo que ele duplica fica em branco.

Ajax

<script type="text/javascript">
        function crunchifyAjax() {

            var seleci = $("#CmbDepartamento").val();
            //             $('#CmbSetor').hide();
            //             alert(seleci);
            $.ajax({
                type : 'POST',
                url : '/preconizado/departamento/setor',
                //                 dataType : 'json',
                data : ({
                    id : seleci
                }),
                //                 contentType : 'application/json',
                //                 mimeType : 'application/json',
                success : function(data) {
                    $('#mostra').html(data);

                }
            });
        }
    </script>

Minha controller da primeira combo

@RequestMapping(value = "/departamento", method = RequestMethod.GET)
    public ModelAndView listar() {
        List<Departamento> departamentos = departamentoDAO.listar();

        ModelAndView modelAndView = new ModelAndView("/departamento/lista");
        modelAndView.addObject("departamentos", departamentos);

        return modelAndView;

Controller da combo dependente

public ModelAndView listar(@RequestParam int id) {

        List<Setor> setores = setorDAO.consulta(id);        
        ModelAndView modelAndView = new ModelAndView("/departamento/lista");
        modelAndView.addObject("setores", setores);            
        return modelAndView;

Opa, pelo seu método listar vc está retornando a mesma página do método que lista os departamentos. Não deveria retornar apenas o html do select com os setores?

exato alberto mas como e onde faço isso? jsp? no ajax? na controller?

No controller :).

mas já estou retornando essa lista não?

modelAndView.addObject("setores", setores);

consegui era apenas mudar de modelandview para list

Que bom que deu certo Diego, sempre que precisar não deixe de criar suas dúvidas.