lunes, 28 de marzo de 2011

Tutorial: Jquery UI autocomplete y Codeigniter

Después de un buen tiempo sin escribir por exceso de trabajo, vuelvo con el tutorial prometido de como usar jquery UI autocomplete con codeigniter, es muy sencillo. Para comenzar vamos a necesitar tener las librerías de jquery ui que se pueden descargar de la pagina oficial: aqui!, podemos descargar un tema si queremos(yo descargue darkhide) , y por supuesto tener codeigniter.

Paso 1: Preparando el terreno.

Primero tenemos que crear un controlador que yo le voy a llamar autocomplete, una vista con el mismo nombre y una base de datos de usuarios que se van a mostrar.

En el código del controlador debemos por ahora agregar la carga de nuestra vista y la carga de el driver para base de datos y el  uri helper que nos ayudara.

Código de controlador inicial:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Autocomplete extends CI_Controller {
    function __construct()
    {
        parent::__construct();
        $this->load->database();
        $this->load->helper('url');
    }
    public function index()
    {
        $this->load->view('autocomplete');
    }
}

/* End of file welcome.php */
/* Location: ./application/controllers/autocomplete.php */

En el código de vista solo debemos poner el enlace a el css y js de jquery ui, para facilitarnos la vida nos ayudaremos con la función base_uri que nos permitirá darle una ruta absoluta.

Código vista:

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
        <title>jQuery UI Autocomplete Ejemplo</title>
        <link type="text/css" href="<?php echo base_url(); ?>css/dark-hive/jquery-ui-1.8.10.custom.css" rel="stylesheet" />    
        <script type="text/javascript" src="<?php echo base_url(); ?>js/jquery-1.4.4.min.js"></script>
        <script type="text/javascript" src="<?php echo base_url(); ?>js/jquery-ui-1.8.10.custom.min.js"></script>
        <script type="text/javascript">
        </script>
    </head>
    <body>
    
    </body>
</html>

Y por ultimo crearemos una pequeña Base de datos de usuarios con solo un id y nombre de usuario, así:

CREATE TABLE `autocomplete`.`usuarios` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`user` VARCHAR( 80 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL
);


INSERT INTO `usuarios` (`id`, `user`) VALUES
(1, 'mariano'),
(2, 'jose'),
(3, 'juan eduardo'),
(4, 'juan pedro'),
(5, 'no se uqe'),
(6, 'no se uqe mas'); 


Lo ultimo de este paso es configurar nuestra base de datos y ya debería cargar una pagina en blanco.

Paso 2: Configurando nuestra vista con autocomplete.

Ahora debemos configurar en la vista el autocomplete, solamente debemos agregar en el cuerpo un input text, y dentro de las etiquetas script la configuracion del autocomplete que va a ser referencia a una función que despues crearemos en nuestro controlador que se llamara ajax. Asi nos debería ir quedando la vista:
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
        <title>jQuery UI Autocomplete Ejemplo</title>
        <link type="text/css" href="<?php echo base_url(); ?>css/dark-hive/jquery-ui-1.8.10.custom.css" rel="stylesheet" />    
        <script type="text/javascript" src="<?php echo base_url(); ?>js/jquery-1.4.4.min.js"></script>
        <script type="text/javascript" src="<?php echo base_url(); ?>js/jquery-ui-1.8.10.custom.min.js"></script>
        <script type="text/javascript">
        $(document).ready(function(){
            $('#autocomplete').autocomplete({source:'<?php echo site_url('autocomplete/ajax'); ?>'});
        });
        </script>
    </head>
    <body>
    <p><label for='autocomplete'>Nombre de Usuario: </label><input type='text' id='autocomplete'></p>
    </body>
</html>
Paso 3: Empezando con el controlador.(Input Class)

En el controlador debemos crear una función llamada ajax que sera la encargada de enviar en formato json los datos para el autocomplete, para esto vamos a usar el Active Record Class de Codeigniter y el input class.

El codeigniter trae una clase ya echa y precargada para lo que son los input, esta libreria incluye funciones muy utiles:
  1. Pre-procesa todas las variables de entrada por seguridad.
  2. Provee algunas funciones para procesar las variables enviadas y pre-procesarlas.
Esta libreria nos provee una función que se llama $this->input->get(), esta función permite dos parametros el primero es para saber que variable de $_GET requerimos y el segundo establecer el filtrado en true(activado) o false(desactivado). La otra ventaja de esta función es que no nos va a dar error si nuestra variable no fue definida, ya que si la variable no fue definida devuelve un false. en nuestro caso agregariamos lo siguiente al código:
if($buscar=$this->input->get('term'))
{ 
} 
Paso 4: Usando Active Record Class para buscar en la base de datos.

Continuamos con el active record class, esta clase trae funciones para seleccionar, insertar, eliminar y modificar ya predefinidas que nos pueden ahorrar muchas lineas de código ademas de que con estas funciones ya todo va pre-filtrado contra posibles ataques.

lo primero es ver la función basica de select, $query=$this->db->get('usuarios') esta función haria simplemente un "select * from usuarios" y devuelve un objeto en $query. Como queremos buscar dentro de user los usuarios que tengan un nombre parecido a el termino de busqueda, debemos usar la función $this->db->like(), que recibe dos parametros, en uno la columna en la que deseamos buscar y el otro lo que deseamos buscar. Y por ultimo usaremos la funcion $this->db->select(), para poder especificar que columnas queremos y como las queremos: a la final nuestra funcion nos quedaria asi:

        $this->db->select('id, user as value');
        $this->db->like('user', $buscar); 
        $query=$this->db->get('usuarios');

Que generaria algo asi "SELECT `id`, `user` as value FROM (`usuarios`) WHERE user` LIKE '%$buscar%'"

Ahora solo debemos verificar que la respuestasea mayor que 0, pero en ves de usar el clasico mysql_num_rows usaremos $query->num_rows() > 0, y  para listar los resultados en ves de while ($row = mysql_fetch_array($result) ) usaremos foreach ($query->result_array() as $row). y por ultimo usamos la funcion json_encode para pasar nuestro array al formato json.

Condigo de la funcion ajax():
function ajax()
    {
        if($buscar = $this->input->get('term'))
        {
            $this->db->select('id, user as value');
            $this->db->like('user', $buscar); 
            $query=$this->db->get('usuarios');
            if($query->num_rows() > 0)
            {
                foreach ($query->result_array() as $row)
                {
                    $result[]= $row;
                }
            }
            echo json_encode($result);
        }
    } 

Con esto ya queda listo nuestro autocomplete solo queda probarlo.

Nota:
  • Si usan php 5 pueden usar el Method Chaining que les permite hacer los select en una sola linea.
  • Es buena idea limitar el numero de filas que vamos a devolver con agregar $this->db->limit(10); es suficiente.
  • Este metodo devulve el id de el usuario a el autocomplete, podemos agregar al autocomplete el siguiente codigo para usar en algo esa info:

    select: function( event, ui ) {
    alert(ui.item ?
    "Selected: " + ui.item.id :
    "Nothing selected, input was " + this.value );
    }


El resultado final esta en esta dirreccion: http://www.box.net/shared/agnursjr8n

23 comentarios:

  1. Hola!

    Antes que nada agradecerte el aporte, la verdad es que (rotura de cabeza de darle vueltas al margen) me parece MUY BUENO, muchas gracias!!!

    Te comento => yo estoy utilizando CI 1.7.algo (creo que 3). El caso es que tomando los datos del zip tal cual desde netbeans y conectando mi db funciona de maravilla. El problema es que lo tengo que aplicar a un proyecto que está, como he dicho antes, en CI 1.7.x. Soy bastante negada (estoy empezando) en ajax/jquery y le llevo dando vueltas a cómo debo variar el código para que pueda aplicarlo al proyecto.

    Podrías echarme un cable? Siento las molestias y de nuevo, muchas gracias :)

    ResponderEliminar
  2. hola me alegra que te se de ayuda el tutorial, si quieres adaptarlo a Codeigniter version 1.7.x simplemente creas en tu proyecto un nuevo controlador, o dentro de un controlador ya existente, pones la funcion ajax igual como esta, y cambias en la vista la ruta de source del autocomplete a donde ubicaste la funcion.

    Si sigues teniendo problemas me puedes dejar otro comentario.

    ResponderEliminar
  3. Hola de nuevo!

    Lo primero, muchas gracias por contestar, y por hacerlo tan rápido :)

    Ayer ya probé a hacer lo que me comentabas, y hoy, por si acaso lo he vuelto a hacer (pensando en que ayer, con la saturación que llevaba igual había cometido un error), pero nada.

    He echo estos pasos =>
    1) He creado un controlador nuevo en un archivo 'completar.php' de la carpeta de controladores, con este código :

    database();
    $this->load->helper('url');
    }}

    public function completar(){
    if($buscar = $this->input->get('term'))
    {
    $this->db->select('id, user as value');
    $this->db->like('user', $buscar);
    $query=$this->db->get('usuarios');
    if($query->num_rows() > 0)
    {
    foreach ($query->result_array() as $row)
    {
    $result[]= $row;
    }
    }
    echo json_encode($result);
    }}}

    ?>


    2- En el controlador que carga el index, he borrado todas las vistas que se ven, salvo la del .php que guarda el autocomplete, para evitar que se cargaran el resto de los js que tengo (nos obligan a poner ibox, lightbox y rotator :S). De esta forma el index del proyecto carga directamente el pruebacompletado.php donde esta ese autocomplete.

    3- En ese archivo, he cambiado, como me comentabas, el source:

    $('#autocomplete').autocomplete({source:''});

    He revisado por si acaso con el firebug para ver que la url que carga es la correcta:

    '{source:'http://localhost/proyectodeprueba/index.php/completado/completar'}

    Aparentemente está bien.

    Y nada, no va ¿¿?? No sé, es posible que al tener la configuración de las carpetas de manera diferente entre 1.7 y 2.0 no carguen algunas de las rutas bien? Es raro que tomando lo que es el código de ejemplo como una carpeta simple en Netbeans y conectándola a mi BD vaya de maravilla (en serio, GENIAL! :) y al aplicarlo en el proyecto de CI no vaya.

    De nuevo MUCHAS GRACIAS! :)

    ResponderEliminar
  4. Pongo de nuevo el código del controlador, que al añadirlo directamente con la marca del php me ha borrado un trozo, siento la molestia :o)

    class Autocomplete extends Controller{
    public function __construct(){
    parent::__construct();{
    $this->load->database();
    $this->load->helper('url');
    }
    }



    public function completar(){
    if($buscar = $this->input->get('term'))
    {
    $this->db->select('id, user as value');
    $this->db->like('user', $buscar);
    $query=$this->db->get('usuarios');
    if($query->num_rows() > 0)
    {
    foreach ($query->result_array() as $row)
    {
    $result[]= $row;
    }
    }
    echo json_encode($result);
    }
    }

    }


    ?>

    ResponderEliminar
  5. bueno, si revisas con el firebug, te debe salir el codigo json con los datos, si te sale te aconsejo que actualizes el jquery a la ultima version, sino el problema es que el sistema no consigue datos en la base de datos.

    ResponderEliminar
  6. Solo quería felicitaros por el blog. Lo acabo de encontrar y va directo a mi lector de Feeds.

    Me estoy iniciando con el CI y estaba buscando desesperadamente como hacer un autocomplete con jQuery UI. A ver si me acaba de salir bien.

    :)

    ResponderEliminar
  7. hola ante todo gracias por el tutorial me sirvio de mucho pero tengo una duda como hacer para validar que el usuario ingrese un dato de la lista he visto metodos search y result en la documentacion de jqueryUi pero no le atino conoces como hacerlo gracias de atemano

    ResponderEliminar
  8. hola, hace tiempo lo hice, pero ahorita no me acuerdo bien, lo voy a buscar y cuando lo consiga lo pondre un post sobre el tema.

    ResponderEliminar
  9. Buenas, a mi en FireBug me da Page not found debido a que CI no admite parametros via GET, a no ser que Query_strings se habilite y no deseo habilitarlo. Hay alguna forma de hacerlo funcionar de todas maneras? Gracias.

    ResponderEliminar
  10. hola chamo, revisa en este tutorial: http://sosinformatico.blogspot.com/2011/03/tutorial-jquery-ui-autocomplete.html en la ultima parte explico como pasar parametros por post al php. Seguramente eso te va a servir.

    ResponderEliminar
  11. chamo sabras como hacer los combos dependiente es decir el clasico estado municipio parroquia

    ResponderEliminar
  12. Buenas, primero que nada gracias por el aporta ya que me sirvio y anda perfecto. Estoy usando CI 2.1
    El tema es que quiero hacer el automplete en varios Inputs del mismo formulario y no me anda.
    Probe que funcione con inputs de clase autocomplete en vez de ID para no tener id's repetidos pero solo el primero toma el autocomplete.
    Tenes alguna idea de cual puede ser el error?
    Gracias

    ResponderEliminar
  13. bueno, realmente no se, nunca lo e probado. pero yo te recomiendo que agarres y crees un objeto con todos los parametros que quieres pasar, y despues haces 3 autocomplete y le pasas ese objeto, sino lo quieres hacer asi, pues abres con firebug revisas a ver si te da error y me dices cual es el error.

    Si tienes alguna duda, pues solo publica otro comentario.

    ResponderEliminar
  14. muy buen ej me funciona muy bien pero ahora pregunto como puedo mostrar los datos que quisiera en mi pagina??, o sea mostrar los datos de mi tabla en mi pagina web en html??? por favor si alguien me puede ayudar mil gracias

    saludos

    ResponderEliminar
  15. No estoy muy claro con tu pregunta, pero sera que quieres hacer esto?: http://sosinformatico.blogspot.com/2011/12/jqgrid-un-grid-para-jquery.html

    Sino explicate un poco mejor.

    ResponderEliminar
  16. bueno ante nada muchas gracias por responder,
    le explico mejor yo estoy haciendo un buscador o sea que me busque en mi base datos y me muestre en mi pagina los resultados en html o sea yo busco por una palabra y me sale todos los resultados en html de esa palabra

    bueno gracias nuevamente

    ResponderEliminar
  17. hola ve, tienes dos opciones, una es usar el evento select de jquery ui autocomplete, y cuando la gente seleccione el que quiere, pues lo mandas ha mostrar la información abajo. Si quieres puedes ver este ejemplo en la pagina de jquery UI http://jqueryui.com/demos/autocomplete/#custom-data.

    Si esa no te sirve, pues me preguntas por la otra manera despues.

    ResponderEliminar
  18. gracias lo voy a probar y despues le digo y le comento pues lo unico que tengo que mostrar los datos de mi base datos por que su ej de autocomplete funciona perfectamente

    gracias nuevamente, despues le comento

    gracias

    ResponderEliminar
  19. nada amigo no he podido mostrar los datos se que hay algo que estoy haciendo mal, le explico yo estoy haciendo un buscador normal sencillo pero que me busque en la base datos y me muestre los resultados, es eso, estoy trabajando con Codeigniter, por ej yo busco vinos y me muestra en una pagina todos los vinos por decir un ej, bueno gracias nuevamente
    saludos

    Alberto

    ResponderEliminar
  20. mandame el codigo para verlo, lo puedes publicar aqui, o me lo mandas a mi correo. marianoramirez353@gmail.com

    ResponderEliminar
  21. gracias, gracias senor se lo enviare por su correo creo que sera mejor y despues lo posteo aqui

    gracias

    ResponderEliminar
  22. Muchas gracias por tu aporte me va a servir de mucho

    ResponderEliminar