Aplicación CRUD con Vue.js y Codeigniter, Segunda parte

1 May

Bueno, continuando con nuestro ejemplo de cómo realizar un sistema CRUD con Vue.js y Codeigniter, vamos a finalizar mostrando cómo desarrollar la funcionalidad del frontend.

Primero nos dirigimos a application/views/tareas, abrimos el archivo “index.php” y vamos a agregar el siguiente código:

<html>
<head>
   <meta charset="utf-8" />
   <title> Lista de tareas </title>
   <link rel="stylesheet" type="text/css" href="<?php echo base_url() ?>css/bootstrap.min.css" />
   <link rel="stylesheet" type="text/css" href="<?php echo base_url() ?>css/bootstrap-responsive.min.css" />
</head>
<body>
   <div class="container">
      <h1> Lista de tareas </h1>
      <form action="javascript:void(0);" id="controlador_tareas">
         <div v-if="cargando_tareas">
            Cargando lista de tareas...
         </div>
         <table class="table" v-if="!cargando_tareas">
            <thead>
               <tr>
                  <th> Título </th>
                  <th> Descripción </th>
                  <th> Estado </th>
                  <th> </th>
               </tr>
            </thead>
            <tbody>
               <!-- Fila para modificar una tarea. -->
               <tr v-for="tar in tareas">
                  <td>
                     <input type="text" v-model="tar.titulo" />
                  </td>
                  <td>
                     <textarea v-model="tar.descripcion"></textarea>
                  </td>
                  <td>
                     <select v-model="tar.id_estado" v-bind:class="colorEstado(tar)">
                        <option v-for="est in estados" v-bind:value="est.id_estado"> {{ est.nombre }} </option>
                     </select>
                  </td>
                  <td>
                     <button class="btn btn-success" v-on:click="modificarTarea(tar)"> Guardar </button>
                     <button class="btn btn-danger" v-on:click="eliminarTarea(tar)"> Eliminar </button>
                  </td>
               </tr>
               <!-- Fin Fila para modificar una tarea. -->
               <!-- Fila para guardar una nueva tarea. -->
               <tr>
                  <td>
                     <input type="text" v-model="tarea_nueva.titulo" />
                  </td>
                  <td>
                     <textarea v-model="tarea_nueva.descripcion"></textarea>
                  </td>
                  <td>
                     &nbsp;
                  </td>
                  <td>
                     <button class="btn btn-success" v-on:click="crearTarea()"> Guardar </button>
                  </td>
               </tr>
               <!-- Fin Fila para guardar una nueva tarea. -->
            </tbody>
         </table>
      </form>
   </div>
   <script type="text/javascript" src="<?php echo base_url() ?>js/vue.js"></script>
   <script type="text/javascript" src="<?php echo base_url() ?>js/vue-resource.min.js"></script>
   <script type="text/javascript" src="<?php echo base_url() ?>js/app.js"></script>
</body>
</html>

Más adelante voy a explicar este código, continuemos…

Css y Js

Vamos a ir a Twiter Bootstrap, y a descargarnos dicha librería, sólo los Css nos servirán de utilidad para darle un poco de estilo a nuestro proyecto:

http://getbootstrap.com/2.3.2/

Los cuales fueron incluidos en el código anterior:

<link rel="stylesheet" type="text/css" href="<?php echo base_url() ?>css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="<?php echo base_url() ?>css/bootstrap-responsive.min.css" />

Descargamos vue.js desde su web:

https://vuejs.org/v2/guide/installation.html

Y también incluimos en el código la librería:

<script type="text/javascript" src="<?php echo base_url() ?>js/vue.js"></script>

Otra cosa, vamos a necesitar otra librería que nos permita hacer peticiones http (ajax). La descargamos desde:

https://cdn.jsdelivr.net/vue.resource/1.3.1/vue-resource.min.js

Y la importamos:

<script type="text/javascript" src="<?php echo base_url() ?>js/vue-resource.min.js"></script>

Por últimos vamos a crear un archivo .js, el cual yo voy a llamar app.js, y va a tener el siguiente código:

var controlador_tareas = new Vue({
   el: '#controlador_tareas',
   data: {
      cargando_tareas: true,
      tarea_nueva: {
         titulo: '',
         descripcion: ''
      },
      estados: [],
      tareas: []
   },
   methods: {
      recuperarEstados: function(){
         this.$http.get('recuperar_estados').then(function(respuesta){
            this.estados = respuesta.body;
         }, function(){
            alert('No se han podido recuperar los estados.');
         });
      },
      recuperarTareas: function(){
         this.cargando_tareas = true;
         this.$http.get('recuperar_tareas').then(function(respuesta){
            this.tareas = respuesta.body;
            this.cargando_tareas = false;
         }, function(){
            alert('No se han podido recuperar los estados.');
            this.cargando_tareas = false;
         }); 
      },
      crearTarea: function(){
         this.$http.post('crear_tarea', this.tarea_nueva).then(function(){
            this.tarea_nueva.titulo = '';
            this.tarea_nueva.descripcion = '';
            this.recuperarTareas();
         }, function(){
            alert('No se ha podido crear la tarea.');
         });
      },
      modificarTarea: function(p_tarea){
         this.$http.post('modificar_tarea', p_tarea).then(function(){
            this.recuperarTareas();
         }, function(){
            alert('No se ha podido modificar la tarea.');
         });
      },
      eliminarTarea: function(p_tarea){
         this.$http.post('eliminar_tarea', p_tarea).then(function(){
            this.recuperarTareas();
         }, function(){
            alert('No se ha podido eliminar la tarea.');
         });
      },
      colorEstado: function(p_tarea){
         var estilo;
         switch(p_tarea.id_estado){
            case '1':
               estilo = 'text text-error';
               break;
            case '2':
               estilo = 'text text-warning';
               break;
            case '3':
               estilo = 'text text-success';
               break;
            default:
               estilo = 'text text-info';
         }
         return estilo;
      }
   },
   created: function(){
      this.recuperarEstados();
      this.recuperarTareas();
   }
});

Y lo incluimos:

<script type="text/javascript" src="<?php echo base_url() ?>js/app.js"></script>

Relación View-Controller

Bueno, finalmente vamos a hacer una explicación de la instancia de Vue que creamos, y cómo funciona en base al código html creado anteriormente:

En primer lugar tenemos un atributo “cargando_tareas”, que va a guardar un boolean indicando a la vista si se está esperando una respuesta del servidor, para así de esta forma mostrar u ocultar un texto de pre carga, y así hacer lo propio con la lista de tareas:

cargando_tareas: true

Y en código html:

<div v-if=”cargando_tareas”> Cargando lista de tareas… </div>

Cada vez que hagamos un refresco para mostrar la nueva lista de tareas, nos mostrará este mensaje en pantalla, hasta que por fin podamos ver la lista actualizada, la pre carga va a estar oculta.

También tenemos un atributo que tendrá una suerte de tarea temporal, y va a servir para guardar las nuevas tareas que vamos creando.

tarea_nueva: {
   titulo: '',
   descripcion: ''
}

E impactará en la vista de esta forma:

<!-- Fila para guardar una nueva tarea. -->
<tr>
    <td>
       <input type="text" v-model="tarea_nueva.titulo" />
    </td>
    <td>
       <textarea v-model="tarea_nueva.descripcion"></textarea>
    </td>
    <td>
       &nbsp;
    </td>
    <td>
       <button class="btn btn-success" v-on:click="crearTarea()"> Guardar </button>
    </td>
</tr>
<!-- Fin Fila para guardar una nueva tarea. -->

Podemos ver la realación de los atributos de “tarea_nueva” con sus atributos:

<input type="text" v-model="tarea_nueva.titulo" />

Este atributo será enviado el servidor para guardar una nueva tarea con el método “crearTarea()”, el cual se llama al pulsar en el botón:

crearTarea: function(){
   this.$http.post('crear_tarea', this.tarea_nueva).then(function(){
      this.tarea_nueva.titulo = '';
      this.tarea_nueva.descripcion = '';
      this.recuperarTareas();
   }, function(){
      alert('No se ha podido crear la tarea.');
   });
},

Este método va a enviar un json con el título y la descripción de la nueva tarea. Una vez que el servidor nos responda indicando que la tarea se creó, el atributo “tarea_nueva” se limpian los datos título y descripción.

Los estados de las tareas se guardarán en un atributo “estados”:

estados: []

Este atributo va llenarse mediante el método: “recuperarEstados()”:

recuperarEstados: function(){
   this.$http.get('recuperar_estados').then(function(respuesta){
      this.estados = respuesta.body;
   }, function(){
      alert('No se han podido recuperar los estados.');
   });
}

Una vez que el servidor nos responda obtendremos algo como esto:

[{"id_estado":"1","nombre":"Pendiente"},{"id_estado":"2","nombre":"En proceso"},{"id_estado":"3","nombre":"Finalizada"},{"id_estado":"4","nombre":"Cancelada"}]

Estos datos serán impactados en los combos para mostrar los estados:

<select v-model="tar.id_estado" v-bind:class="colorEstado(tar)">
   <option v-for="est in estados" v-bind:value="est.id_estado"> {{ est.nombre }} </option>
</select>

Mediante v-for que nos permite recorrer una array, repitiendo el código html que se va a dibujar en cada vuelta.

También tendremos el atributo “tareas”:

tareas: []

Y se llenará mediante el método "recuperarTareas()":

recuperarTareas: function(){
   this.cargando_tareas = true;
   this.$http.get('recuperar_tareas').then(function(respuesta){
      this.tareas = respuesta.body;
      this.cargando_tareas = false;
   }, function(){
      alert('No se han podido recuperar los estados.');
      this.cargando_tareas = false;
   }); 
}

 

El atributo “tareas” a diferencia de “estados”, va a cargarse varias veces durante el funcionamiento de la aplicación. Sin embargo, dentro del código html no tendremos que hacer refrescos constantes, cada vez que el atributos cambie su valor Vue se encargará de dibujar el código html nuevamente:

<!-- Fila para modificar una tarea. -->
<tr v-for="tar in tareas">
   <td>
      <input type="text" v-model="tar.titulo" />
   </td>
   <td>
      <textarea v-model="tar.descripcion"></textarea>
   </td>
   <td>
      <select v-model="tar.id_estado" v-bind:class="colorEstado(tar)">
         <option v-for="est in estados" v-bind:value="est.id_estado"> {{ est.nombre }} </option>
      </select>
   </td>
   <td>
      <button class="btn btn-success" v-on:click="modificarTarea(tar)"> Guardar </button>
      <button class="btn btn-danger" v-on:click="eliminarTarea(tar)"> Eliminar </button>
   </td>
</tr>
<!-- Fin Fila para modificar una tarea. -->

Los métodos “recuperarEstados()” y “recuperarTareas()” va a ejecutarse ni bien se haya terminado de crear la instancia de Vue, con el método “created()”:

created: function(){
   this.recuperarEstados();
   this.recuperarTareas();
}

En el código html también podemos observar dos métodos que se llaman con el evento v-on:click. “modificarTarea()”:

modificarTarea: function(p_tarea){
      this.$http.post('modificar_tarea', p_tarea).then(function(){
      this.recuperarTareas();
   }, function(){
      alert('No se ha podido modificar la tarea.');
   });
}

y “eliminarTarea()”:

eliminarTarea: function(p_tarea){
   this.$http.post('eliminar_tarea', p_tarea).then(function(){
      this.recuperarTareas();
   }, function(){
      alert('No se ha podido eliminar la tarea.');
   });
}

En ambos casos enviamos la tarea modificada al servicio, y una vez que nos responda el servidor, volvemos a cargar la lista de tareas con el método “recuperarTareas()”.

Cada tarea que obtenemos cuando recorremos el for, la agregamos a los parámetros de modificar y eliminar, en definitiva son json con el siguiente aspecto:

{id_tarea: "7", titulo: "Subir tutorial de Vue.js", descripcion: "Escribiendo POST.", id_estado: "2"}

Bueno, hasta acá todo. Para los que quieran descargarse el código, aquí se encuentra, en mi repositorio:

https://github.com/fernandoggaitan/vuejs_codeigniter

Saludos y feliz día del trabajador!

Ver parte 1

Redes sociables

    Deja un comentario

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *


    *