17 de novembro de 2009
15Populando selects de cidades e estados com AJAX (PHP e jQuery)
Nada pior do que deixar um campo de cidade como texto livre para os usuários. Os erros de português e digitação acabam com qualquer chance de um relatório fiel filtrado por localidade. Além do mais, é muito mais fácil pro próprio usuário poder escolher sua cidade em uma lista já estabelecida.
Com este artigo, pretendo mostrar um método fácil de implementar um select de estados que, via AJAX, popula o select de cidades. O frontend utiliza a biblioteca javascript jQuery e o script AJAX foi desenvolvido em PHP.
Abaixo, além do arquivo de exemplo, você também encontra para download um SQL completo com as tabelas de cidades e estados. Portanto, caso queira desenvolver para um outra linguagem, basta seguir a lógica apresentada aqui.
Banco de Dados
Antes de mais nada, precisamos criar a nossa base de cidades e estados. No seu banco MySQL, crie as tabelas cidades e estados. O arquivo SQL abaixo faz isso e ainda insere todos os registros necessários. Não sei se essa base está atualizada e/ou completa, mas é a que sempre utilizo em meus projetos e, até agora, ninguém reclamou!
O select de estados vai utilizar os campos cod_estados e sigla como dados. Já o de cidades, listará as cidades de acordo com o campo estados_cod_estados, exibindo o nome e tendo como valor cod_cidades.
O frontend
A idéia básica é a seguinte: o select de estados virá automaticamente populado com os registros cadastrados em nosso banco de dados. Toda vez que o usuário selecionar um estado diferente, o select de cidades será preenchido via AJAX fazendo uma consulta na nossa tabela de cidades, trazendo todos os registros relacionados ao estado.
Note que não vou me estender muito na conexão com o banco de dados. O ideal é fazer isso separado, com variáveis para o host, senha, usuário etc. Aqui vai tudo no mesmo arquivo, só pra agilizar o exemplo.
<?php
$con = mysql_connect( 'localhost', 'root', 'root' );
mysql_select_db( 'cadastro', $con );
?>
<label for="cod_estados">Estado:</label>
<select name="cod_estados" id="cod_estados">
<option value=""></option>
<?php
$sql = "SELECT cod_estados, sigla
FROM estados
ORDER BY sigla";
$res = mysql_query( $sql );
while ( $row = mysql_fetch_assoc( $res ) ) {
echo '<option value="'.$row['cod_estados'].'">'.$row['sigla'].'</option>';
}
?>
</option></select>
<label for="cod_cidades">Cidade:</label>
<select name="cod_cidades" id="cod_cidades">
<option value="">-- Escolha um estado --</option>
</select>
O código acima representa o estado inicial da listagem de estados/cidades.
Populando o select
Vejamos agora como fica o javascript (jQuery) responsável pelo carregamento de dados no select de cidades. Vamos utilizar o padrão JSON para a saída do script PHP. Se você ainda não conhece esse padrão, vale a pena dar uma pesquisada - ele é extremamente útil para scripts AJAX, evitando aquele blocão HTML que todo mundo costuma usar como saída. O PHP fica responsável somente pelos dados enquanto o javascript trata e monta o HTML.
$(function(){
$('#cod_estados').change(function(){
if( $(this).val() ) {
$('#cod_cidades').hide();
$('.carregando').show();
$.getJSON('cidades.ajax.php?search=',{cod_estados: $(this).val(), ajax: 'true'}, function(j){
var options = '<option value=""></option>';
for (var i = 0; i < j.length; i++) {
options += '<option value="' + j[i].cod_cidades '">' + j[i].nome + '</option>';
}
$('#cod_cidades').html(options).show();
$('.carregando').hide();
});
} else {
$('#cod_cidades').html('<option value="">-- Escolha um estado --</option>');
}
});
});
O jQuery possui o método getJSON para o recebimento de dados no padrão citado acima. Como parâmetro enviamos o código do estado selecionado. O script PHP faz então uma pesquisa na tabela cidades e retorna os resultados relacionados com o código do estado em um array JSON.
Agora a última peça do nosso exemplo, o PHP responsável por retornar os dados encontrados, chamado na função getJSON:
header( 'Cache-Control: no-cache' );
header( 'Content-type: application/xml; charset="utf-8"', true );
$con = mysql_connect( 'localhost', 'root', 'root' ) ;
mysql_select_db( 'cadastro', $con );
$cod_estados = mysql_real_escape_string( $_GET['cod_estados'] );
$cidades = array();
$sql = "SELECT cod_cidades, nome
FROM cidades
WHERE estados_cod_estados=$cod_estados
ORDER BY nome";
$res = mysql_query( $sql );
while ( $row = mysql_fetch_assoc( $res ) ) {
$cidades[] = array(
'cod_cidades' => $row['cod_cidades'],
'nome' => $row['nome'],
);
}
echo( json_encode( $cidades ) );
Como de praxe, deixo pra vocês o trabalho de efetuar melhorias em nosso script. E se, em um mesmo formulário, precisarmos de dois campos de endereço (um residencial e outro comercial)? Repetir o código nem pensar! O ideal seria uma função recebendo como parâmetro os IDs dos selects de estado e cidade. E que tal uma base de dados para bairros? Toda vez que uma cidade fosse escolhida, um select de bairros seria automaticamente populado. Ideias não faltam.
Espero que este post sirva de base para vocês melhorarem seus formulários de cadastro. E qualquer dúvida já sabem, utilizem os comentários.
15 leitores comentaram este artigo
04/12/2009
13:50
Ricardo Kruger escreveu:
Excelente este código, ajudou em muito a funcionalidade de meu sistema de cadastro o qual estou desenvolvendo.
Assim que tiver um melhora no meu código, irei postar aqui uma atualização, como por exemplo o de bairros.
Abraços
Responder
07/12/2009
11:24
Alexandre Broggio escreveu:
Vlw pelo post ^_^
Responder
10/12/2009
12:38
Ricarte A. Barros escreveu:
Bem enxuto! nota 10!
Responder
05/01/2010
00:48
Felipe escreveu:
Cara bom de mais esse seu script, ele funciona 100% na minha maquina local , mas quando faço o FTP ele não lista as cidades, a conexão com o banco esta correta, sei lá pq não está funcionando..
vc tem alguma dica pra mim sobre oq pode estar acontecendo.???
se quiser ver é só acessar www.familyturismo.com
valew
abraços
Responder
05/01/2010
09:37
Davi Ferreira escreveu:
Fala aí, Felipe.
Cara, dei uma olhada lá no código-fonte do seu site e não consegui achar nenhuma referência ao javascript que carrega as cidades ou até mesmo do jquery. Não é aquele na home? Tá subindo certinho?
Abrá!
Responder
18/01/2010
14:40
Luiz Bezerra escreveu:
O meu na hr que eu subo tbm nao lista as cidades.
Responder
18/01/2010
15:10
Luiz Bezerra escreveu:
obs:
Versão do PHP 5.2.12
Versão do MySQL 5.0.85-community
Responder
20/01/2010
10:50
tiago escreveu:
como se faz esses campos de códigos, com a numeração das linhas ao lado?
valeu
Responder
21/01/2010
04:53
tiago escreveu:
Ah, esqueci de especificar melhor:
"como se faz esses campos de códigos, com a numeração das linhas ao lado?", esses do seu blog, onde você mostra os códigos. Gostaria de fazer um blog também e colocar isso... Obrigado.
Responder
22/01/2010
14:10
tiago escreveu:
outra coisa, na hora de carregar as cidades no mysql, algumas entraram com erros, como "BRASILÉIA", "TARAUACÃ", "JORDÃO", etc... sabe como faço pra nao entrar com esses caracteres?? Valeu
Responder
25/01/2010
08:50
Bruno escreveu:
Aqui eu utilizei o script para carregar um combobox com subcategoria de produtos, ta dando problema em nomes com acento, por exemplo Câmera Digital, só aparece a letra C
se eu retirar o acento aparece toda a palavra
como faço para aparecer com acento?
Responder
07/02/2010
15:06
Davi Ferreira escreveu:
Tem que se ligar que a base de dados está como UTF-8. Então se seu banco/sistema for ISO-8859-1 tem que converter a base de alguma forma.
Responder
25/01/2010
11:22
tiago escreveu:
Estou utilizando outro sistema, só com javascript e mais nada. Quem quiser me pedir, é só adicionar no MSN tbrazil@hotmail.com
Responder
15/02/2010
13:34
Perroni escreveu:
Mais um...
Obrigado graças as pessoas como você que os sobrinhos evoluem.
Responder
06/03/2010
08:09
Roberto cezar escreveu:
Cara valeu show de bola o escript valeu mesmo um abraço
Responder
Deixe seu comentário