viernes, 20 de abril de 2012

Tutorial: Ajax pagination Codeigniter // Paginación con Ajax en CodeIgniter

Hey Hola, como les va a todos, antes que nada vamos a ver el resultado final, o almenos lo que esperamos obtener al final de este articulo.

Photobucket

Como podemos apreciar, los nuevos resultados son anexados de forma asíncrona usando ajax. pretty cool x). Bueno a primera vista solo podríamos decir eso, pero si somos mas cuidadosos podemos ver una pequeña animación la cual nos indica que la consulta para los nuevos registros esta siendo procesada, ademas, el enlace de More Results es des habilitado para prevenir el caso que un usuario impaciente pueda realizar nuevamente click en el enlace si aun haberse completado totalmente la consulta anterior, nuevamente, pretty cool x). y por ultimo, cuando ya no quedan mas registros por ser retornados desde la base de datos, notificamos al usuario que no hay mas registros para mostrar.

Para lograr lo anteriormente explicado vamos a utilizar: Libreria Javascript JQuery para realizar las llamadas ajax a la base de datos. como gestor de base de datos... bueno eso es indiferente, pero como yo uso XAMPP vamos a trabajar con MySql y PhpMyAdmin. y para manejar las vistas y el acceso a la base de datos (osea el MVC) el Framework Codeigniter. creo que no se me olvida nada... bueno, y un poco de CSS.



Bueno. que es lo primero que vamos a codificar. pues en si, la lógica de las consultas, y como estamos usando el Framework Codeigniter, nos referimos al Modelo. entonces, sin perder mas tiempo, procedamos a crear un nuevo archivo en la carpeta application/models llamado (en mi caso) UserModel.php
El Modelo por el momento simplemente contendrá un método el cual recibirá dos parámetros, El máximo numero de registros retornados($limit) y el $offset, que vendría a ser como el numero desde el cual la consulta retornara registros de la base de datos. bueno, ustedes entenderán a que me quiero referir, y si no es así, cuando ejecutemos el código nos vamos a enterar :). so (8) dont worry, be happy.(8).

<?php

 // @author McCubo <-- ese soy yo xD
 // @copyright 2011
 // @license GPL V2.
class UserModel extends CI_Model {

    public function __construct() {
        parent::__construct();
    }

    // @return $limit cantidad de registros a partir de $offset
    public function getUserList($limit, $offset=0) {
        $this->db->select('id, first_name, last_name, nickname, registration_date');
        $this->db->order_by('first_name', 'asc');
        return $this->db->get('user', $limit, $offset);
    } // getUserList End

    // @return integer del total de registros en la tabla
    public function getTotalUserCount() {
        $numRows = $this->db->count_all_results('user');
        return $numRows;
    }// getTotalUserCount End

}//UserModel End

?>//FILE END

Bastante sencillo no?. indicamos que campos necesitamos retornar con la consulta (ya que no quiero mostrar la password, tipo de privilegios, edad y otros campos que no son relevantes). los ordenamos por nombre ascendente y retornamos los valores encontrados por la consulta.

Luego la otra función es aun mas sencilla, simplemente retornamos cuantos registros existen en la tabla (es importante conocer cuantos registros tiene la tabla a la hora de configurar la paginación) Ahora, ya teniendo los métodos en el modelo, guardemos, y dejemos en segundo plano ese archivo para proceder con... no se, déjenme pensarlo, no se si el controlador o la vista. si, vamos a empezar con el controlador. Entonces procedemos a crear un nuevo archivo php llamado (en mi caso) UserController.php en la carpeta application/controllers. justo ahora vamos a crear el método index:
<?php
 // @author McCubo <-- otra vez yo...
 // @copyright 2011
 // @license GPL V2.
class UserController extends CI_Controller {
    private $limit = 1;

    public function __construct() {
        parent::__construct();
        $this->load->model('UserModel');
        $this->load->library(array('form_validation', 'table', 'session', 'encrypt'));
        $this->load->helper(array('security', 'form'));
    } // End Construct

    public function index() {
        $data['userList'] = $this->UserModel->getUserList($this->limit);
        $data['limit'] = $this->limit;
        $data['totalCount'] = $this->UserModel->getTotalUserCount();
        $this->load->view('user/userView', $data);
    } // End Index

    public function user_ajax_pag($offset) {
       // Empty. not implemented yet
    }
}// End Controller
?> // End File

En el Constructor, lo normal, la llamada al constructor de la clase padre, cargamos el modelo, librerias y helpers que vamos a necesitar en todo el controlador.

Mientras tanto en el index, llamamos al método que nos devuelve la lista de usuarios, si el $offset es enviado como parámetro a la función, entonces este es 0 (Cero.) ya que necesitamos regresar desde el primer registro de la tabla, hasta un numero de $limit. Luego cargamos una nueva vista (que aun no hemos creado) y le pasamos un arreglo el cual contiene dos posiciones.

Y Creamos una función user_ajax_pag (vacia por el momento), la cual es la que vamos a llamar desde la vista. dicha funcion nos retornara de forma asincrona los registros de las consultas.

Bueno dejemos este otro archivo tambien en segundo plano para crear uno nuevo llamado userView.php (en el directorio application/views/user) en el cual vamos a desarrollar la vista, osea la paginación, como podemos ver en el gif de arriba, dicha tabla tiene dos imagenes (que suponen eliminar y editar). pues esas columnas por el momento las vamos a olvidar paracentrar nuestra atención en la cuestión de la paginación.
La vista inicial:
Codeigniter Ajax Pagination

Como podemos suponer, userList será el div contenedor de la tabla. y la etiquita script que esta vacia, en ella se ejecutara la llamada al método que nos retornará los nuevos registros (que es el método vacio del controlador user_ajax_pag). Bueno antes que nada, vamos iniciar con una pequeña condicional, si no existen registros en la tabla, mostramos el mensaje correspondiente en lugar de la tabla:

        
  <div id="userList">
      <?php if ($totalCount == 0) : ?>
           <h3>No Records Found</h3>
      <?php else: ?>
           // Generamos la tabla
      <?php endif; ?>
  </div>

Entonces, vamos a proceder a seguir editando la vista, en especifico a generar la tabla
    <body>
        <div id="userList">
            <?php if ($totalCount == 0) : ?>
                <h3>No user to display</h3>
            <?php else : ?>
                // Generamos la tabla
                <?php $this->table->set_heading('User Id', 'First Name', 'Last Name', 'NickName', 'Registration Date'); ?>
                <?php $template = array('table_open' => '<table border="1" cellpadding="1" cellspacing="0" class="stripeTable" style="width:500px;"'); ?>
                <?php $this->table->set_template($template); ?>
                <?php foreach ($userList->result() as $user) : ?>
                    <?php $this->table->add_row($user->id, $user->first_name, $user->last_name, $user->nickname, $user->registration_date); ?>
                <?php endforeach; ?>
                <?php echo $this->table->generate(); ?>
                <div id="div_more" class="div_more_pag"><a href="#">More Results</a></div>                
            <?php endif; ?>
        </div>
    </body>

Entonces si nos vamos a nuestro navegador y escribimos la url para nuestro controlador. si tenemos uno o mas registros en la tabla de la base de datos, entonces obtendremos algo como esto:


o si No tenemos registros:

Bueno, Llegamos a este punto, guardamos todos los cambios en este archivo y nos regresamos al controlador, y vamos a implementar el método user_ajax_pag.
    public function user_ajax_pag($offset) {
        // Lista con los Nuevos registros
        $userList = $this->UserModel->getUserList($this->limit, $offset);
        $data['userList'] = $userList;
        // Vista que simplemente nos retorna una tabla en formato HTML con los nuevos registros de la consulta
        $newTable = $this->load->view('user/ajax/userList_pagination', $data, true);
        $returnedData = array('newtable' => $newTable);
        // Codificamos a formato json (que es lo que vamos a esperar en la vista)
        $json_encode = json_encode($returnedData);
        // para que se note un poco mejor la animacion. deberia de ser removido una vez puesto en produccion
        sleep(1);
        echo $json_encode;
    }

Ahora vamos a ver la vista userList_pagination.php, la cual se almacena en: application/views/user/ajax
<?php
    foreach ($userList->result() as $user) {
        $this->table->add_row($user->id, $user->first_name, $user->last_name, $user->nickname, $user->registration_date);
    }
    echo $this->table->generate();
?>

Eso seria todo por parte del Controlador, entonces guardamos y nos regresamos a la vista.
Agregamos código entre las etiquetas de <script> que dejamos anteriormente sin implementar, y dicho código nos quedara parecido a lo siguiente:

           $(document).ready(function() {
                // variable enviada desde el controlador
                var totalCount = "<?php echo $totalCount; ?>";
                // variable enviada desde el controlador
                var limit = "<?php echo $limit; ?>";
                var controller =  "<?php echo site_url("userController/user_ajax_pag/"); ?>";
                limit = parseInt(limit);
                var counter = limit;
                $("#div_more a").click(function() {
                    var methodUrl = controller+"/"+counter;                                        
                    $.ajax({
                        type: "POST", // Indicamos que método se utilizará para la petición
                        url: methodUrl, // Método a ejecutarse
                        dataType: "json", // Tipo de respuesta esperada
                        beforeSend: function() {                            
                            $("#div_more").toggleClass("div_more_pag loadingAjaxClass");
                        },
                        success: function(data) {
                            // Si ningun error es arrojado obtenemos el HTML que contiene la nueva tabla, osea todos las etiquetas <tr>
                            var newRecords = $("tbody", data.newtable).html();
                            // Obtenemos la tabla y despues de la ultima fila agregamos N numero de filas devueltas por la consulta
                            $("table tr:last").after(newRecords);
                            // Creamos el estilo tipo Zebra para la tabla
                            createTableStyle();
                            // Aumentamos el counter, que lo podemos ver como el offset de la proxima consulta
                            counter += limit;
                        },
                        complete: function() {
                            $("#div_more").toggleClass("div_more_pag loadingAjaxClass");
                            if (counter >= totalCount) {
                                $("#div_more a")
                                    .text("No More Results to show...") // Cambiamos el texto del enlace
                                    .css("pointer-events", "none") // deshabilitamos el enlace
                                    .css("color", "#CCC"); // Cambiamos color del enlace
                            }
                        }
                    });
                    return false;
                });  // End link More Result Click event
           }); // End Jquery document.ready

Agregamos la referencia a la hoja de estilo en el header
<link rel="stylesheet" href="<?php echo base_url("css/main.css"); ?>" >

Y dicha Hoja de estilo es la siguiente:
.div_more_pag, .loadingAjaxClass{
    text-align: center;
    margin-top: 10px;
    padding-top: 7px;
    height: 28px;
    width: 500px;
    background: #E0F2F7;
    border: 1px solid #000;
}

.div_more_pag a, .loadingAjaxClass a {
    text-decoration: none;
}

.div_more_pag a{
    color: #000;
}

.loadingAjaxClass a {
    color: #CCC;
    pointer-events: none;
    cursor: default;
}

.div_more_pag a:hover {
    color: #610B0B;
}

.loadingAjaxClass {
    background: #fff;
    background-image: url("images/loading.gif");
    background-repeat: no-repeat;
    background-position: right;
}

Bueno, espero no se me olvide nada y si les gusta comenten, si no les gusta compartan x).
Ojala les funcione, cualquier duda o comentario pueden hacerlo escribiendo en este post o a mi cuenta personal de google (gmail) y vamos a tratar de solucionar o aclarar cualquier cuestión del tema

Suscribanse al blog o háganse seguidores demi cuenta de twitter para enterarse de los nuevos post que, ojala el tiempo y Dios lo permitan,  estaré publicando :D
Saludos y Cuídense. 

14 comentarios:

  1. deberias colgar los archivos para descargarlos

    ResponderEliminar
  2. esta magnifico el tutorial, oye tengo una predunta
    como obtngo un arreglo desde una vista a un controlador, el arreglo lo creo en la vista.
    donde creo el arreglo tngo asi
    foreach ($datos as $key => $value) {
    $perfiles[] = "$value";
    echo "value";
    }
    ?
    donde datos es una arreglo que le paso a la vista desde el controlador
    y en otro controlador tengo asi
    $arreglo['datos']= $this->input->post("perfiles");
    pero ahi entonces la variable arreglo esta vacia..
    ...otra pregunta; como paso un arreglo de una vista a otra vista???

    ResponderEliminar
    Respuestas
    1. Hola, antes que nada, me alegra que el material que humildemente publico en el blog sea de tu agrado. Muchas Gracias. bueno, entrando con tu primera pregunta: "Enviar un array desde la vista al Controlador". Nunca lo había hecho (hasta ahora), y pues en una forma un poco rápida, lo primero que se me vino a la mente es enviar ese array en formato json (mediante un input tipo hidden) al controlador, y en el controlador transformarlo nuevamente a Array. Código de la vista:
      (?php $array = array('object_1', 'Object_2', 'Object_3'); ?)
      (?php
      $json_encode = json_encode($array);
      ?)
      (form)
      (input name="hiddenArray" id="hiddenArray" type="hidden" value='(?php echo $json_encode; ?)' /)
      (/form)

      CODIGO CONTROLLER:
      $post = $this->input->post('hiddenArray');
      $json_decode = json_decode($post);

      Eliminar
    2. Bueno, te separo las respuestas por cuestión de orden :).
      Y con el código anterior ya tienes tu array de la vista en el controller (usando un formulario, usando un botón submit o un enlace con una llamada $.ajax de jQuery, $("form").serialize() en el parámetro data..
      tu otra pregunta: "como paso un arreglo de una vista a otra vista???". bueno, ya teniendo el array en tu controlador, lo unico que debes de hacer es crear un array el cual contenga tu array y pasarlo como parametro a la vista
      $data = array(
      'array' => $json_decode; #tomando como ejemplo el código de la respuesta de arriba
      );
      $this->load->view('viewRequestArray', $data);

      Espero sirva de ayuda, y dejame un feedback para saber si te ha funcionado, o almenos indicado mas o menos como hacerlo.
      suerte y saludos!

      Eliminar
  3. oye primero gracias por contestar
    pero no me salio, el arreglo al final no tiene nada

    mira creo ke no me explique bien,..

    en controlador_1 tngo asi

    load->helper('array');


    $this->load->helper(array('form','url'));
    $this->load->model('colocame/M_consultas_bd'); //cargar el modelo para conectarse a la bd
    $this->M_consultas_bd->conectarBD(); //se conecta a la bd


    if (isset($_POST["tipo_emp"]) && is_array($_POST["tipo_emp"]) && count($_POST["tipo_emp"]) > 0)
    {
    $arreglo['datos']=$_POST["tipo_emp"];


    $this->load->view('colocame/selecc_ciudad',$arreglo);


    }
    else {
    $this->load->view('colocame/selecc_tipo_empleo');

    }

    }
    }
    ?>


    ---en la vista selecc_tipo_empleo tengo asi
    ...
    $tipo_emp = array();

    "checkbox" name="tipo_emp[]" value ="Admon Oficina" id="e1" />
    Administración/Oficina

    "checkbox" name="tipo_emp[]" value ="art_dis_med" id="e2" />
    Arte/Diseño/Medio

    ---el arreglo tipo_empl lo obtengo en el controlador C_colocame, este arreglo si lo puedo ver, pero lo
    malo esta cuando ese arreglo lo paso a otra vista que se llama selecc_ciudad

    ---------vista selecc_ ciudad--------

    foreach ($datos as $key => $value) {
    $perfiles[] = "$value";
    echo "value";
    } //aqui si imprimo los valores que le paso.. pero los meto en el arreglo $perfiles[] y al jalar este arreglo, esta vacio. lo jalo desde el controlador c_colocame_estado



    $selecc_ciudad = array();


    "checkbox" name="selecc_ciudad[]" value ="ciudad_1" id="ciudad1" onclick = "desabilitar()" />
    Aguascalientes

    "checkbox" name="selecc_ciudad[]" value ="ciudad_2" id="ciudad2" onclick = "desabilitar()" />
    Baja California


    ---.------


    ----controlador c_colocame_edo----

    aki tengo esta linea
    $arreglo['datos']= $this->input->post("perfiles");

    que es donde jalo el valor de "perfiles" que es una arreglo. pero esta vacio..

    ...ya probe con lo que me dejaste y te lo agradesco pero no me salio.. al pasar el arreglo tambien esta vacio

    ----esto lo probe en la vista selecc_ciudad






    <-/---div>
    ------


    y asi lo puse en el controlador c_colocame_edo
    $post = $this->input->post('hiddenArray');

    $json_decode = json_decode($post);
    echo "$json_decode";
    $data = array(
    'array' => $json_decode);
    rint_r($data); no imprime nada

    ResponderEliminar
  4. oye tuve que modificar el codigo html quite input, div,..porque no me dejaba publicar..bueno espero tu reespuesta, y muchas gracias :)

    ResponderEliminar
    Respuestas
    1. Hola, pues la verdad no capto muy bien lo que estas tratando de hacer (y debido a blogger no permite poner código html ni php, como que no ayuda mucho). si quieres detalla lo que quieres hacer (sin código) para tener una idea clara de tu propósito, y así poder ayudarte de una forma mas efectiva. Si no lo quieres publicar en el blog, envíamelo a mi correo personal, yo lo reviso y hago las pruebas, si?

      Eliminar
  5. hola pues te planteo el objetivo de lo que quiero hacer...me gustaria enviarte mi codigo para que lo revises y me corrijas, pero donde esta tu correo??..bueno mira el objetivo es:
    en una vista muestro categorias de empleos (por ej hoteles, docencia...) de los cuales el usuario podra seleccionar los que quiera (checkbox) despues en otra vista se muestra unas ciudadees donde el usuario podra seleccionar las que quiera (por ejem: ciudad_1,ciudad_2)(checkbox). y esas selecciones del usuario (empleos y ciudades) me serviran para hacer la consulta a una base datos de donde mostrare los empleos que correspondan a las categorias y ciuades que el usuario a seleccionado. bueno pues ese es el objetivo, espero que me puedas ayudar y muchas gracias por tu tiempo

    ResponderEliminar
    Respuestas
    1. Hola, que interesante esta lo que vas hacer :) si así ya entiendo el punto y mas o menos me voy haciendo una idea de como lograrlo :) Pues para mi, en verdad, seria un placer ayudarte, para eso esta el blog en primer lugar, y segundo, nunca he hecho algo así, así que se gana experiencia para futuros trabajos :). pensé que mi correo era visible en Google plus, pero al parecer no, no se porque, pero bueno mi correo es cubiascaceres@gmail.com
      bueno, seria bueno que enviaras, aparte del proyecto, el script de la base de datos. No es necesario que me envíes todo el esquema, sino solo las tablas involucradas en el proceso que describís arriba (eso por si no quieres que mire todo el esquema de tu sistema, y la verdad te entenderé si así lo quieres hacer, queda a tu criterio lo del esquema)
      Espero el email y si asi lo deseas, comunicarnos por ese medio a partir de ahora :). Saludos!

      Eliminar
  6. hola, pues te envie codigo y el scrip de la base de datos que uso, te lo envie con el asunto: codigo_ayuda bueno espero tu respuesta. y muchas gracias

    ResponderEliminar
  7. hola!!. pues quiero agradecerte por la ayuda que me as proporcionado!! :) estoy muy agradecido contido!! me as salvado la vida!!!. gracias por compartir tus conocimientos. gracias por los codiggos que publicas!!. tienes un gran blog!! muy interesante!!....bueno pues saludos desde méxico! :)

    ResponderEliminar
  8. sigue publicando!! ayudas a muchos como yo !!! :) y te lo agradecemos!! :)

    ResponderEliminar
  9. hola q tal muy bueno el ejemplo me servio ..pero que pasa si tengo varios datos ..como seria hacer una paginacion que muestre 10 primeros datos(1-10) ..luego muestre los otros 10(11-20) ..pero los anterios 10(1-10) ya se no se muestren

    ResponderEliminar