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:

CREATE TABLE IF NOT EXISTS `departamentos` (
`departamentos_id` int(11) NOT NULL AUTO_INCREMENT,
`departamentos_nome` varchar(255) NOT NULL,
PRIMARY KEY (`departamentos_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

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

CREATE TABLE IF NOT EXISTS `produtos` (
`produtos_id` int(11) NOT NULL AUTO_INCREMENT,
`produtos_id_departamento` int(11) NOT NULL,
`produtos_nome` varchar(255) NOT NULL,
PRIMARY KEY (`produtos_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

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:

<p>
Escolha o Departamento:<br />
<select name="departamentos" id="departamentos">
<? echo $options_departamentos; ?>
</select>
</p>
<p>
Escolha o Produto:<br />
<select name="produtos" id="produtos">
</select>
</p>

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:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class M_departamentos_produtos extends CI_Model{

function __construct()
{
parent::__construct();
}

public function retorna_departamentos()
{

$this->db->order_by("departamentos_nome", "asc");
$consulta = $this->db->get("departamentos");

return $consulta;
}
}

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:

public function index()
{
$this->load->model("m_departamentos_produtos");

$departamentos = $this->m_departamentos_produtos->retorna_departamentos();

$option = "<option value=''></option>";
foreach($departamentos -> result() as $linha) {
$option .= "<option value='$linha->departamentos_id'>$linha->departamentos_nome</option>"; 
}

$variaveis['options_departamentos'] = $option;

$this->load->view('welcome_message', $variaveis);
}

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:

<select name="departamentos" id="departamentos" onchange='busca_produtos($(this).val())'>

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:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>

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.

function busca_produtos(id_departamento){
  alert(id_departamento);
}

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:

var base_url = '<? echo base_url() ?>';

function busca_produtos(id_departamento){

$.post(base_url+"index.php/welcome/busca_produtos_by_departamento", {
id_departamento : id_departamento
}, function(data){
$('#produtos').html(data);
});
}

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:

public function retorna_produtos_by_departamento() {

$id_departamento = $this->input->post("id_departamento");

$this->db->where("produtos_id_departamento", $id_departamento);

$this->db->order_by("produtos_nome", "asc");

$consulta = $this->db->get("produtos");

return $consulta;
}

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:

public function busca_produtos_by_departamento(){

$this->load->model("m_departamentos_produtos");

$produtos = $this->m_departamentos_produtos->retorna_produtos_by_departamento();

$option = "<option value=''></option>";
foreach($produtos -> result() as $linha) {
$option .= "<option value='$linha->produtos_id'>$linha->produtos_nome</option>"; 
}

echo $option;
}

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.