lunes, 20 de febrero de 2012

Datepicker reutilizable


Ya había mencionado que mi objetivo principal era desarrollar funciones y componentes que sean reutilizables y fáciles usar, a continuación voy a tratar de mejorar el componente ui de jquery para que pueda conectarse directamente con una tabla de la base de datos, en el ejemplo anterior en nombre de la tabla que se usó es historial, pero que pasaría si queremos usar este componente en otro proyecto tendríamos que hacer cambios cada vez y puede ser que ya la tabla no se llame historial inclusive el nombre del campo puede variar, para eso pensé en crear un modelo "genérico" que reciba cualquier nombre de tabla y campo, se conecte a la bd y que obtenga los datos necesarios, lo llamaré generic_model, nos servirá para posteriores ejemplos al cual iremos añadiendo nuevas funcionalidades.             

application/models/generic_model.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
class Generic_model extends CI_Model {

    function __construct() {
        // Call the Model constructor
        parent::__construct();
    }
/**
* Obtiene los registros de un campo de una tabla de la base de datos
* @param  $nombre_tabla  El nombre de la tabla
* @param  $nombre_campo  El nombre del campo de la tabla
*/
    function get_datos($nombre_tabla,$nombre_campo) {
        // SQL equivalente a SELECT $nombrecampo FROM $nombre_tabla;
        $this->db->select($nombre_campo);
        $this->db->from($nombre_tabla);
        $query = $this->db->get();
        return $query->result();
    }

}




Como se puede observar la función get_datos($nombre_tabla,$nombre_campo) acepta 2 parámetros que recibimos por medio de nuestro controller, y gracias a las funciones de la clase Database de codeigniter obtenemos el equivalente al código sql SELECT $nombrecampo FROM $nombre_tabla;
He conseguido que el modelo sea "mas genérico" ya que ahora el nombre de la tabla es variable y también del campo.

A continuación hacemos los correspondientes cambios al controller en la función datos_dp,  esencialmente recibe de la vista los datos correspondientes al nombre de la tabla y del campo que son enviados por ajax usando los métodos de la clase input de codeigniter vease manual , casi es el mismo código al ejemplo anterior.


application/controllers/dp.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
class Dp extends CI_Controller {

    public function __construct() {
        parent::__construct();
        // cargamos nuestro base de datos ahora lo hacemos por defecto
        $this->load->database();
        }

    public function index() {
        // en este caso queremos que la vista haga las peticiones no el controller
        // cargamos nuestra vista
        $this->load->view('dp_view');
    }

    public function datos_dp() {

        $tabla = $this->input->post('tabla'); //el nombre de la tabla de la bd
        $campo = $this->input->post('campo');//el nombre de campo de la tabla
        $this->load->model("Generic_model");// cargo mi modelo generico
         // le envio el nombre de la tabla y el campo al modelo a travez de get_datos
        $datos['query'] = $this->Generic_model->get_datos($tabla, $campo);
        // codificamos el array a json usando json_encode mirar manual de php
        $data_json = json_encode($datos);
        // enviamos el json a la vista
        echo $data_json;
 
    }

}

En las lineas que contienen $this->input->post('tabla')  y    $this->input->post('campo') las variables tabla y campo provienen de la vista, específicamente del html, explicaré esto más adelante, pero ya se puede ver que todo se vuelve un poco más parametrizado

Los cambios son mas amplios en el javascript, ya que creamos una función que podemos reutilizarla las veces que consideremos necesarias.

js/dp.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 /*
 * La lógica por parte del cliente usando jquery
 */

jQuery(document).ready(function(){
    
    datepicker("#datepicker"); // ejemplo de uso de la función datepicker


/**
* La función datepicker crea un datepicker logico no?
* @param $id_input  Es el id del input que se convierte en datepicker
*/

  function datepicker($id_input){

     //creamos el datepicker
    $($id_input).datepicker({
        dateFormat: "dd/mm/yy"
    });

    var nombre_tabla = $($id_input).attr("tabla");
    var nombre_campo = $($id_input).attr("campo");
    
    var json_conf_dp = {
        tabla:nombre_tabla,
        campo:nombre_campo
    };
    $.ajax({
        type: "POST",
        url: "dp/datos_dp",
        data: json_conf_dp,
        success: function(msg){
            var datos = $.evalJSON(msg);// se convierte de json a un objeto javascript
              $( $id_input ).datepicker('setDate', datos.query[1][nombre_campo]);
        }
    });




  }

});// fin de ready function
Si miramos más adelante en el código html de nuestra vista en la linea <input id="datepicker" type="text" tabla="historial" campo="fecha">  , se puede observar que he añadido 2 nuevos atributos inventados por mi a la etiqueta input, aunque no es estándar del html nos ayudará a definir si nuestro input se va a convertir en un datepicker, ya que estos dos atributos contienen la relación entre el datepicker y la tabla de la base de datos, es decir el nombre de la tabla y el campo, esta es la manera de "conectar" mi código html con mi base de datos, se puede hacer de la misma forma para otros componentes, todo depende de lo que se necesite.
Estas dos lineas en mi javascript var nombre_tabla = $($id_input).attr("tabla"); y  var nombre_campo = $($id_input).attr("campo"); obtienen el valor de los atributos de mi input que en este caso se contienen el valor historial y fecha respectivamente que luego son pasados por medio de un objeto json json_conf_dp a la función ajax. 
Luego dentro de mi función ajax el siguiente código $('#datepicker').datepicker('setDate', datos.query[1][nombre_campo]);  asigna la fecha a mi datepicker por medio del parámetro datos.query[1][nombre_campo] que contiene nuestra fecha obtenida de la base de datos.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<!doctype html>
<html lang="es">
    <head>
        <link type="text/css" href="../js/css/smoothness/jquery-ui-1.8.17.custom.css" rel="stylesheet" />
        <script type="text/javascript" src="../js/jquery-1.7.1.min.js"></script>
        <script type="text/javascript" src="../js/jquery-ui-1.8.17.custom.min.js"></script>
         <script language="JavaScript" type="text/javascript" src="../js/jquery.json-2.3.min.js"></script>
        <script type="text/javascript" src="../js/dp.js"></script>
    </head>
    <body>
    <div>
    <input id="datepicker" type="text" tabla="historial" campo="fecha">
    </div>
    </body>
</html>

Al final puedo poner tantos datepickers como quiera a mi vista pero tengo que tener en cuenta ciertos detalles, el id del input debe ser único, además también tengo que llamar a la función por cada datepicker de la siguiente manera

datepicker("#datepicker1"); // ejemplo de uso de la función datepicker
datepicker("#datepicker2"); // ejemplo de uso de la función datepicker

Aunque todavía nos toca escribir un poco de código es mucho mejor que con el ejemplo anterior ya que lo he reducido a 2 lineas, imagínate que tuvieras que incluir 10 datepickers cuanto código se necesitaría, con esta función solo se necesitaría 10 lineas y por supuesto reutilizar la función datepicker.
Aunque sería interesante que no tuviéramos que cambiar el javascript para nada y solo añadiéramos nuestros inputs al html  de  nuestra vista y se creara automáticamente los datepicker, como se podría lograr ?
La primera forma que se me ocurre es utilizando los parámetros extras que le incluimos al input
<input id="datepicker" type="text" tabla="historial" campo="fecha">  que son tabla y campo, la función debería detectar si cada input en mi vista contiene estos dos campos, si los contiene entonces que cree nuestros datepicker con conexión a nuestra base de datos.
La segunda forma es crear nuestra propia etiqueta que se llame por ejemplo datepicker, la función debería detectar y crearlos automáticamente,  el html quedaría así <datepicker id="datepicker1" tabla="historial" campo="fecha"> además de ser semánticamente mas correcto, visualmente podríamos detectar más rápidamente dentro de nuestro código cual es un input ordinario y un datepicker, si se confundieron aquí lo aclararé implementando esta parte en el siguiente artículo :)


Todo esto se puede mejorar añadiendo más funcionalidad a mi componente, por ejemplo además de que obtenga una fecha de la bd se puede intentar actualizar un campo de dicha tabla o agregar una fecha, etc..







No hay comentarios:

Publicar un comentario