Cómo crear un cliente REST en Angular JS

Crear un cliente REST en Angular JS es una tarea sencilla de implementar. Angular JS cuenta con el módulo ngResource en el cual podemos encontrar el servicio $resource el cual nos dará esta funcionalidad. En este tutorial crearemos un cliente REST en Angular JS paso por paso, trabajaremos con una lista de nombres de usuarios y su edad y utilizaremos el servicio $resource para crear nuevos usuarios, borrarlos o editarlos.

Para la realización de este tutorial vamos a utilizar json-server de @typicode. Con esta utilidad podremos crear una falsa REST API, muy útil para hacer pruebas en entornos de desarrollo.

Fichero JSON a utilizar (data.json)

Crearemos un fichero JSON consistente en un Array de Objetos, el cual contendrá los datos iniciales de la aplicación.

Después de creado el fichero lo situamos en la carpeta del proyecto:

{
  "users": [
    {
      "id": 1,
      "name": "Martha",
      "age": 20
    },
    {
      "id": 2,
      "name": "Carl",
      "age": 34
    },
    {
      "id": 3,
      "name": "Chris",
      "age": 23
    }
  ]
}

Instalar json-server

Para instalar json-server usaremos npm. La manera más fácil de obtener npm es instalar Node.js. Una vez tengamos npm, ya podemos pasar a instalar json-server:

// Si estás en Windows ejecuta este script en una ventana de CMD con permisos administrativos
// Si estás en Mac OS ejecuta esta línea de comandos precediéndola con sudo
$ npm install -g json-server

Montar el servidor REST

Después de instalar npm pondremos en marcha el servidor REST, para hacerlo debemos dirigirnos a la carpeta del proyecto y ejecutamos en el CMD de Windows o en el terminal de Mac OS la siguiente línea de comandos:

$ json-server --watch data.json

Esto pondrá en marcha el servidor, si nos dirigimos a la url: http://localhost:3000/users/2, nos debería salir en el navegador lo siguiente:

crear-un-cliente-rest-en-angular-js-server

Si no nos sale el usuario con id 2 en el navegador algo hemos hecho mal, así que si no funciona deberíamos revisar que hayamos realizado bien los pasos anteriores.

Creación del fichero HTML (index.html)

Usaremos Bootstrap para aprovechar sus clases y agilizar el trabajo. La estructura HTML sería la siguiente:

<!DOCTYPE html>
<html>
<head>
	<title>REST Angular Example</title>
	<meta charset="UTF-8">
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
	<link rel="stylesheet" href="styles/styles.css">
</head>
<body ng-controller="myController">

	<!-- Formulario -->
	<div class="container">

		<form id="myForm" name="myForm">
			<div class="form-group">
				<label class="sr-only" for="name">Nombre</label>
				<input class="form-control" type="text" id="name" name="name" placeholder="Nombre" required>
			</div>
			<div class="form-group">
				<label class="sr-only" for="age">Edad</label>
				<input class="form-control" type="number" min="1" max="150" id="age" name="age" placeholder="Edad" required>
			</div>
			<div class="form-group">
				<input class="btn btn-primary" type="submit" value="Añadir">
			</div>
		</form>

	</div>

	<!-- Tabla -->
	<div class="container no-top">

		<table class="table table-striped">
	 		<thead>
	 			<tr>
	 				<th width="45%">Nombre
		 			<th width="45%">Edad
		 			<th width="10%">
	 			</tr>
	 		</thead>
	 		<tbody>
	 		
	 		</tbody>
		</table>

	</div>

	<script src="js/angular/angular.min.js"></script>
	<script src="js/angular/angular-resource.min.js"></script>
</body>
</html>

Como podemos ver, es un HTML muy sencillo. En la parte superior contamos con un contenedor con un formulario que tiene tres elementos: un input de tipo texto para el nombre, otro input de tipo número para la edad y un input de tipo submit con el que guardaremos los resultados. En la parte inferior contamos con otro contenedor que dentro tiene una tabla con tres columnas, la cual no tiene datos por ahora.

Se ha añadido al final del body el script principal de Angular JS y se ha añadido también el script relativo al módulo ngResource, necesario para usar el servicio $resource con el que accederemos a la REST API.

El resultado debe quedar como el siguiente:

crear-un-cliente-rest-en-angular-js-start-html

Añadir las directivas ng-app y ng-controller al HTML

En el elemento html añadiremos la directiva ng-app con el nombre del módulo de la aplicación, en este caso hemos escogido myApp:

<html ng-app="myApp">

Y en el body añadiremos el nombre del controlador que utilizaremos mediante la directiva ng-controller. En este caso hemos escogido myController como nombre:

<body ng-controller="myController">

Módulo de la aplicación (fichero app.js)

Crearemos dentro de un fichero que nombraremos app.js el código relativo al módulo de la aplicación y colocaremos como dependencia del mismo al módulo ngResource.

(function(){

	// Accedemos al módulo myApp
	var app = angular.module("myApp", ["ngResource"]);

})();

Crear el servicio RestApi (fichero services.js)

Crearemos dentro de un fichero que nombraremos services.js el código relativo al servicio que se encargará de interactuar con la REST API. Le hemos situado como nombre RestApi.

(function(){

	// Accedemos al módulo myApp
	var app = angular.module("myApp");

	// Servicio RestApi
	// Le inyectamos el servicio $resource
	app.factory("RestApi", ["$resource", function RestApiFactory($resource){

		// Retornamos el servicio $resource apuntando a la dirección de la REST API
		// Los parámetros deben ir precedidos de ":"
		// Como tercer parámetro pasamos un objeto que contendrá las acciones personalizadas
		// Como acción personalizada hemos colocado una llamada update que corresponderá al método PUT
		return $resource("http://localhost:3000/users/:id", {}, {

			update: {method: "PUT"}

		});

	}]);

})();

Crear el controlador (fichero controllers.js)

Crearemos dentro de un fichero que nombraremos controllers.js el código inicial relativo al controlador con el que trabajaremos. Inyectaremos en el controlador el servicio RestApi que hemos creamos anteriormente, así podremos llamarlo y acceder a la REST API desde dentro del mismo:

(function(){

	// Accedemos al módulo myApp
	var app = angular.module("myApp");

	app.controller("myController", ["$scope", "RestApi", function($scope, RestApi){

		// Obtener la lista de usuarios
		$scope.users = RestApi.query();

	}]);

})();

Hemos usado el método query() del servicio $resource. Este método es equivalente a hacer una llamada GET con el servicio $http a la dirección de la REST API. Este método devolverá un objeto JSON con todos los usuarios el cual guardaremos dentro de la variable users del $scope.

Mostrar los usuarios en la tabla

Ahora, guiándonos por la variable users vamos a mostrar estos datos en la tabla contenida dentro del fichero index.html:

<!-- Tabla -->
<div class="container no-top">

	<table class="table table-striped">
	 	<thead>
	 		<tr>
	 			<th width="45%">Nombre
		 		<th width="45%">Edad
		 		<th width="10%">
	 		</tr>
	 	</thead>
	 	<tbody>
	 		<tr class="form-inline" ng-repeat="user in users">
	 			<td>
	 				<span>{{user.name}}</span>
	 			</td>
	 			<td>
	 				<span>{{user.age}}</span>
	 			</td>
	 			<td>
	 				<button type="button" class="btn btn-primary">Eliminar</button>
	 			</td>
	 		</tr>
	 	</tbody>
	</table>

</div>

<script src="js/angular/angular.min.js"></script>
<script src="js/angular/angular-resource.min.js"></script>
<script src="js/app.js"></script>
<script src="js/services.js"></script>
<script src="js/controllers.js"></script>

Dentro de un elemento tr de la tabla, añadimos la directiva ng-repeat iterando entre todos los usuarios dentro del objeto users. Después en un elemento td situamos la propiedad name y en otro situamos la propiedad age de cada usuario. En un tercer elemento td añadimos un botón con el texto eliminar. Si probamos la aplicación debe quedar algo como esto:

crear-un-cliente-rest-en-angular-js-html-data

Borrar usuarios

Para borrar usuarios vamos a crear un método con la directiva ng-click en el botón que se encuentra en el tercer td de cada fila de la tabla, enviándole a este método el objeto user que obtenemos de la iteración. Hemos llamado a este método deleteUser:

<td>
	<button type="button" class="btn btn-primary" ng-click="deleteUser(user)">Eliminar</button>
</td>

Ahora creamos el método en el controlador con la funcionalidad para borrar el usuario que le enviemos:

(function(){

	// Accedemos al módulo myApp
	var app = angular.module("myApp");

	app.controller("myController", ["$scope", "RestApi", function($scope, RestApi){

		// Leer los usuarios
		$scope.users = RestApi.query();

		// Eliminar usuario
		$scope.deleteUser = function(user){

			RestApi.delete(user);

		};

	}]);

})();

Este método se encargará de hacer una llamada DELETE al servidor. Si probamos presionar uno de los botones de borrar notaremos que el usuario es borrado del servidor pero la vista no se actualiza. Esto ocurre porque después de borrado el usuario no actualizamos la variable users del controlador. Procederemos a usar la propiedad $promise de la instancia de $resource que obtenemos al llamar al método delete. Mediante esta propiedad podremos obtener una retrollamada cuando el método delete haya culminado con éxito:

// Eliminar usuario
RestApi.delete(user)

	.$promise.then(

		// Cuando se haya borrado correctamente el usuario del servidor
		function(){

			$scope.users.splice( $scope.users.indexOf(user), 1 );

		}
	);

Una vez se haya borrado el usuario del servidor, procederemos a eliminarlo del Array que lo contiene en el $scope. Para lograr este propósito usaremos el método splice. Si probamos borrar un usuario de la lista notaremos que es borrado del servidor y el borrado se refleja en la vista. Con esto queda esta sección culminada.

Añadir un nuevo usuario

Para poder añadir un usuario trabajaremos con el formulario ubicado en el primer contenedor que creamos anteriormente en el HTML. Lo primero que haremos será inhabilitar el botón que añade un usuario cuando no se haya rellenado el formulario y lo habilitaremos cuando se hayan rellenado los dos datos necesarios (nombre y edad):

<form id="myForm" name="myForm">
	<div class="form-group">
		<label class="sr-only" for="name">Nombre</label>
		<input class="form-control" type="text" id="name" name="name" placeholder="Nombre" ng-model="user.name" required>
	</div>
	<div class="form-group">
		<label class="sr-only" for="age">Edad</label>
		<input class="form-control" type="number" min="1" max="150" id="age" name="age" placeholder="Edad" ng-model="user.age" required>
	</div>
	<div class="form-group">
		<input class="btn btn-primary" type="submit" value="Añadir" ng-class="{'disabled': myForm.$invalid}">
	</div>
</form>

En el anterior código HTML, hemos usado la directiva ng-model en cada input para poder enlazar su valor con propiedades específicas dentro del controlador. Si el objeto o las propiedades no existen en el controlador (como en nuestro caso) éstas son creadas dinámicamente.

Después en el botón de submit del formulario usamos la directiva ng-class para asignar una clase dependiendo del estado del formulario, si este último es inválido se añadirá la clase disabled de Bootstrap al botón y si no lo es se eliminará la clase. El formulario será inválido si alguno de sus elementos con la propiedad required asignada no está correctamente rellenado.

Si probamos el resultado podemos ver como el botón del formulario se mantiene inhabilitado hasta que no añadamos los datos necesarios.

crear-un-cliente-rest-en-angular-js-form-validation

Ahora procederemos a crear el método que añadirá un usuario a la lista, usaremos la directiva ng-click en el botón para ejecutar el método addUser en el controlador enviándole el objeto respectivo al usuario y una vez añadido al servidor lo añadiremos también al Array users para que la vista se actualice y podamos ver los datos en la tabla.

<input class="btn btn-primary" type="submit" value="Añadir" ng-class="{'disabled': myForm.$invalid}" ng-click="addUser(user)">

El método addUser en el controlador quedaría así:

// Añadir un usuario
$scope.addUser = function(user){

	// Ejecutar el método save para guardar el usuario
	RestApi.save(user)

		// Al guardar el usuario correctamente
		.$promise.then(

			function(response){

				// Añadir los datos del usuario al array de users
				$scope.users.push({

					id	: response.id,
					name	: response.name,
					age	: response.age

				});

				// Reemplazar la variable user del scope
				// por un objeto vacío para que el formulario
				// quede limpio
				$scope.user = {};

			}

		);

};

El método save es equivalente a hacer una llamada POST al servidor. Si probamos la aplicación veremos que ya podemos añadir usuarios, la vista es actualizada cuando lo hacemos y el formulario queda limpio una vez se haya añadido.

crear-un-cliente-rest-en-angular-js-add-user

Editar usuarios

Procederemos a crear la funcionalidad de editar los usuarios. Para hacerlo vamos a crear los elementos necesarios en cada columna de la tabla. Bajo el nombre y la edad de cada uno colocaremos un input con el parámetro value con estos datos asignados y con la directiva ng-model preparada para variar dichos datos. Debajo del botón de eliminar el usuario colocaremos otro botón con la directiva ng-click asignada a un método llamado editUser dentro del controlador encargado de editar el usuario en el servidor.

<tbody>
	<tr class="form-inline" ng-repeat="user in users">
		<td>
			<span>{{user.name}}</span>
			<input type="text" class="form-control" ng-model="user.name" value="{{user.name}}">
		</td>
		<td>
			<span>{{user.age}}</span>
			<input type="number" class="form-control" ng-model="user.age" min="1" max="150" value="{{user.age}}">
		</td>
		<td>
			<button type="button" class="btn btn-primary" ng-click="deleteUser(user)">Eliminar</button>
			<button type="button" class="btn btn-warning" ng-click="editUser(user)">Editar</button>
		</td>
	</tr>
</tbody>

Si probamos a variar el nombre o la edad en sus respectivos inputs podremos notar como es actualizado el dato también en el span correspondiente.

crear-un-cliente-rest-en-angular-js-edit-user

Pasaremos ahora a crear el método editUser dentro del controlador, el cual será encargado de editar el usuario en el servidor.

// Editar un usuario
$scope.editUser = function(user){

	// Llamar al método update (PUT)
	RestApi.update({id: user.id}, user);

};

Recordemos que al crear el servicio RestApi, creamos una acción personalizada llamada update que equivalía a una llamada PUT al servidor. Si ejecutamos esta llamada enviando un objeto con los datos del usuario, éste será actualizado. No hace falta hacer ninguna variación en el Array users ya que al tener relacionados los inputs con estos valores mediante la directiva ng-model estas propiedades serán variadas automáticamente.

Mejorando la edición

En este momento los elementos necesarios para la edición se muestran todo el tiempo. Haremos que estos elementos estén ocultos por defecto y que se muestren cuando demos doble click sobre el nombre o la edad de un usuario. Para lograr esto nos guiaremos por una variable del $scope. Si la variable es true mostraremos los elementos respectivos a la edición y ocultaremos los spans y el botón de eliminar. Si la variable es false mostraremos los spans y el botón de eliminar y ocultaremos los elementos de la edición.

Usaremos la directiva ng-show y ng-hide para mostrar u ocultar los elementos deseados guiándonos por una variable del $scope. El código del HTML quedaría así:

<td>
	<span ng-hide="edit[user.id]">{{user.name}}</span>
	<input type="text" class="form-control" ng-model="user.name" ng-show="edit[user.id]" value="{{user.name}}">
</td>
<td>
	<span ng-hide="edit[user.id]">{{user.age}}</span>
	<input type="number" class="form-control" ng-model="user.age" ng-show="edit[user.id]" min="1" max="150" value="{{user.age}}">
</td>
<td>
	<button type="button" class="btn btn-primary" ng-hide="edit[user.id]" ng-click="deleteUser(user)">Eliminar</button>
	<button type="button" class="btn btn-warning" ng-show="edit[user.id]" ng-click="editUser(user)">Editar</button>
</td>

Como podemos notar estamos consultando una variable llamada edit y estamos accediendo a una propiedad de la misma igual al id de cada usuario. Como la propiedad no existirá en un inicio los elementos respectivos a la edición no se mostrarán. Para que se muestren debemos hacer que la propiedad respectiva al id del usuario tome valor true en el objeto edit. Para lograr esto utilizaremos la directiva ng-dblclick para que cuando demos doble click sobre el nombre o la edad del usuario un método asigne a esta propiedad valor true.

<td>
	<span ng-hide="edit[user.id]" ng-dblclick="showEdition($event, user.id)">{{user.name}}</span>
	<input type="text" class="form-control" ng-model="user.name" ng-show="edit[user.id]" value="{{user.name}}">
</td>
<td>
	<span ng-hide="edit[user.id]" ng-dblclick="showEdition($event, user.id)">{{user.age}}</span>
	<input type="number" class="form-control" ng-model="user.age" ng-show="edit[user.id]" min="1" max="150" value="{{user.age}}">
</td>
<td>
	<button type="button" class="btn btn-primary" ng-hide="edit[user.id]" ng-click="deleteUser(user)">Eliminar</button>
	<button type="button" class="btn btn-warning" ng-show="edit[user.id]" ng-click="editUser(user)">Editar</button>
</td>

El método showEdition envía como parámetros el evento de mouse generado y el id del usuario, a continuación mostramos cómo quedaría el método en el controlador:

// Declarar la variable edit en el controlador
$scope.edit = {};

// Mostrar la edición
$scope.showEdition = function($event, id){			

	// Asignar valor true la variable representada por el id del usuario
	// Esto provocará que se muestren los elementos respectivos a la edición
	// y se oculten los spans y el botón de eliminar usuario
	$scope.edit[id] = true;

	// Con $event.currentTarget accedemos al elemento que ha lanzado el evento
	// Guiándonos por este elemento accedemos mediante jQuery al input que está debajo del mismo
	var input = angular.element($event.currentTarget).parent().find("input")[0];		

	// Después de 50 milisegundos hacemos que el input tome el foco
	// Y que el texto que contiene se seleccione
	setTimeout(function(){

		input.focus();
		input.select();

	}, 50);

};

El método showEdition primero que todo asigna el valor true a la variable necesaria del objeto edit. Después usando la función angular.element usamos jQuery para acceder al input que se encuentra debajo del span al que se le ha dado doble click y provocamos que este tome foco y después quede seleccionado su contenido.

Si comprobamos la aplicación veremos cómo los campos necesarios para la edición son mostrados después de hacer doble-click sobre el span del nombre o el de la edad. También el input que corresponde al span presionado toma foco y se selecciona automáticamente:

crear-un-cliente-rest-en-angular-js-show-edition

En este momento sólo falta que los elementos de la edición vuelvan a ocultarse cuando la edición sea realizada, para eso vamos a modificar el método editUser en el controlador:

// Editar un usuario
$scope.editUser = function(user){

	// Llamar al método update (PUT)
	RestApi.update({id: user.id}, user)

		// Una vez realizada la edición
		.$promise.then(

			// Eliminar la variable respectiva al id del usuario del objeto edit
			function(response){

				delete $scope.edit[user.id];

			}

		);

};

Una vez que se haya realizado la edición en el servidor procedemos a borrar la propiedad respectiva al id del usuario del objeto edit, esto provocará que los elementos respectivos a la edición queden ocultos en la fila editada.

Con esto queda lista la aplicación, ya podemos añadir, borrar y editar usuarios. Espero que este tutorial os haya servido de ayuda. Cualquier duda podéis dejarla en los comentarios.

Descargara los ficheros del tutorial

Descarga los ficheros para crear un cliente REST en Angular JS.

Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInShare on StumbleUpon

Deja un comentario

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

Puedes situar fragmentos de código dentro de etiquetas <pre></pre> y código HTML o XML entre etiquetas <xmp></xmp>.

Time limit is exhausted. Please reload CAPTCHA.