Como usar "máscaras" em campos de formulário do Cake com plugin maskedinput pra jQuery

Postado por Carlitos | Tags , , , | Postado em 17:45

0

No post anterior mostrei como usar "máscaras" em campos de formulário do Cake com plugin meioMask pra jQuery. Hoje vou mostrar um outro plugin que faz basicamente a mesma coisa, porém ele mostra a "máscara", digamos assim, assim que damos um focus no campo. Por isso gosto e uso muito ele. Trata-se do maskedinput (http://digitalbush.com/projects/masked-input-plugin/).

Bom, antes de começar dá um play nesse som =]
1) Primeiramente fazemos o download do plugin maskedinput através do link http://digitalbush.com/projects/masked-input-plugin/. Eu baixei a versão 1.2.2 minified. Salvando o script em app/webroot/js;

2) Em uma view qualquer (escolhi a app/views/users/add.ctp) gerada via BAKE eu criei três campos: dtNasc, cpf e hora. Vejam:
<?php
//... app/views/users/add.ctp
...
  echo $this->Form->input('dtnasc',
   array(
    'label' => 'Data de Nascimento'
   ) 
  );
  echo $this->Form->input('cpf',
   array(
    'label' => 'CPF'
   ) 
  );
  echo $this->Form->input('hora',
   array(
    'label' => 'Hora'
   ) 
  );
...
?>

3) Adiciono os scripts (jQuery e o plugin) na view. Vejam:
<?php
//... app/views/users/add
 $javascript->link(
  array(
   'https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js', 
   'jquery.maskedinput'
  ), 
 false);
...
?>

4) Conforme falei no post anterior usaremos os IDs dos campos para que o jQuery "os encontre" no DOM. Então setamos as máscaras para cada campo, para isto usamos a função mask(). Vejam:
<?php
//... app/views/users/add.ctp
...
 $javascript->codeBlock('
  jQuery(function($){
   $("#UserDtnasc").mask("99/99/9999");
   $("#UserCpf").mask("999.999.999-99");
   $("#UserHora").mask("99:99");
  });
 ', array('inline' => false));
...
?>

5) Pronto! Simples não? Repare que ao colocar o cursor do mouse sobre os campos a "máscara" já é mostrada. Isso facilita muito para o usuário, uma vez que ele já prevê como os valores serão formatados (mascarados). Vejam o código final da view:

<?php
//... app/views/users/add.ctp
 $javascript->link(
  array(
   'https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js', 
   'jquery.maskedinput'
  ), 
 false); 
 $javascript->codeBlock('
  jQuery(function($){
   $("#UserDtnasc").mask("99/99/9999");
   $("#UserCpf").mask("999.999.999-99");
   $("#UserHora").mask("99:99");
  });
 ', array('inline' => false));
?>
<div class="users form">
<?php echo $this->Form->create('User');?>
 <fieldset>
   <legend><?php __('Add User'); ?></legend>
 <?php
  echo $this->Form->input('dtnasc', 
   array(
    'label' => 'Data de Nascimento'
   ) 
  );
  echo $this->Form->input('cpf', 
   array(
    'label' => 'CPF' 
   ) 
  );
  echo $this->Form->input('hora', 
   array(
    'label' => 'Hora' 
   ) 
  );
 ?>
 </fieldset>
<?php echo $this->Form->end(__('Submit', true));?>
</div>

Bom, espero que tenham gostado! Apesar de ser "perfumaria", muitas vezes os recursos de máscara facilitam a vida do usuário. Só não pode esquecer de tratar os dados no server-side, pois o usuário pode estar com o javascript desabilitado, ok? =P

Como usar "máscaras" em campos de formulário do Cake com plugin meioMask pra jQuery

Postado por Carlitos | Tags , , , | Postado em 18:22

0


Tá precisando colocar umas máscaras em campos de formulário? Não precisa ficar quebrando a cabeça com um monte de javascript. Existem muitos plugins prontos para jQuery e outras bibliotecas.
O plugin meioMask (http://plugins.jquery.com/project/meioMask) é uma excelente iniciativa brazuca do pessoal do MeioCódigo.com. Esse plugin para jQuery é bem flexível, veja como usá-lo em http://www.meiocodigo.com/projects/meiomask/.

Bom, mãos na massa!

1) O primeiro passo é entrar no site do meiomask e baixar a útltima versão estável do script e salvá-lo em: app/webroot/js. No meu caso baixei a versão 1.1.3 (comprimida) e salvei com o nome "jquery.meio.mask.min.js";


2) Peguei uma view qualquer (escolhi a app/views/users/add.ctp) previamente gerada pelo BAKE que possui um formulário com os seguintes campos: DtNasc, CPF e Hora (não me pergunte pra que raio de cadastro é esse... coloquei só pra exemplificar os casos =]), vejam:
<?php
// ...app/views/users/add.ctp  
...
...
...

  echo $this->Form->input('dtnasc',
   array(
    'label' => 'Data de Nascimento'
   ) 
  );
  echo $this->Form->input('cpf',
   array(
    'label' => 'CPF'
   ) 
  );
  echo $this->Form->input('hora',
   array(
    'label' => 'Hora'
   ) 
  );

...
...
...
?>

3) Agora adiciono o jQuery e o script do plugin meiomask na view, vejam:

<?php
// ...app/views/users/add.ctp
 $javascript->link(
  array(
   'https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js',
   'jquery.meio.mask.min'
  ),
 false);
...
...
...
?>

4) Logo em seguida, adicionamos um "bloco de código" setando as máscaras para os campos do formulário usando o ID do campo para isso.
OBS: O Form Helper do Cake sempre gera um ID para cada campo criado seguindo o padrão id="ModelCampo". No nosso caso o model é o User e temos os campos Dtnasc, Cpf e Hora, o que gera os ids: UsersDtnasc, UserCpf e UserHora. O jQuery usa o '#' para referenciar IDs no DOM.

<?php
// ...app/views/users/add.ctp
...
...
...

 $javascript->codeBlock('
  jQuery(function($){
   $("#UserDtnasc").setMask("39/19/2999");
   $("#UserCpf").setMask("999.999.999-99");
   $("#UserHora").setMask("29:59");
  });
 ', array('inline' => false));
...
...
...

?>

5) Feito isto é só acessar o .../users/add e verificar o resultado ao entrar com números nos campos. Veja que ele permite apenas a entrada de números e adiciona automaticamente os pontos, barras e etc, que foram setados no molde da máscara. O código final ficou assim:

<?php // ...app/views/users/add.ctp $javascript->link( array( 'https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js', 'jquery.meio.mask.min' ), false); $javascript->codeBlock(' jQuery(function($){ $("#UserDtnasc").setMask("39/19/2999"); $("#UserCpf").setMask("999.999.999-99"); $("#UserHora").setMask("29:59"); }); ', array('inline' => false)); ?> <div class="users form"> <?php echo $this->Form->create('User');?> <fieldset> <legend><?php __('Add User'); ?></legend> <?php echo $this->Form->input('dtnasc', array( 'label' => 'Data de Nascimento' ) ); echo $this->Form->input('cpf', array( 'label' => 'CPF' ) ); echo $this->Form->input('hora', array( 'label' => 'Hora' ) ); ?> </fieldset> <?php echo $this->Form->end(__('Submit', true));?> </div>
Eu particularmente uso outro plugin para máscaras (que mostrarei no próximo tópico), mas o meioMask é uma excelente alternativa além de ser brasileiro.

Espero que seja útil! Abração!

Autocomplete nativo do Cake (Ajax Helper)

Postado por Carlitos | Tags , , , , | Postado em 11:20

2

Eu já havia mostrado uma implementação de autocomplete no Cake usando o jQuery UI (http://cakenaveia.blogspot.com/2010/06/jqueryui-autocomplete-no-cakephp-agora.html), mas nunca havia usado o autocomplete nativo dele que utiliza o Prototype e o Scriptaculos. Até porque não tenho muita familiaridade com essas outras bibliotecas e gosto muito dos temas prontos do jQuery UI, o que dispensa dores de cabeça com o CSS.

Bom vamos nessa então...

Antes de começarmos veja nos posts anteriores como criar uma tabela de "cidades" (no meu caso, com os campos: id, estado_id, cidade) e crie para ela o model, views e controller usando o bake.

1º) Seguindo o book (http://book.cakephp.org/view/1370/autoComplete) crie a action autoComplete() no controller ...app/controllers/cidades_controller.php.

function autoComplete(){
        $this->layout = 'ajax';
        $cidades = $this->Cidade->find('all', array(
                'conditions' =>    array('Cidade.cidade LIKE' => $this->data['Cidade']['cidade'] . '%'),
                'order' => array('Cidade.cidade'),
                'fields' => array('cidade')
            )
        );
        $this->set('cidades', $cidades);
    }
Veja que estou listando todas as cidades cujo nome comece com o argumento recebido via POST e ordeno a lista de cidades ascendentemente.

2º) Crio a view ...app/views/cidades/auto_complete.ctp:
<ul>
<?php
    foreach($cidades as $cidade)
        echo '<li>' . $cidade['Cidade']['cidade'] . '</li>';
?>
</ul>
3º) E na view ...app/views/cidades/add.ctp adicionamos o autocomplete em si:
<?php
    $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);  
    
    echo $this->Html->css('autocomplete');
?>    
<div class="cidades form">
<?php echo $this->Form->create('Cidade');?>
    <fieldset>
         <legend><?php __('Add Cidade'); ?></legend>
    <?php
        echo $this->Form->label('Cidade');
        echo $ajax->autoComplete('Cidade.cidade', '/cidades/autoComplete');
    ?>
    </fieldset>
<?php echo $this->Form->end(__('Submit', true));?>
</div>
Veja que o $ajax->autoComplete('Cidade.cidade', '/cidades/autoComplete') cria um input com autocomplete, mas esse input vem sem label =/, portanto temos que gerar um label antes.

Veja também que adicionei um CSS (echo $this->Html->css('autocomplete'))  para estilizar a lista com os resultados do autocomplete. O arquivo ...app/webroot/css/autocomplete.css ficou assim:
div.auto_complete {
    background: #003d4c;
    color: #ffffff;
}
div.auto_complete ul {
    margin:0;
    padding:0;
    width: 100%;
    list-style-type:none;
}
div.auto_complete ul li.selected {
    background-color: #62AF56;
    font-weight: bold;
}
div.auto_complete ul li {
    margin:0;
    padding:5px;
    cursor:pointer;
}

Obs.: Eu dei uma garibada no CSS que achei aqui (http://webdomino.blogspot.com/2006/08/ajax-autocompletion.html). =]

Ao acessar a aplicação em: http://<seu_dominio>/cidades/add e entrar com o prefixo de alguma cidade já cadastrada no banco no campo cidade, após alguns segundos (é bem rápido, acho que não chega nem a isso) a lista é carregada automagicamente* hehe!

Veja o resultado final!



Espero que tenham gostado! Qualquer dúvida é só perguntar.

Abraço!

Helper Ajax com jQuery, ahan!

Postado por Carlitos | Tags , , , | Postado em 17:58

0

Estou numa empreitada testando o Helper Ajax nativo do CakePHP e ontem, inclusive, postei um exemplo legal de como usar o método observeField() para fazer um Select Combo de Estado e Cidade. Lembrando que o CakePHP traz esse helper que foi criado usando as bibliotecas Prototype e Scriptaculos. Daí eu pensei: - Poxa vida, bem que alguém poderia criar um Helper jQuery ou algo do tipo para o Cake... E não é que esse alguém existe, e se chama: Damian Jóźwiak. Ele disponibilizou a sua criação no Bakery com um link pro site onde tem os exemplos, download do código e até um teste de benchmark com outras bibliotecas (YUI, Dojo, etc).
Baixei o Helper Ajax do Damian e fui fazer uns testes, vejam:

Usei uma cópia da aplicação do Select Combo de Estado e Cidade, para isto basta copiar e colar a pasta app, renomeando-a, no meu caso chamei de "appjquery". A aplicação anterior eu acesso assim: "http://localhost/cake137/" e a nova eu acesso assim: "http://localhost/cake137/appjquery".

Feito isto eu extraí os arquivos: ajax.php e javascript.php para o diretório de helpers (/appjquery/views/helpers/).

Extraí também o jquery-1.4.2.min.js para o diretório /appjquery/webroot/js/.

Na minha view appjquery/views/users/add.ctp eu troquei o Prototype e o Scriptaculos pelo jQuery =P:

<?php
    //$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); 
    
    $javascript->link('jquery-1.4.2.min', false);
.
.
.

Pronto! Agora quem está fazendo o AJAX funcionar é o jQuery... e não precisei mudar nada as chamadas das funções.

Não conheço muito o Prototype, muito menos o Scriptaculos então pra mim foi muito vantajoso esse helper. Sem contar na facilidade de integração com o jQuery UI.

Bom, vi que esse helper permite muita coisa que ainda não testei. Vou começar a usá-lo a partir de agora e sempre que tiver novidades posto aqui!

Vejam as imagens dele funcionando! Ah, já ia me esquecendo... fiz um teste rápido com poucos registros e o helper nativo ainda ganha um pouco em desempenho =/... mas o jQuery lançou esta semana a sua versão 1.5 e os testes mostram uma melhora execelente principalmente para o uso do AJAX e para os navegadores Chrome e Firefox 4.



Select combo (estado + cidade) usando o Helper Ajax (observeField)

Postado por Carlitos | Tags , , | 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! =]

Expressões Regulares, um dia você precisará delas....

Postado por Carlitos | Tags , , , | Postado em 18:47

0

Opa... Eu sempre menosprezei as expressões regulares sem entender o poder delas. Elas não servem apenas para a validação de dados, como eu achava, pois com poucas coisa você consegue realizar pesquisas/verificações complexas.

Uma expressão regular é um padrão formado por simples caracteres alfa-numéricos e especiais.Ou seja, a expressão: /[aeiou]/gi, encontraria todas as vogais maiúsculas ou minúsculas em um determinado texto.

Para saber mais sobre a sintaxe eu recomendo a leitura deste artigo do iMasters, http://imasters.com.br/artigo/2515/javascript/regular_expression/, entre outros que você encontra facilmente no Google. E se quiser "treinar" os seus conhecimentos poderá utilizar o http://gskinner.com/RegExr/ para testar seus padrões.

Mas o que isso tem haver com o CakePHP? Tem muito! Não só com o Cake, mas todo programador que se preze deve conhecer o básico de expressões regulares, pois ela poupa um precioso tempo. Veja um exemplo básico de como usar expressões regulares no Cake:

O $validate aceita regras de validação customizadas onde podemos utilizar: expressões regulares ou métodos (funções). No próprio book do Cake ele dá o exemplo abaixo:

var $validate = array(
    'login' => array(
        'rule' => array('custom', '/[a-z0-9]{3,}$/i'),  
        'message' => 'Apenas letras e números, mínimo de 3 caracteres'
    )
);

Pensando assim já podemos imaginar infinitas possibilidades de validação resolvidas com as benditas Regular Expressions.

Por hoje é só, flws

jQueryUI Autocomplete no CakePHP - Agora sim!

Postado por Carlitos | Tags , , , , | Postado em 15:55

3

Dias atrás postei como usar o Autocomplete do jQueryUI no cakePHP, porém tive que fazer uma "gambiarra" pra que a opção de obter os valores via data source "funcionasse".

Bom, então depois de um help do pessoal do jquery-br vi que o arquivo que gera os resultados recebe um valor via GET através da variável "term". Com isso basta verificar quais das chaves possui o "term" (ou até aqueles que começam com "term", basta algumas alterações no código).

Agora veja a solução pronta!

1º O Controller Users (./app/controllers/users_controller.php):

<?php
/**
* @author Carlitos Fioravante
*/

class UsersController extends AppController {
  var $name = 'Users';
  var $helpers = array('Javascript');

  function autocomplete(){
    $this->set('users', $this->User->find('list', array('fields' => 'User.username')));
  }

  function list_users(){
    $this->layout = false;
    $this->set('users', $this->User->find('list', array('fields' => 'User.username')));
  }
}
?>

2º A view "autocomplete.ctp" (./app/views/users/autocomplete.ctp):
<?php
/**
* @author Carlitos Fioravante
*/

$javascript->link(array('http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js','http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js'), false);
echo $html->css('http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/themes/flick/jquery-ui.css', null, array('inline' => false));

$javascript->codeBlock('
  jQuery(function($){
    $("#username").autocomplete({
      source: "' . $html->url(array('action' => 'list_users')) . '"
    });
  });
', array('inline' => false));

echo $form->create('Users');
echo $form->input('username', array('id' => 'username'));
echo $form->end('OK');
?>

3º A view "list_users.ctp" (./app/views/users/list_users.ctp):
<?php
/**
* @author Carlitos Fioravante
*/

header('Content-type: application/json; charset=UTF-8');

$users_selecteds = array();

if(!empty($_GET['term'])){
  foreach($users as $user){
    if(strripos($user, $_GET['term']) !== false){
      array_push($users_selecteds, $user);
    }
  }
}

echo json_encode($users_selecteds);

?>


Táh aê! Espero que seja proveitoso para alguém!

Abraço,