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,

jQueryUI Autocomplete no CakePHP

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

0

Então... um colega nosso do grupo cakephp-br entrou em contato comigo via MP perguntando como utilizar o autocomplete do jQueryUI no CakePHP. Topei ajudá-lo e já aproveitei para conhecer as novidades do Cake 1.3.2.

Bom, depois de quebrar um pouco a cabeça com as mudanças na forma de invocar o JavaScript, entre outras mudanças neste novo cake, cheguei a uma solução que eu não recomendo para o caso em que o campo a ser listado do BD tenha muitos registros. E pensando bem um campo autocomplete é sempre mais indicado nestas circunstâncias mesmo, por exemplo para autocompletar um nome de um produto (de uma lista já predefinida, normalmente não muito grande), de uma cidade, etc.

Primeiramente vamos ver o que o jQueryUI diz a respeito do Autocomplete.

1) Na opção "default" o Autocomplete pode ser gerado a partir de uma lista de "tags" pré-definidas em um Array passado à variável "source" da função, assim:

$(function() {
  var availableTags = ["c++", "java", "php", "coldfusion", "javascript", "asp", "ruby", "python", "c", "scala", "groovy", "haskell", "perl"];
  $("#tags").autocomplete({
    source: availableTags
  });
});

2) Outra opção é obter este Array de tags através de uma página que retorne um array no formato JSON, assim:
$(function() {
  $("#tags").autocomplete({
    source: "search.php"
  });
});
Como os dados estão numa tabela do BD o ideal seria usar a 2ª opção, porém não consegui utilizá-la. Criei uma página que gerava o array no formato JSON (Ex.: ["c++", "java", "php", "coldfusion", "javascript", "asp", "ruby", "python", "c", "scala", "groovy", "haskell", "perl"]), porém o autocomplete "puxava" todos os elementos como se fossem um só, ou seja, se eu começava a digitar "a" ele me mostrava todas as opções do Array e não apenas aquelas que continham o caractere "a".

Bom, parti para a 1ª opção então. Dentro do meu controller eu criei a action "autocomplete" e nela eu busco todos os registros que quero para o meu campo "autocompletável" :D, assim:
function autocomplete(){
  $this->set('users', $this->User->find('list', array('fields' => 'User.username')));
}

Obs.: No meu caso estou usando uma tabela "Users" que possui um campo "username".

Já na view "autocomplete.ctp" eu estou recebendo a variável $users, que vem com um Array da seguinte forma:
Array
(
  [1] => a1_teste@teste.com
  [2] => a2_teste@teste.com
  [3] => outro_nome_de_teste@teste.com
   .
   .
   .
)

e então crio uma String com o formato array do JSON, desta forma:
$usernames = '[';

foreach($users as $user)
  $usernames .= '"' . $user . '",';

$usernames .= ']';

Então temos o seguinte código para a view:
<?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)); // Tema do Flickr, hehe :D

$usernames = '[';

foreach($users as $user)
  $usernames .= '"' . $user . '",';

$usernames .= ']';

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

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

debug($users);
?>

Bom, não é a solução perfeita mas funcionou! Ainda estou a procura dela...

Veja a solução correta aqui nesse novo post!

Abraço,