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.