Como criar um select dinâmico

UPDATE 10/03/2017

Veja o vídeo onde mostro como fazer um select dinâmico com Estados/Cidades.


É bem comum hoje em dia precisarmos de sites onde existam selects dinâmicos para aumentar a funcionalidade e a interatividade do usuário.

Mas o que são mesmo selects ou combos dinâmicos?

O exemplo clássico para explicar isto é aquele de Estados e Cidades. Em uma página há 2 selects, o primeiro contém os estados e o segundo contém as cidades, mas que está inativo.

Quando o usuário escolhe um estado, automaticamente o combo de cidades é preenchido com as cidades daquele respectivo estado.

Vamos ver no exemplo de hoje como fazer algo parecido no CodeIgniter. Vamos aprender a como criar um select dinâmico. Aqui eu não vou ensinar a fazer a parte de Estados/Cidades, mas vai ser um exemplo que tem o funcionamento igual. Se você entender como este exemplo funciona, irá conseguir fazer seu select de Estados/Cidades.

A ideia aqui é a seguinte: vamos imaginar que estamos desenvolvendo uma loja virtual e que haverá 2 selects de navegação.

O primeiro select conterá os Departamentos, e o segundo select conterá os produtos do departamento escolhido no select anterior.

O primeiro passo é criarmos um banco de dados com as respectivas tabelas

A primeira tabela vai ser a de departamentos. Será uma tabela bem simples, com apenas 2 campos. DEPARTAMENTOS_ID e DEPARTAMENTOS_NOME. Abaixo a SQL para você criá-la:

Agora, a tabela PRODUTOS. Também será bem simples. Terá os campos: PRODUTOS_ID, PRODUTOS_ID_DEPARTAMENTO, PRODUTOS_NOME. Veja o código:

Nesta tabela, atente para o campo PRODUTOS_ID_DEPARTAMENTO. Aqui nós vamos inserir o ID do departamento PAI deste produto. Lembre-se que um DEPARTAMENTO poderá ter vários produtos.

Não vou criar aqui a parte de inserção de dados nas tabelas. Vamos inserir via phpmyadmin mesmo tudo na mão.

Acrescente na tabela DEPARTAMENTOS os seguinte registros de exemplo:

INFORMÁTICA
TELEFONIA
ELETRODOMÉSTICOS
GAMES

Não precisa colocar nada no campo DEPARTAMENTOS_ID, pois é um campo do tipo auto incremento.

Depois de inseridos os registros, você deverá ter algo parecido com isto:

imagem da tabela departamentos

 

Agora, na tabela PRODUTOS vamos inserir os produtos de cada departamento. Mas antes de inserir um produto, você deve verificar a qual departamento ele pertence, e copiar o ID do departamento para inserir na tabela. Vamos supor que vou inserir produtos que são do departamento INFORMÁTICA e vamos considerar que o DEPARTAMENTOS_ID de INFORMÁTICA é 1. Então, na tabela PRODUTOS os registros ficarão assim:

PRODUTOS_ID_DEPARTAMENTO: 1
PRODUTOS_NOME: MOUSE

PRODUTOS_ID_DEPARTAMENTO: 1
PRODUTOS_NOME: TECLADO

PRODUTOS_ID_DEPARTAMENTO: 1
PRODUTOS_NOME: MONITOR

PRODUTOS_ID_DEPARTAMENTO: 1
PRODUTOS_NOME: HD

PRODUTOS_ID_DEPARTAMENTO: 1
PRODUTOS_NOME: MEMÓRIA

PRODUTOS_ID_DEPARTAMENTO: 1
PRODUTOS_NOME: FONTE

Esta é uma etapa muito importante, pois é o campo PRODUTOS_ID_DEPARTAMENTO que irá dizer qual departamento é o dono daquele produto. Faça o mesmo agora para outros departamentos. Coloque uns 3 produtos por departamento.

Vamos inserir agora produtos para o departamento TELEFONIA, que tem o ID igual a 2.

PRODUTOS_ID_DEPARTAMENTO: 2
PRODUTOS_NOME: BATERIA

PRODUTOS_ID_DEPARTAMENTO: 2
PRODUTOS_NOME: CABO DE DADOS

PRODUTOS_ID_DEPARTAMENTO: 2
PRODUTOS_NOME: DISPLAY

Agora, produtos para o departamento ELETRODOMÉSTICOS, que tem o ID igual a 3
PRODUTOS_ID_DEPARTAMENTO: 3
PRODUTOS_NOME: FOGÃO

PRODUTOS_ID_DEPARTAMENTO: 3
PRODUTOS_NOME: GELADEIRA

PRODUTOS_ID_DEPARTAMENTO: 3
PRODUTOS_NOME: LAVADORA DE ROUPAS

E por último, produtos para o departamento GAMES, que tem o ID igual a 4

PRODUTOS_ID_DEPARTAMENTO: 4
PRODUTOS_NOME: PLAYSTATION

PRODUTOS_ID_DEPARTAMENTO: 4
PRODUTOS_NOME: WII

PRODUTOS_ID_DEPARTAMENTO: 4
PRODUTOS_NOME: XBOX

A tabela produtos deverá ficar parecida com a imagem abaixo:

print da tabela produtos

Feito isso, nossas tabelas já estão populadas e agora podemos fazer a parte de codificação no CodeIgniter.

Coloque uma nova cópia do CodeIgniter na pasta do seu servidor e configure-o para se conectar ao banco de dados recém criado. Se você não sabe como configurar o CodeIgniter para se conectar a um banco de dados, clique aqui.

Após conectar ao banco de dados, não se esqueça de carregar a biblioteca de banco de dados no autoload.php, que está em application/config, do CodeIgniter. Basta abrir este arquivo e informar que deseja carregar a biblioteca ‘database’, na linha 55.

Agora vamos aproveitar a estrutura de estilos e os controllers e views que o próprio CodeIgniter traz para gente.

O primeiro passo é criarmos os dois selects que ficarão na página inicial.

Abra a view welcome_message.php que está localizada em application/views. Localize a div body e apague os <p> que estão lá dentro. Então coloque o seguinte código:

Aqui nós vamos preencher os selects dinamicamente. Repare que em vez de digitar os options do select, eu coloquei uma variável PHP. Esta variável virá do controller welcome.php que é onde iremos montar os options com os departamentos vindos da tabela DEPARTAMENTOS.

O select de produtos será também preenchido dinamicamente, porém, via ajax. E os valores serão preenchidos baseado no departamento que o usuário escolher no select acima.

Agora, vamos criar um model que irá acessar o banco de dados e em seguida criar uma função que irá trazer todos os departamentos da tabela DEPARTAMENTOS.

Crie um arquivo chamado: m_departamentos_produtos.php e salve dentro da pasta application/models 

Dentro deste arquivo coloque o seguinte código:

Repare aqui nas regras de nomes para a criação de um model. A primeira letra da classe deve ser a primeira letra do nome do arquivo, porém em maiúscula.

Em seguida, criamos a função retorna_departamentos() que ao ser chamada fará uma simples consulta na tabela DEPARTAMENTOS e retornará estes dados para o controller welcome, que será de onde iremos chamar este model.

Agora, abra o arquivo welcome.php que está em application/controllers, localize a função index() e então substitua pelo seguinte código:

O que fazemos aqui é o seguinte:

Carregamos nosso model que irá fazer as consultas ao banco de dados.

Depois chamamos a função dentro deste model que irá trazer os registros da tabela DEPARTAMENTOS e atribuímos estes valores a uma variável chamada $departamentos.

Percorremos esta variável usando um foreach e para cada linha, criamos um option do select. Após percorrer a tabela inteira, enviamos o valor contido em $option para a view através da variável options_departamentos.

Se tudo deu certo aí, você já deverá ver o select Departamentos preenchido e funcionando na sua página inicial. Veja a figura abaixo:

print do select departamentos

Agora, vamos trabalhar em cima do select produtos. A lógica é seguinte: vamos acrescentar um evento onchange dentro do select departamentos, e cada vez que for clicado em um departamento diferente, uma função javascript, que irá trazer os produtos daquele departamento, será chamada e irá preencher o select produtos.

Altere a tag de abertura do select de departamentos para o seguinte código:

O que fizemos aqui foi acrescentar o evento onchange que irá chamar a função busca_produtos que receberá como parâmetro o valor que está em VALUE dentro de cada option quando este for selecionado. Para passar o parâmetro ID do departamento estamos utilizando uma função jQuery: $(this).val(), por isso você deve acrescentar dentro do HEAD do arquivo welcome_message.php umal linha que traz o jquery para seu projeto. Pode ser um arquivo no seu servidor ou hospedado em algum lugar na net. Vamos usar aqui um código que o Google nos fornece:

Acrescente entre as tag: <head> e </head> o seguinte código:

E logo abaixo desta linha, mas antes de fechar a tag </head>, coloque nossa função que irá buscar os dados no banco de dados.

Repare que por enquanto coloquei somente um alert no id_departamento que está vindo como parâmetro do select. Isto é só para testar. Ao clicar em algum departamento você deverá ver um alert na sua tela com o ID dele. Faça o teste.

Se você não ver um alert com o ID do departamento, então tem algo errado e você não deve proceder a leitura aqui no post. Volte e tente achar o erro. Caso contrário, não vai funcionar. 🙂

Testado e funcionando, vamos agora alterar a função busca_produtos para o código que realmente vai ter alguma utilidade.

O que vamos fazer é uma consulta via ajax para uma função dentro do controller welcome onde iremos passar o id_departamento como parâmetro para fazer uma busca na tabela produtos. Então, somente os produtos daquele departamento é que deverão ser retornados. Veja abaixo o código da função:

Arqui eu armazenei o endereço base do site dentro da variável javascript base_url, para que eu utilizasse ela na função. Para usar a função base_url() do CodeIgniter, você deve habilitar o helper ‘url’ dentro do autoload.php, que está em application/autoload.php

Depois, eu utilizei a função $.post() do jQuery, que basicamente faz o post de algum parâmetro para um endereço fornecido, e retorna algum valor dentro da função DATA, que no caso são os options baseados no departamento que nós queremos.

Em seguida, eu altero o contéudo do select produtos através da linha $(‘#produtos).html(data). Onde dentro de data está os options que geramos no controller.

Agora, vamos criar uma função dentro do nosso model que irá trazer os produtos baseados no id do departamento.

Abra o model m_departamentos_produtos e acrescente a seguinte função:

Aqui o processo também é bem simples. Eu recebo o id do departamento via post e uso isto como parâmetro para consultar a tabela produtos, para que ela me retorne somente os produtos que tem o id do departamento passado. Em seguida, eu saio da função com um return desta consulta.

Agora, vamos para o controller.

Abra o controller welcome.php e acrescente a seguinte função:

Esta é a função que o $.post() do jquery chama lá da view welcome_message.php. Esta função faz o seguinte:

Carrega o model, depois chama a função dentro do model que retornará os produtos pertencentes ao departamento, através do ID do departamento que é passado lá dentro do model.

Quando o model retornar os dados, eu uso um foreach para montar os options, exatamente como na função Departamentos, mas aqui tem um detalhe que faz toda a diferença.

Repare que na função que monta o select de departamentos, eu passo os options via variável PHP, e recupero estes valores lá na view.

No caso da função que irá montar os options do select de produtos, eu preciso dar um echo na variável criada pelo foreach, pois este valor será recuperado pela função $.post() do jquery, que nada mais é que um texto comum, e este texto eu atribuo ao select dentro do html.

Bom, se você fez tudo direitinho e eu não errei nada 🙂 é para estar tudo funcionando. Ao selecionar um departamento qualquer, a combo de produtos logo abaixo é preenchida automaticamente sem recarregar a página.

Abaixo segue o link para você fazer o download do projeto. Não esqueça de criar o banco de dados e as tabelas.

-> Baixar o projeto Select Dinâmico

Este é o fim do post de hoje. Por favor, não esqueça de deixar seu comentário abaixo dizendo suas dúvidas ou sugestões de novos posts.

Abraços.

P.S. Coloque seu e-mail na caixa ao lado para ficar sempre a par das coisas novas que posto aqui sobre o mundo CodeIgniter.

 

Fábio S. Reszko

Sou Programador PHP desde 2006 e eu acredito sinceramente que programar usando um Framework PHP é a solução para os problemas de códigos desorganizados, difíceis de entender e de dar manutenção no futuro. Se você também acredita nisto, então fique à vontade em explorar meu blog.

  • Vitor Henckel

    Parabéns pelo post. Ótimo.
    Não entendi uma coisa, se eu dou o POST para o Controller (welcome/busca_produtos_by_departamento) com o ID do departamento, como recupero no Model ($id_departamento = $this->input->post(“id_departamento”);) este POST?
    Abraço.

  • Olá Vitor, tudo tranquilo aí?

    O valor do ID enviado via POST pode ser recuperado tanto no Controller quanto no model através da linha $this->input->post(“id_departamento”). No exemplo acima, mesmo eu enviando um POST para o controller, eu consigo recuperar esta variável tanto no Controller quanto no Model, já que é uma variável SUPERGLOBAL, que está disponível em qualquer parte do php.

    Mas se você quiser, também pode passar este parâmetro para a função retorna_produtos_by_departamento() dentro do model via controller. Ficaria assim:

    $this->m_departamentos_produtos->retorna_produtos_by_departamento($id_departamento);

    A diferença é que na função dentro do model, você não precisaria criar a linha $this->input->post(“id_departamento”), pois ela já veio como parâmetro e já está disponível na variável $id_departamento.

    Se tiver alguma outra dúvida sobre o CodeIgniter, sugira um post.

    Abraços

    Fábio

  • Ruan Victor

    Obrigado, ótimo post, me ajudou muito ^^

  • Valeu Ruan, qualquer dúvida ou sugestão de post, fique à vontade.

    Abraços

  • Cássio

    Valeu me ajudou muito, já que meu forte não é Jquery, também adorei a iniciativa do blog, ainda existem poucos blogs dedicados ou Codeigniter.

  • Olá Cássio.

    Valeu pela comentário. Se puder, ajude a divulgar o blog.

    Abraços

  • Samuel

    Boa Noite, tenho uma duvida com codeigniter não sei se é possível me ajudar, tenho cadastro de cliente certo, ai tenho uma pagina onde faço as etiquetas e imprimo eu preciso que nessa pagina eu seleciono o cliente e preenche automático os demais campos que são endereço, telefone, cidade, e estado do cliente que já estão cadastrado na tabela de cliente, Obrigado Samuel

  • Olá Samuel

    Bom, fica meio difícil explicar pois não sei exatamente como é seu sistema. Pelo que entendi você tem uma página que faz a impressão de etiquetas e nesta página você quer colocar um menu dropdown, por exemplo, onde você escolhe o cliente, então a página recarrega com os campos que serão impressos já preenchidos.

    Há duas maneiras de fazer isto: do jeito tradicional ou com ajax.

    Do jeito tradicional, você coloca no menu dropdown uma função que dê um post para a própria página enviando o ID do cliente que aparece neste menu dropdown. Então, no controller que vai receber este post, você recupera este ID e faz uma consulta ao seu banco de dados para trazer os dados do cliente. Em seguida, basta chamar esta mesma view passando os dados deste cliente através de uma variável.

    Um outro jeito é via ajax. Nesta mesma página com o menu dropdown, no evento onchange dele, você chama uma função Ajax que vai até um controller e busca os dados do cliente através do ID. Depois, você preenche os elementos dentro desta página usando jSON, pois vários campos serão retornados.

    Eu só expliquei aqui o conceito, pois fica complicado de eu escrever o código completo.

    Espero que tenha ajudado.

    Valeu

    Fabio

  • Thiago Silva

    Bom Dia, primeiro quero agradecer pelo post, só que o mesmo não esta funcionando, baixei o projeto e o mesmo também não lista ele não apresenta nenhum erro só que não lista os departamentos nem o produtos,

  • Bom dia Thiago

    No arquivo para download eu coloquei somente a estrutura do banco de dados, esqueci de colocar os dados. Eu fiz a atualização do arquivo. Baixe ele de novo e rode novamente o arquivo tabelas.sql no seu banco de dados.

    Agora ele vai funcionar.

    Obrigado

    Fabio

  • Thiago Silva

    fiz a atualização no DB e também substitui os arquivos pelos atualizados mas não listou

  • Thiago, criei uma pasta nova aqui no meu servidor local baseado no zip do post e funcionou.
    Se não está listando nem os departamentos, talvez haja algum erro de conexão ao seu banco. Veja se o seu PHP está configurado para não mostrar os erros. Provavelmente haja algum erro que não está sendo enviado para a tela.

    Fabio

  • rafael

    Muito bom cara, agora tem como limitar o primeiro departamento? Ex: no meu banco de dados tem 15 registro mas eu so quero que apareça 5 registros , cada pagina vai ser diferente entendeu ?
    desde ja obrigado
    abraços

  • Olá Rafael

    Pelo que entendi você quer limitar a quantidade de produtos para cada departamento dependendo da página onde o visitante estará. Se for isso mesmo, então você vai ter que passar um parâmetro para a função que retorna os produtos daquele departamento, e este parâmetro será diferente em cada página.

    Eu faria assim: em cada página onde você quer que apareçam os produtos, eu colocaria um campo do tipo hidden no formulário com o nome por exemplo: , e na função que faz o post: busca_produtos() você passa também este parâmetro junto com id_departamento. Ficaria assim:

    function busca_produtos(id_departamento){

    $.post(base_url+”index.php/welcome/busca_produtos_by_departamento”, {
    id_departamento : id_departamento,
    limite: $(‘#limite’).val()
    }, function(data){
    $(‘#produtos’).html(data);
    });
    }

    Fazendo isso, você vai conseguir recuperar esta variável lá no controller, que então poderá passar para o model e aplicar o limit na consulta do banco de dados.
    Em cada página você vai colocar este campo hidden e colocar em value quantos registros você quer que sejam trazidos do banco de dados.
    Não testei, mas acho que eu iria por este caminho. Faça um teste aí e depois poste os resultados.

    Valeu
    Fabio

  • daniel capua

    Fábio parabéns pela iniciativa do blog, estou concluindo o curso de ADS e meu TCC será desenvolvido em codeigniter e bootstrap, sou novo no assunto, seu blog ajudará muito!!

  • Olá Daniel

    Obrigado. Boa sorte no seu TCC.

    Se quiser dar alguma sugestão de post, fique à vontade.

    Abraços.

  • Ronald

    Quero receber mensagens e novas postagens, mas não localizei o local no site…

  • Olá Ronald,

    No momento estamos postando as atualizações na nossa página no Facebook. Basta curtir o site que você será notificado quando houver post novo.

    Obrigado

    Fabio

  • Jorgito Paiva

    Prezado Fábio,

    Eu fiz de acordo com seu post de dicas para carregar em select de UF’, porém na parte do código ($variaveis[‘ufs’] = $option;) não é possível jogar a variável $variaveis no caregamento da view ($this->load->view(‘v_layout’, $dados);) pois já existe uma variável $dados para carregar a view v_clientes ($dados[‘nome_view’] = ‘v_clientes’;) o meu código esta abaixo, neste caso o que devo fazer ???

    public function index() {
    $dados[‘nome_view’] = ‘v_clientes’;

    $this->load->model(“m_uf”);
    $uf = $this->m_uf->getUf();
    $option = “”;

    foreach($uf -> result() as $linha) {
    $option .= “id_uf’>$linha->uf_sigla”;
    }
    $variaveis[‘ufs’] = $option;
    $this->load->view(‘v_layout’, $dados);

    }

  • Jorgito, você precisa criar um array para passar as variáveis pra view. No caso do post, esta array eu chamei de $variaveis[]. No seu exemplo você deve simplesmente mudar a linha que chama a view de:

    $this->load->view(‘v_layout’, $dados);

    PARA;

    $this->load->view(‘v_layout’, $variaveis);

    Você está passando uma array chamada $dados que não existe no controller.

    Dúvidas entre em contato.

    Fabio

  • Betinho Silva

    está com esse erro

    A PHP Error was encountered

    Severity: Notice
    Message: Undefined variable: options_departamentos
    Filename: views/welcome_message.php
    Line Number: 92

    linha 92 é essa:

  • Betinho Silva

    echo $options_departamentos;

  • Veja se a variável options_departamentos está sendo criada no controller e sendo repassada para a view. Olhei o código fonte do controller aqui e está aparentemente tudo normal.

    Fabio

  • Tudo funcionou perfeitamente.

    Ajudou muito.

    Obrigado!

  • PARABENS FABIO! Parace que virou maxima lembro que vejo um trabalho seu parabenizo. Mas parabenizo pela sua dedicacao e presteza em sempre apresentar os artigos de forma que irah acrescentar algo a alguem. O mundo precisa de mais pessoas iguais a voce amigo.
    – Fabio tenho uma pergunta, apos alimentar os $this->db, tem como obter a select completa gerada, a que ele gera para efetuar a consulta ou o comando no banco. aguardo. abracos e continue a alimentar-nos pela rede.

  • Obrigado José.

    Tem sim, basta você digitar a linha echo $this->db->last_query() imediatamente após o $this->db->get(). Assim o CI imprimirá na tela a query gerada.

    Abraços
    Fábio

  • Walney Moreira Klein

    sou iniciante em php, como por exemplo funcionaria se tivesse um form para cadastrar estes produtos e dentro uma combobox com os departamentos que estão na tabela de departamentos e ao salvar salvar o id do departamento, como fazer isso e se tiver um form estilo boostrap melhor ainda, pois ainda não sei fazer isso, obrigado.

  • Amapá Sites Tecnologia

    Fabio mais uma vez parabéns pelo artigo. Bem detalhado. Bom eu peguei seu exemplo para usar no meu trabalho, porem estou com um pouco de dificuldades no javascrip. Pois quero ao selecionar um option de um select, retornar um valor para um input tipo texto. Então invés de $(‘#produtos’).html(data);
    Como retorno o valor requerido? Abraço Fabio e obrigado por sempre ajudar.

  • Para retornar o valor faça assim: $(“#produtos”).val();

  • Amapá Sites Tecnologia

    Estou recebendo essa msg Message: Invalid argument supplied for foreach().
    Onde estou errando?

  • O foreach serve para iterar um array. Se você não passar um array pra ele, vai dar este erro.

  • Rafael Dória

    Beleza Fábio! ok, ótimo post. Dúvida: salvar, como recupera o id do departamento e do produto, na ferramenta do browser os id’s dos mesmo estão vazios, null, ” “. Obrigado.

  • João Vitor Martins

    Aqui tive que trocar a tag de abertura Php.
    de para