Introducción a Angular JS

Listar y crear registros usando el servicio ngResource Más videos

Descripción del tema

En el tutorial anterior vimos como crear servicios para hacer peticiones Ajax al servidor, en este tema veremos como podemos consultar un API RESTful para consultar el listado de bookmarks y crear uno nuevo.

Angular JS viene con un servicio llamado $ngResource, este servicio nos permite hacer conexiones vía REST a nuestra API para enviar y recibir información. Internamente ngResource utiliza el servicio $http que vimos en el tutorial anterior.

Usar ngResource en lugar de $http tiene varias ventajas, sobre todo cuando queremos hacer operaciones CRUD, ya que automáticamente nos define los métodos necesarios para guardar, listar y consultar un API de tipo REST, además es muy sencillo agregar nuevos métodos. Hacer esto con el servicio $http nos requerirá algunas lineas de código adicionales, pero es completamente posible.

Los métodos que define de manera automática son los siguientes:

  1. get()
  2. query()
  3. save()
  4. remove()
  5. delete()
En este tema nos enfocaremos solamente en como utilizar el método query y el método save.

Definir dependencias

El servicio ngResource no viene incluido dentro de la librería principal de Angular JS, lo tenemos que incluir manualmente y definirlo en las dependencias de nuestro módulo, vamos a insertar el siguiente script en el documento HTML.

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular-resource.min.js"></script>

Lo tenemos que importar por debajo de la librería de Angular JS para no tener errores. Ahora en el archivo app.js agregamos el siguiente código.

angular.module('Bookmarks',[
    //dependencies here
    'ngResource' //<----
])

Cuando creamos nuestro módulo principal dijimos que el segundo parámetro corresponde a un arreglo con las dependencias de nuestra aplicación. Ha llegado el momento de comenzar a agregar dependencias.

Configuración básica del servicio ngResource

Ya dijimos que la persistencia debemos manejarla en servicios, para este ejemplo vamos a usar un servicio que haga uso del ngResource, pero a diferencia del tutorial anterior, en esta ocasión vamos a crear el servicio usando una factoría. 

Las factorías a diferencia de los servicios que estudiamos en el tema anterior, nos permiten crear y retornar el servicio usando en una función. En este caso regresaremos el ngResource con las configuraciones necesarias.

//Step 1
.factory('Bookmark',function($resource){ //Step 2
    //Step 3
    return $resource('http://bookmarks-angular.herokuapp.com/api/bookmarks/:id');
})
  1. En el paso uno definimos la factoría con el método factory, en el primer parámetro le asignamos el nombre del servicio, en este caso Bookmark, y el segundo parámetro es la función que creará el servicio Bookmark.
  2. En el paso dos agregamos como parámetro el servicio ngResource, el cual exta disponible bajo el identificador $resource. Angular inyectará este servicio automáticamente, solo tenemos que asegurarnos nombrarlo exactamente igual.
  3. En el paso tres configuramos el recurso con la URL donde está nuestra API, algo importante a destacar es que definimos el parámetro :id, este lo usaremos para consultar, actualizar o borrar un bookmark.

Una factoría siempre debe regresar un objeto o instancia del servicio que crearemos, en este ejemplo estamos regresando el recurso ya configurado y listo para ser usado en nuestros controladores.

Listar bookmarks existentes

Para solicitar el listado de bookmarks que actualmente se encuentran almacenadas en el servidor, en el controlador usamos el método query de la siguiente manera.

.controller('MainController',function($scope,Category,Bookmark){ //Step 1
    $scope.name = 'Carl';

    Category.getAll(function(data){
        $scope.categories = data.categories;
        $scope.currentCategory = data.categories[0]; //Step 2
        $scope.bookmarks = Bookmark.query(); //Step 3
    });
 
    //...

});
  1. En el paso uno inyectamos el nuevo servicio que creamos usando la factoría.
  2. El paso dos se ejecuta cuando el servidor responde con el listado de categorías, aquí solamente seleccionamos la categoría cero para filtrar los bookmarks.
  3. En el paso tres ejecutamos el método query(), este método hace una petición GET hacia la url que definimos.

Antes de probar nuestros cambios necesitamos cambiar el template para manejar correctamente las categorías, anteriormente estábamos usando strings solamente, ahora estamos usando objetos, por lo tanto debemos actualizar nuestro template de la siguiente manera.

<!-- sidebar -->
<div class="column col-sm-3" id="sidebar">
    <p class="nav-title">
      Categories 
      <a href="#" class="pull-right"><i class="glyphicon glyphicon-folder-open"></i></a>
    </p>
    <ul class="nav">
        <li ng-repeat="category in categories" ng-class="{active: isCurrentCategory(category)}">
            <a href="#" ng-click="setCurrentCategory(category)"> <i class="glyphicon glyphicon-tags"></i> {{category.name}}</a>
        </li>
    </ul>
</div>
<!-- /sidebar -->

<!-- main -->
<div class="column col-sm-9" id="main">
    <div class="padding">
      <div class="full col-sm-9">
        
          <!-- content -->
          <h2>
            Category: {{currentCategory.name}}
            <a ng-click="showWindow()" href="#" class="btn btn-primary btn-xs pull-right"><i class="glyphicon glyphicon-plus-sign"></i> New bookmark</a>
          </h2>
          <ul>
            <li ng-repeat="bookmark in bookmarks | filter: {category: currentCategory.name}">
                <p>
                    <a href="{{bookmark.url}}">{{bookmark.title}}</a> 
                    <i ng-click="remove(bookmark.id)" class="glyphicon glyphicon-trash"></i>
                    <i ng-click="showWindow(bookmark)" class="glyphicon glyphicon-pencil"></i><br/>
                    <small>{{bookmark.url}}</small>
                </p>
            </li>
        </ul>
          
          
        
      </div><!-- /col-9 -->
    </div><!-- /padding -->
</div>
<!-- /main -->
  1. En el sidebar solo hemos cambiado dos cosas, a la función isCurrentCategorysetCurrentCategory le estamos enviando el objeto y no solamente el nombre de la categoría.
  2. En el listado de bookmarks desplegamos el nombre de la categoría seleccionada usando currentCategory.name y también cambiamos el filtro. Todo lo demás sigue exactamente igual.

Ya casi estamos listos para probar nuestros cambios, solo nos queda modificar la función isCurrentCategory de la siguiente manera.

$scope.isCurrentCategory = function(category){
    return $scope.currentCategory.id === category.id;
}

Ya que estamos usando objetos para manejar las categorías, necesitamos comparar los identificadores. Una vez que cambiamos esto ya podremos ver nuestra aplicación listando los bookmarks que actualmente están en la base de datos del servidor.

Angular ngResource

Angular ngResource

Crear un nuevo Bookmark

Vamos a crear nuevos bookmarks utilizando el método save, este método hará una petición Ajax a la URL que definimos en el ngResource de tipo POST, la API que esta en Heroku tiene soporte para recibir este tipo de peticiones y espera el siguiente objeto json en el payload del request.

{
    "title"       : "The title of the new bookmark",
    "url"         : "http://testing.com",
    "category_id" : 2
}

Con esto en mente modificaremos el código del método save que ya tenemos en el controlador. Ahora en lugar de solamente agregar el objeto al arreglo local de bookmarks, también haremos la petición al servidor para guardarlo en la base de datos, en Heroku la base de datos es PostgreSQL.

$scope.save = function(bookmark){
    if($scope.bookmarkForm.$valid){
        if(!bookmark.id){
            var record = new Bookmark(); //Step 1
            
            record.title = bookmark.title; //Step 2
            record.url = bookmark.url;
            record.category_id = bookmark.category.id;

            record.$save(function(){ //Step 3
                $scope.bookmarks.push(record); //Step 4
            });
        }
        $('#bookmarkModal').modal('hide');
    }
}
  1. En el paso uno creamos una instancia de nuestro servicio Bookmark usando la palabra reservada new.
  2. En el paso dos agregamos la información (title, url, category_id) a la instancia del servicio que creamos en el paso uno, esta información es la que se enviará al servidor y es la que el API está esperando recibir.
  3. En el paso tres invocamos el método $save de la instancia del servicio, este método es el que hace la petición ajax y nos regresa una promesa.
  4. En el ultimo paso insertamos el record al arreglo de bookmarks, cuando el servidor responde. 

Idealmente usaremos solamente el método get y query del servicio Bookmark, ya que tenemos a nuestra disposición el método $save, $delete y $remove an cada instancia de Bookmark. Es importante resaltar que estos métodos inician con el signo $, esto nos indica que son métodos de la instancia.

Si probamos la app en el navegador y creamos un nuevo bookmark, veremos que se está haciendo una petición al servidor para guardar el bookmark en la base de datos.

ngResource

Guardando un bookmark

Por el momento hasta aquí llegaremos en este tutorial, en el próximo veremos como editar los bookmarks existentes y también como borrarlos utilizando el ngResource que ya tenemos configurado.

Recuerda que puedes descargar el código fuente, y el video desde el área de miembros de Quizzpot.com, si tienes dudas puedes usar el foro.

Te gustaría recibir más tutoriales como este en tu correo?

Este tutorial pertenece al curso Introducción a Angular JS, te recomiendo revises el resto de los tutoriales ya que están en secuencia de menor a mayor complejidad.

Si deseas recibir más tutoriales como este en tu correo te recomiendo registrarte al curso, si ya eres miembro solo identifícate y registrate al curso, si no eres miembro te puedes registrar gratuitamente!

Si no gustas registrarte en este momento no es necesario! Aún así puedes recibir los nuevos tutoriales en tu correo! Jamás te enviaremos Spam y puedes cancelar tu suscripción en cualquier momento.

¿Olvidaste tu contraseña?

26Comentarios

  • Avatar-6 Jorge Armand Olivero 27/10/2014

    Bien, una duda ¿A un sigues usando el array para poder mostrar los datos sin necesidad de refrescar la pagina o no es necesario a pesar de que estas usando ajax?

    • Avatar-5 Crysfel Villa 27/10/2014

      El array es necesario para poder iterarlo en el template, la diferencia es que ahora estamos trayendo la información desde una API json.

    • Avatar-2 Cesar Murillo 29/10/2014

      Crysfel Muy bueno esta vez te puliste. Domo arigatou.

      • Avatar-5 Kevin Garibo 12/11/2014

        Muy buen tutorial :D

        • Avatar-2 edwing david romero 26/11/2014

          Al momento de insertar un nuevo bookmark mediante push... definen "record.category_id" .. el subguion id (_id) es porque??..

          • Avatar-3 Crysfel Villa 26/11/2014

            Hola Edwing, el subguion es porque el API así lo espera, creo que debí haber mencionado esa en el video xD Saludos

          • Avatar-10 Ricky Muñoz 08/01/2015

            Crysfel, cuál es la diferencia entre get() y query()?? y cómo se yo en qué momento le envío el :id usando cualquiera de esos métodos? En el controller (específicamente en el paso 3) haces un llamado a Bookmark.query() ahí pues asumo que haces (como mencionas en tu post) el envío del :id que te menciono, pero no se en qué parte le asigno yo a Bookmark ese valor (Tomando en cuenta que Bookmark es una Factory y en ningún momento veo la interacción entre esa factory y el modelo) Ojala me hayas entendido. Saludos y muchas gracias!

            • Avatar-6 Crysfel Villa 11/01/2015

              Hola Ricky El método query te regresa una lista de registros, la idea es que aquí puedas hacer una consulta de bookmarks, podrías enviar los parámetros que necesites. El método en este ejemplo no lo estamos usando, pero lo que hace es regresar un solo registro, lo único que se tendría que hacer es algo como esto: Bookmark.get({id:1},function(response){ ... }) con eso se haría una petición Ajax al servidor de manera automática con el ID igual a 1. Saludos

            • Avatar-6 Ramon Ramirez 07/08/2015

              Excelentes tutoriales. Soy nuevo en Angular. Solo tengo una duda, utilizo las versiones 1.4.3 de cada librería de angular. Pero al parecer solo me funciona todo lo de los tutoriales es con la versión 1.3.0 La parte del get(), query(), etc.. no carga sino es la versión 1.3.0, versiones posteriores no hace nada. Me gustaría alguna asesoría sobre como me puede funcionar en las nuevas versiones estos métodos. Muchas gracias.

              • Avatar-9 Juan 11/09/2015

                Excelente!, pero una consulta con respecto al select del modal, los valores me marcan como 0, 1, 2, 3 por defecto, como podria hacer para que en el valor salga el ID de la categoria ng-options="value.name for value in categories"

                • Avatar-2 juan 11/09/2015

                  Me he confundido con las factorias, tienes un ejemplo mas detallado, soy nuevo en AngularJS y no entiendo que es una factoria, lo veo en muchas cosas, para que realmente sirve

                  • Avatar-2 Silvia 07/10/2015

                    Hola, tengo un problema. la página se carga bien, pero al clicar en las categorías (JavaScript, CSS ...) no sale la lista de la categoría seleccionada, se queda en blanco si voy a la http: http://bookmarks-angular.herokuapp.com/api/bookmarks/ salen todas las categorias

                    • Avatar-6 Silvia 07/10/2015

                      ya solucioné el problema, muchas gracias!!!! :)

                      • Avatar-7 drxgou 03/12/2015

                        como solucionaste amigo?

                        • Avatar-5 Silvia 03/12/2015

                          al final me tuve que descargar su código fuente y substituirlo por el mío, ya que hacía exactamente todo lo que decía en el vídeo y la explicación suya pero no había maneras yo creo que sería una tontería como un punto y coma que faltase o alguna cosa así, ya que su código por el mío tampoco vi diferencia alguna

                        • Avatar-1 Carlos Mario 16/10/2015

                          Hola quisiera me pudieras ayudar con un ejemplo, mi caso es el siguiente: Necesito enviar como parametro un registro que yo escoja en un droundown, ese parametro lo tengo que recibir en la consulta sqlserver, para que luego me llene una tabla, con la informacion adquirida, ese proyecto lo estoy haciendo con angular y MVC4, te agradeceria alguna ayuda.

                          • Avatar-3 Edward Velasquez 10/12/2015

                            Saludos Crysfel, he estado siguiendo tu curso y he aprendido mucho hasta ahora, para hacerlo mas interesante me he creado una api local en laravel 5, mi url es 'http://bookmarks.local/bookmarks/' y me devuelve: {"code":200,"bookmark":[{"id":1,"title":"HTML5 for Dummies","URL":"http:\/\/html5fordummies.com","category_id":1,"category":{"id":1,"name":"HTML5"}}]} Cuando declaro mi factory: .factory('Bookmark', function($resource){ return $resource('http://bookmarks.local/bookmarks/:id'); }) me devuelve un error 'Error in resource configuration for action `query`. Expected response to contain an array but got an object (Request: GET http://bookmarks.local/bookmarks)', he buscado información pero aun no logro resolverlo y no puedo seguir avanzando, sabes que estoy haciendo mal?

                            • Avatar-11 Dante 29/08/2016

                              Buenas noches amigo tengo un problema. la página se carga bien, pero al clicar en las categorías (JavaScript, CSS ...) no sale la lista de la categoría seleccionada, se queda en blanco, estoy usando ANGULARS 1.5, hice todo pero no me devuelve el query.

                            • Avatar-5 Yoelvys 20/09/2016

                              Buenas tardes tengo un problema con la version, estoy trabajando con 1.5.8 y a pesar de que me funciona todo lo de obtener los datos, el problema es en mostrarlos, el filtro parece no funciona en mi version, he intentado varias cosas pero nada que me ayude a solucionar. saludos

                            • Avatar-2 carlos jaramillo 27/12/2016

                              <li> No me funciona, no me muestra ninguna pero remplazo el .name por .title y me salen todas sin filtrar.

                              • Avatar-4 carlos jaramillo 27/12/2016

                                bookmark in bookmarks | filter: {category: currentCategory.name} No me funciona, no me muestra ninguna pero remplazo el .name por .title y me salen todas sin filtrar.

                              Instructor del curso

                              Crysfel3

                              Autor: Crysfel Villa

                              Ha participado en varios proyectos con Angular y es participante activo del grupo de Angular NYC.

                              Descarga video Descarga Código Fuente Ver Demostración

                              Regístrate a este curso

                              Este tutorial pertenece al curso Introducción a Angular JS, revisa todos los tutoriales que tenemos en este mismo curso ya que están en secuencia y van de lo más sencillo a lo más complicado.

                              Tendrás acceso a descargar los videos, códigos y material adicional.

                              Podrás resolver los ejercicios incluidos en el curso así como los Quizzes.

                              Llevarás un registro de tu avance.