17 de novembro de 2009
29Populando 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.
29 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
02/06/2010
11:33
João Paulo escreveu:
Responder
02/06/2010
11:34
João Paulo escreveu:
echo htmlentities($menu_sub['nome'], ENT_COMPAT, 'UTF-8')
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
04/04/2010
15:50
Rafael Gilead escreveu:
Meu velho, conseguí por para funcionar perfeitamente. O problema que estou encontrando é para por a cidade para ser selecionada em uma página para EDITAR o cadastro.
Pois eu coloco o estado SELECTED mas as cidades só aparecem se eu mecher no select dos estados.
Responder
14/04/2010
11:34
Ayesha escreveu:
Olá, inclui o cod no site q estou desenvolvendo e nao carrega as cidade de maneira alguma... aqui esta o php em questao: http://www.canalcomercio.tv/tecnica/teste/cadastro/cadpj.php
alguma ideia?
Responder
17/04/2010
07:34
Davi Ferreira escreveu:
Seu servidor não tem suporte nativo a JSON. Utilize esta classe: http://mike.teczno.com/json.html.
Responder
16/04/2010
10:45
Plínio escreveu:
Só não entendi o pq do campo id do estado ser um int(11) se temos somente 27 estados.
Responder
13/05/2010
00:40
Ulisses Costa escreveu:
Amigo, desculpe a B.O, estou com a mesma dificulde em carregar as cidades no servidor remoto, já baixei a biblioteca sujerida mais nada, abaixo segue o o codigo.
require("JSON.php"); //importando a biblioteca
$json = new Services_JSON();//criando o objeto para manipular a JSON
...
$output = $json->encode($cidades);
echo($output);
Responder
13/05/2010
13:50
Marco Tulio escreveu:
Boa tarde!
Primeiramente muito obrigado pelo post.
Estou a procurar por vários dias mas não encontrei nada que fizesse o que eu queria.
Estou a ter o seguinte problema:
Para inserir um combobox dá certo. Funciona ok!
Porém quando coloco 2 combobox não está a funcionar.
Não sei o que devo fazer. Você pode me dar alguma dica de como fazer isso?
Obrigado!
Responder
15/05/2010
18:29
Davi Ferreira escreveu:
Fala Marco,
você vai precisar desenvolver uma função ou duplicar (ugh!) o trecho de código modificando os IDs dos elementos (#cod_cidades, #cod_estados).
Responder
19/05/2010
13:22
Sidarta escreveu:
Olá
Obrigado pelo código, mas estou com um problema, o primeiro e o último valor que da lista que é carregada estão como null. O que pode ser?
Responder
22/07/2010
09:20
Brunno Velasco escreveu:
Pra resolver o problema da acentuação:
mysql_query("SET NAMES 'utf8'", $con);
mysql_query('SET character_set_connection=utf8', $con);
mysql_query('SET character_set_client=utf8', $con);
mysql_query('SET character_set_results=utf8', $con);
Responder
24/07/2010
10:09
Junior Eberhardt escreveu:
No meu aqui apareceu certinho, quando seleciono algum estado, algumas cidades aparecem listadas como null...?
Responder
27/07/2010
19:51
Leonardo escreveu:
Uma dúvida! Se eventualmente o meu select cod_estado já estiver um valor selecionado logo de cara... sem que eu tenha que selecionar... como fazer com que a página já saiba disso e escolha as cidades... e/ou A cidade também??
Responder
Deixe seu comentário