Magic CRUD Angular – Huyendo de escribir código JavaScript con mgCrud (Parte II) – Como usarlo

Con la finalidad de cubrir la creación, lectura, actualización y borrado de entidades (CRUD), mgCrud predefine una serie de comportamientos, para cubrir esos cuatro casos, estos son mgCreate, mgEdit, mgPut y mgDelete, y añade también mgIndex para cargar del servidor una lista de objetos y poder enviar parametros de filtro y mgPatch para enviar al servidor una actualización parcial de datos de una entidad. Estos comportamientos están predefinidos como Factories de Angular, y las obtiene mediante el service locator de Angular. Vamos a ir viendo un ejemplo de como usar mgCrud, en una aplicación donde se mostrará una lista de personas y te dará opción a crear una nueva persona, editar los datos de cada una de ellas y eliminarlas. Voy a extraer código de un ejemplo del uso de mgCrud que realicé, en el ejemplo original uso Angular Material … aquí voy a intentar quitarlo para que no contamine, pero si se me escapa algo … sorry. Para el ejemplo vamos a suponer que tenemos un servicio REST para acceder a la lista de personas, no vamos a ver nada del servidor pues no es lo que nos ocupa. En un principio tan solo necesitamos incluir mgCrud en las dependencias del modulo de nuestra aplicación AngularJS. Así pues tendremos la creación del módulo y la configuración de las rutas:

window.myModule = window.angular.module('mgCrudSampleModule', ['ngRoute', 'mgCrud']);
 
    window.myModule.config(function ($routeProvider, $locationProvider) {
        $routeProvider
            .when("/", {templateUrl: "list.html"})
            .when("/edit/:id", {templateUrl: "edit.html"})
            .when("/create", {templateUrl: "create.html"})
            .when("/delete/:id", { templateUrl: "delete.html" })
            .when("/about", { templateUrl: "about.html" })
            .otherwise("/");
    });

En nuestro index.html (o lo que sea) iniciaremos la fiesta haciendo uso de ng-app y ng-view, ni lo pongo. Vamos directo con list.html que muestrará la lista de personas.

<mg-ajax path="/people" options="mgIndex">
    <ul>
  <li ng-repeat="item in index.model">
    <span>{{item.name}}</span>
                <span>{{item.email}}</span>
                span>{{item.company}}&lt;/span>
                <span>
                    <a ng-href="#/edit/{{item.id}}">Edit</a>
                    <a ng-href="#/delete/{{item.id}}">Delete</a>
                </span>
 
  </li>
 
</ul>
&lt;/mg-ajax>

Como se ve en el ejemplo se hace un ng-repeat sobre index.model. Bien, esto es debido a que mgAjax cuando se usa con el comportamiento “mgIndex” lo que hace es crear en el scope un atributo “index” y dentro de él guarda el resultado de la operación get(“/people”) sobre el atributo model. De tal modo que “$scope.index.model” contendrá la lista obtenida del servidor. mgIndex también aporta la paginación contra el servidor, de forma que por defecto envía en el get los parametros “page” y “recordsPerPage”, por defecto pide la página 0 y 20 registros por página. También es de observar que en el path pone “/people” bien mgCrud no acepta el schema en el path, hay que configurarselo antes diciendole cual es la url de nuestro servicio REST, aquí muestro ahora la creación del modulo Angular de nuestra aplicación, esta vez mostrando como configurar la url y también cambiando los 20 registros por página a 4:

window.myModule = window.angular.module('mgCrudSampleModule', ['ngRoute', 'mgCrud', "ngMaterial"]);
 
    // { ... configuaración de la ruta ... }
 
    window.myModule.config(function (mgHttpProvider) {
        mgHttpProvider.setDefaultConfig({ url: 'http://mgcrudserver.azurewebsites.net/api' });
    });
 
    jrPeopleIndex.$inject = ['mgIndex'];
    function jrPeopleIndex(mgIndex) {
        return angular.extend(mgIndex, {
            init: 'index.filter={page:0,recordsPerPage:4}'
        });
    }
 
    window.myModule.factory('jrPeopleIndex', jrPeopleIndex);

mgCrud usa un wrapper sobre el provider de $http llamado mgHttpProvider, ahí indicamos cual es la url base de nuestro servicio REST. A continuación nos creamos una Factory con el nuevo filtro a enviar al servidor, indicando que queremos 4 registros por página. Esto lo hacemos sobreescribiendo el atrubuto “init” de la factoría. “init” viene a ser un ng-init que ejecuta mgAjax al iniciarse, ponemos el filtro inicial en “index.filter” por que “mgIndex” usa el atributo “filter” para enviarlo al servidor en el GET. Por supuesto esto es algo que se debe saber, pero que se aprende rápido con el uso. Como decía al principio “mgIndex” es una factoría que define su comportamiento. En este ejemplo creamos una factoría “jrPeopleIndex” extendiendo de “mgIndex” y sobreescribiendo el atributo init de la factoría para indicarle el nuevo filtro a enviar al servidor. Ahora nuestra vista “list.html” de arriba funcionará corectamente, trayendose 4 registros por página. Lo siguiente añadir es ponerle un filtro por nombre a nuestra lista y habilitar la paginación. Veamos como queda:

&lt;mg-ajax path="/people" options="jrPeopleIndex">
    <div>
  <h2>
    People list
  </h2>
 
 
  <input type="text" ng-model="index.filter.searchStr" />
          <button ng-click="index.filter.page=0; index.accept();">
              Search!
          </button>
 
</div>
 
 
<ul>
  <li ng-repeat="item in index.model">
    <span>{{item.name}}</span>
                <span>{{item.email}}</span>
                <span>{{item.company}}</span>
                <span>
                    <a ng-href="#/edit/{{item.id}}">Edit</a>
                    <a ng-href="#/delete/{{item.id}}">Delete</a>
                </span>
 
  </li>
 
</ul>
 
 
<div>
  Current page: {{index.filter.page + 1}}
</div>
 
 
<div>
  <button ng-click="index.filter.page=0;index.accept();" ng-disabled="index.filter.page==0">First page</button>
          <button ng-click="index.previousPage();" ng-disabled="index.filter.page <= 0" >Prior page</button>
          <button ng-click="index.nextPage();" ng-disabled="index.model.length != index.filter.recordsPerPage">Next page</button>
 
</div>
&lt;/mg-ajax>

Lo primero es darnos cuenta de que ahora usamos el comportamiento “jrPeopleIndex”, donde extendíamos el “mgIndex” y asignabamos el filtro de paginación. Ese mismo “index.filter” es el mismo que usamos en en el ng-model del input de busqueda, añadimos lo que se escriba en el input al filtro que se enviará al servidor. Atención al botón Search, en el ng-click lo que hacemos es cambiar a la primera página y hacer un “index.accept()”, mgIndex expone también esta función accept y es al ejecutarse cuando se envía la petición al servidor. Por último abajo ponemos unos botones para movernos por las páginas, ver como llamamos a las funciones “previousPage” y “nextPage”, estas cambiar el número de página del filtro y ejecutan un “accept()” para que se soliciten los datos al servidor. Con esta simple vista y dandole un poco de estilo tenemos cualquier pantalla tonta de búsqueda de cualquier entidad. Bien, visto esto y explicado como el comportamiento que indicamos en el atributo “options” de mgAjax expone en el $scope las funciones y atributos para interactuar con la directiva ya podemos ir un poco más rápido. Vamos a ver ahora el ejemplo de la vista “create.html” donde enviamos una nueva persona al servidor con POST:

&lt;mg-ajax path="/people" options="mgCreate">
    <h2>
  Create a new person
</h2>
 
 
 
<button class="md-theme-green" ng-click="create.accept()">Create</button>
    <button class="md-theme-red" ng-click="create.close()">Cancel</button>      
&lt;/mg-ajax>

Ya!, este es fácil, ponemos un mgAjax y marcamos “mgCreate” como comportamiento y fin. “mgCreate” expone en $scope las funciones accept() y close(), una envía el POST al server y la otra navega hacia atrás. Al enviar incluye como data: “model” (create.model) que es donde van los datos bindeados en los inputs. Ahora la edición, aquí ya se combinan dos mgAjax, uno para leer y otro para actualizar:

&lt;mg-ajax path="/people/{{edit.params.id}}" options="mgEdit">
    &lt;mg-ajax path="/people/{{edit.params.id}}" options="mgPut">
        <h2>
  Edit the person details
</h2>
 
 
 
<button class="md-theme-green" ng-click="put.accept()">Save</button>
        <button class="md-theme-red" ng-click="put.close()">Cancel</button>
    &lt;/mg-ajax>
&lt;/mg-ajax>

Lo primero que notamos es que en el “path” tenemos moustache syntax, si lo acepta perfectamente. Y luego vemos que los ng-model de los inputs se bindean con “edit.model” que es donde “mgEdit” guarda los datos que vienen del servidor, por último los ng-click de los botones van a “put.accept()” y “put.close()”. Lo que está pasando es que cada mg-ajax tiene su $scope y al estar anidados uno dentro del otro pueden acceder los unos a los datos del $scope del otro, y “mgPut” está configurado para que coja “edit.model” como modelo para enviar al servidor con el PUT. El caso del PATCH es exactamente el mismo, solo que lo que te permite es enviar un modelo parcial (partialModel) el cual se puede especificar en el mgPatch. Y también el caso del DELETE:

&lt;mg-ajax path="/people/{{edit.params.id}}" options="mgEdit">
    &lt;mg-ajax path="/people/{{edit.params.id}}" options="mgDelete">
        <!-- Form con los inputs -->
 
 
<button class="md-theme-green" ng-click="delete.accept()">Remove</button>
        <button class="md-theme-red" ng-click="delete.close()">Cancel</button>
    &lt;/mg-ajax>
&lt;/mg-ajax>

No se si me dejo más cosas, pero

aquí podéis acceder a un fork que he realizado de mgCrud en GitHub y podéis ver la implementación completa del ejemplo en la carpeta “samples/mgCrudWithAngularMaterial”. Y para verlo funcionar en directo aquí la demo Por último una puntualización, mg-ajax está pensado también para implementar una cache para recuperar los datos cuando navegamos de una ventana a otra. Se de buena tinta que ya hay algo hecho, pero están terminando de perfilarla, en mi repositorio de GitHub está implementada temporalmente para ver como quedaría.

Deja un comentario

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

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax

Demuestra que no eres un bot *