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! =]