Select combo (estado + cidade) usando o Helper Ajax (observeField)
Postado por Carlitos | Tags ajax , cakephp , helper ajax | Postado em 18:33
3
Estou começando a utilizar o Helper Ajax do CakePHP (baixei a versão 1.3.7), que utiliza o Prototype (e o Scriptaculous). Antes eu usava o jQuery para lidar com AJAX no Cake, mas conversando com o Ananias no grupo resolvi implementar alguns métodos do Helper Ajax para conhecer melhor e para testar a sua performance.
Bom, neste post pretendo mostrar uma forma de implementar aquele velho select combo de "estado" e "cidade" (ou pais, estado e cidade), onde ao selecionar um determinado "estado" as "cidades" referentes a ele são carregadas no select abaixo. Veja como fica simples de implementar usando o Helper Ajax.
1º) Eu criei duas tabelas: "estados" e "cidades" e criei também os respectivos: Models, Controllers e Views para elas. O código para criação das tabelas é:
CREATE TABLE `estados` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `estado` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; CREATE TABLE `cidades` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `estado_id` int(11) NOT NULL, `cidade` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
para gerar o MVC usei o BAKE.
2º) Criei também a tabela "users" e seu MVC usando o bake. Veja o SQL para criação da tabela:
CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) NOT NULL, `password` char(40) NOT NULL, `created` datetime DEFAULT NULL, `modified` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
Criei o "users" apenas para servir como ponto de partida para o formulário onde serão carregados os dados de outros modelos (veja que o modelo "User" não possui relacionamento com "Estado" e nem com "Cidade", e nem vice-versa).
3º) Bom, como tudo foi devidamente gerado via bake imagino que você já tenha todos os Models, Controllers e View devidamente criados (pelo menos o CRUD - add(), view(), delete() e edit()).
4º) Em ..app/controllers/cidades_controller.php vamos criar a action "listar", veja:
function listar($estado_id = 1){
$this->layout = 'ajax';
$this->set('cidades', $this->Cidade->find('list', array(
'conditions' => array(
'Cidade.estado_id' => $estado_id
),
'fields' => array(
'id', 'cidade'
),
))
);
}
e criar a view ...app/views/cidades/listar.ctp:<?php // Recebo $cidades echo '<option value="">Selecione a cidade</option>\n'; foreach($cidades as $id => $cidade) echo "<option value='$id'>$cidade</option>\n"; ?>
Veja que essa view irá gerar as opções de cidades do nosso select Cidades.
5º) No ...app/controllers/users_controllers.php vamos: definir a var $helpers, criar a action "listar_cidades" e modificar a action add:
class UsersController extends AppController {
var $name = 'Users';
var $helpers = array('Ajax', 'Javascript');
function add() {
if (!empty($this->data)) {
$this->User->create();
if ($this->User->save($this->data)) {
$this->Session->setFlash(__('The user has been saved', true));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.', true));
// Se o usuário selecionou algum estado, carregamos a lista de cidades para a view
if(!empty($this->data['User']['estado'])){
$this->loadModel('Cidade');
$cidades = $this->Cidade->find('list', array(
'conditions' => array(
'Cidade.estado_id' => $this->data['User']['estado']
),
'fields' => array('id', 'cidade'))
);
$cidades = array('' => 'Selecione a cidade', $cidades); // Adiciono o "Selecione a cidade" na lista de cidades
$this->set('cidades', $cidades);
}
}
}
$this->loadModel('Estado');
$estados = $this->Estado->find('list', array('fields' => array('id', 'estado')));
$this->set('estados', $estados);
}
function listar_cidades(){
// Se foi informado o Estado via POST
if(!empty($this->data['User']['estado'])){
$this->redirect(array('controller' => 'cidades', 'action' => 'listar', $this->data['User']['estado']));
}
}
.
.
. Veja o código do formulário criado no view add, em ...app/views/users/add.ctp:
<?php
// Carrego o Prototype e o Scriptaculos
$javascript->link('https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js', false);
$javascript->link('https://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.3/scriptaculous.js', false);
?>
<div class="users form">
<?php echo $this->Form->create('User');?>
<fieldset>
<legend><?php __('Add User'); ?></legend>
<?php
echo $this->Form->input('estado',
array(
'options' => $estados,
'empty' => 'Selecione o estado'
)
);
// Crio um Loading... para que o usuário saiba o que está ocorrendo
echo '<div id="loading" style="display: none"><b>' . $html->image('carregando.gif') . ' Aguarde, carregando cidades...</b></div>';
echo $this->Form->input('cidade',
array(
'type' => 'select',
)
);
echo $this->Form->input('username');
echo $this->Form->input('password');
?>
</fieldset>
<?php echo $this->Form->end(__('Submit', true));?>
</div>
<div class="actions">
<h3><?php __('Actions'); ?></h3>
<ul>
<li><?php echo $this->Html->link(__('List Users', true), array('action' => 'index'));?></li>
</ul>
</div>
<?php
echo $ajax->observeField('UserEstado',
array(
'url' => array(
'action' => 'listar_cidades'
),
'frequency' => 0.2,
'update' => 'UserCidade',
'indicator' => 'loading',
)
);
?>
Bom. o resultado final é este!Imagem 1 - O Form com o select Estado com os valores do banco e o select Cidade vazio, aguardando a seleção do estado.:
Imagem 2 - O usuário seleciona um estado:
Imagem 3 - Selecionado o estado a mensagem de carregando (atributo "indicator" do observeField()) aparece:
Imagem 4 - É carregada a lista de cidades!
Espero que o artigo seja útil! Caso fique com alguma dúvida ou tenha uma sugestão/crítica, fique a vontade para comentar! =]





Excelente post companheiro. muito bom mesmo.
Só pra acrescentar, uma pequena correção na codificação do cidades_controller:
function listar($estado_id = 1){
$this->layout = 'ajax';
$this->set('cidades', $this->Cidade->find('list', array(
'conditions' => array(
'Cidade.estado_id' => $estado_id
),
'fields' => array(
'id', 'cidade'
),
))
);
}
Obrigado.
Que bom que você gostou Carlilton!
Corrigi a codificação. Agora está OK!
Muito obrigado pelo toque!
Abraço,
kara,
muito bom o teu blog. parabens. ajudou-me muito.
100% de eficácia.
ficarei acompanhando.
abraços.