7 days of WordPress plugins, themes & templates - for free!* Unlimited asset downloads! Start 7-Day Free Trial
Advertisement
  1. Code
  2. JavaScript

Aplicaciones de una sola página más adaptables con AngularJS y Socket.IO: Creando la biblioteca

Scroll to top
Read Time: 11 mins

Spanish (Español) translation by steven (you can also view the original English article)

Ni HTML ni HTTP se crearon para aplicaciones web dinámicas. Básicamente, confiamos en los hacks, además de los hacks para dar a nuestras aplicaciones una interfaz de usuario adaptable. AngularJS elimina algunas limitaciones de HTML, lo que nos permite crear y administrar el código de la interfaz de usuario más fácilmente. Socket.IO, por otro lado, nos ayuda a enviar datos desde el servidor no solo cuando el cliente lo solicita, sino también cuando el servidor lo necesita. En este artículo, te mostraré cómo combinar estos dos para mejorar la capacidad de respuesta de tus aplicaciones de una sola página.


Introducción

En la primera parte de este tutorial crearemos un servicio AngularJS reutilizable para Socket.IO. Debido a esa parte reutilizable, esto será un poco más complicado que simplemente usar module.service() o module.factory(). Estas dos funciones son simplemente el dulce sintáctico además del método module.provider() de nivel más bajo, que usaremos para proporcionar algunas opciones de configuración. Si nunca antes has usado AngularJS, te recomiendo encarecidamente que sigas al menos el tutorial oficial y algunos de los tutoriales aquí en Tuts+.


Preparación: El backend

Antes de comenzar a escribir nuestro módulo AngularJS, necesitamos un back-end simple para probar. Si ya estás familiarizado con Socket.IO, puedes desplazarte hacia abajo hasta el final de esta sección, copiar la fuente de back-end y continuar con la siguiente, si no, sigue leyendo.

Módulos requeridos

Solo necesitaremos socket.io. Puedes instalarlo directamente usando el comando npm como este:

O crea un archivo package.json, coloca esta línea en la sección dependencies:

Y ejecuta el comando npm install.

Creación del servidor Socket.IO

Como no necesitamos un framework web complicado como Express, podemos crear el servidor usando Socket.IO:

Eso es todo lo que necesitas para configurar el servidor Socket.IO. Si inicias tu aplicación, deberías ver un resultado similar en la consola:

Y deberías poder acceder al archivo socket.io.js en tu navegador en http://localhost:8080/socket.io/socket.io.js:

Manejando las conexiones

Manejaremos todas las conexiones entrantes en el detector de eventos connection del objeto io.sockets:

El atributo socket pasado a la devolución de llamada es el cliente que se conectó y podemos escuchar los eventos en él.

Un detector básico

Ahora agregaremos un detector de eventos básico en la devolución de llamada anterior. Enviará los datos recibidos, de vuelta al cliente usando el método socket.emit():

echo es el nombre del evento personalizado que usaremos más adelante.

Un oyente con reconocimiento

También usaremos reconocimientos en nuestra biblioteca. Esta característica te permite pasar una función como tercer parámetro del método socket.emit(). Esta función se puede llamar en el servidor para enviar algunos datos al cliente:

Esto te permite responder al cliente sin necesidad de que se escuche ningún evento (lo cual es útil si solo deseas solicitar algunos datos del servidor).

Ahora nuestro back-end de prueba está completo. El código debería verse así (este es el código que deberías copiar si omites esta sección):

Ahora debes ejecutar la aplicación y dejarla ejecutándose antes de continuar con el resto del tutorial.


Preparación: El front-end

Por supuesto, necesitaremos algo de HTML para probar nuestra biblioteca. Tenemos que incluir AngularJS, socket.io.js de nuestro back-end, nuestra biblioteca angular-socket.js y un controlador AngularJS básico para ejecutar algunas pruebas. El controlador se incluirá en el <head> del documento para simplificar el flujo de trabajo:

Esto es todo lo que necesitamos por ahora, volveremos a la etiqueta script vacía más tarde ya que aún no tenemos la biblioteca.


Creando la biblioteca AngularJS Socket.IO

En esta sección crearemos la biblioteca angular-socket.js. Todo el código debe estar insertado en este archivo.

El módulo

Comencemos creando el módulo para nuestra librería:

No tenemos ninguna dependencia, por lo que la matriz en el segundo argumento de angular.module() está vacía, pero no la elimines por completo u obtendrás un error $injector:nomod. Esto sucede porque la forma de un argumento de angular.module() recupera una referencia al módulo ya existente, en lugar de crear uno nuevo.

El proveedor

Los proveedores son una de las formas de crear servicios de AngularJS. La sintaxis es simple: el primer argumento es el nombre del servicio (¡no el nombre del proveedor!) y el segundo es la función constructora del proveedor:

Opciones de configuración

Para que la biblioteca sea reutilizable, necesitaremos permitir cambios en la configuración de Socket.IO. Primero definamos dos variables que contendrán la URL para la conexión y el objeto de configuración (el código en este paso va a la función $socketProvider()):

Ahora que estas variables no están disponibles fuera de la función $socketProvider() (son algo privadas), tenemos que crear métodos (establecedores) para cambiarlas. Por supuesto, podríamos hacerlas públicas así:

Pero:

  1. Tendríamos que usar Function.bind() más tarde para acceder al contexto apropiado para this
  2. Si usamos establecedores, podemos validar para asegurarnos de que se establezcan los valores adecuados; no queremos poner false como la opción 'tiempo de espera de conexión'.

Se puede ver una lista completa de opciones para el cliente de Socket.IO en su wiki de GitHub. Crearemos un setter o establecedor para cada uno de ellos más uno para la URL. Todos los métodos parecen similares, por lo que explicaré el código de uno de ellos y pondré el resto a continuación.

Definamos el primer método:

Esto debe verificar el tipo de parámetro que le pasamos:

Si es el que esperábamos, establece la opción:

Si no, debería lanzar una excepción de tipo TypeError:

Para el resto de ellos, podemos crear una función auxiliar para mantenerlo en el modelo DRY:

Simplemente arroja un TypeError si el tipo es incorrecto; de lo contrario, establece el valor. Aquí está el código para el resto de opciones:

Puedes reemplazarlo con un solo método setOption(), pero parece más fácil escribir el nombre de la opción en mayúsculas, en lugar de pasarlo como una cadena con espacios.

La función Factory

Esta función creará el objeto de servicio que podremos usar más adelante (por ejemplo, en controladores). Primero, llamemos a la función io() para conectarnos al servidor Socket.IO:

Ten en cuenta que estamos asignando la función a la propiedad $get del objeto creado por el proveedor; esto es importante ya que AngularJS usa esa propiedad para llamarlo. También ponemos $rootScope como parámetro. En este punto, podemos usar la inyección de dependencia de AngularJS para acceder a otros servicios. Lo usaremos para propagar cambios a cualquier modelo en las devoluciones de llamada de Socket.IO.

Ahora la función necesita devolver un objeto:

Pondremos todos los métodos para el servicio en él.

El método on()

Este método adjuntará un detector de eventos al objeto de socket, por lo que podemos utilizar cualquier dato enviado desde el servidor:

Usaremos socket.on() de Socket.IO para adjuntar nuestra devolución de llamada y llamarla en el método $scope.$apply() de AngularJS. Esto es muy importante, porque los modelos solo se pueden modificar dentro de él:

Primero, tenemos que copiar los argumentos a una variable temporal para poder usarlos más tarde. Los argumentos son, por supuesto, todo lo que el servidor nos envió:

A continuación, podemos llamar a nuestra devolución de llamada usando Function.apply() para pasarle argumentos:

Cuando el emisor de eventos socket llama a la función de escucha, usa $rootScope.$apply() para llamar a la devolución de llamada proporcionada como segundo argumento del método .on(). De esta manera, puedes escribir tus oyentes de eventos como lo harías para cualquier otra aplicación usando Socket.IO, pero puedes modificar los modelos de AngularJS en ellos.

El método off()

Este método eliminará uno o todos los detectores de eventos para un evento determinado. Esto te ayuda a evitar pérdidas de memoria y comportamientos inesperados. Imagina que estás usando ngRoute y adjuntas pocos oyentes en cada controlador. Si el usuario navega a otra vista, tu controlador se destruye, pero el detector de eventos permanece adjunto. Después de algunas navegaciones, tendremos una pérdida de memoria.

Solo tenemos que verificar si se proporcionó la devolución de llamada (o el callback) y llamar a socket.removeListener() o socket.removeAllListeners():

El método emit()

Este es el último método que necesitamos. Como sugiere el nombre, este método enviará datos al servidor:

Dado que Socket.IO admite reconocimientos, verificaremos si se proporcionó el callback. Si lo fue, usaremos el mismo patrón que en el método on() para llamar a la devolución de llamada dentro de $scope.$apply():

Si no hay callback, podemos simplemente llamar a socket.emit():


Uso

Para probar la biblioteca, crearemos un formulario simple que enviará algunos datos al servidor y mostrará la respuesta. Todo el código JavaScript en esta sección debe ir en la etiqueta <script> en el <head> de tu documento y todo el HTML en tu <body>.

Creando el módulo

Primero tenemos que crear un módulo para nuestra aplicación:

Observa que 'socket.io' en la matriz, en el segundo parámetro, le dice a AngularJS que este módulo depende de nuestra biblioteca Socket.IO.

La función de configuración

Dado que ejecutaremos desde un archivo HTML estático, tenemos que especificar la URL de conexión para Socket.IO. Podemos hacer esto usando el método config() del módulo:

Como puedes ver, AngularJS inyecta automáticamente nuestro $socketProvider.

El controlador

El controlador será responsable de toda la lógica de la aplicación (la aplicación es pequeña, por lo que solo necesitamos uno):

$scope es un objeto que contiene todos los modelos del controlador, es la base del enlace de datos bidireccional de AngularJS. $socket es nuestro servicio Socket.IO.

Primero, crearemos un oyente para el evento 'echo' que será emitido por nuestro servidor de prueba:

Más adelante mostraremos $scope.serverResponse, en HTML, usando las expresiones de AngularJS.

Ahora también habrá dos funciones que enviarán los datos: una usando el método básico emit() y otra usando emit() con una devolución de llamada de reconocimiento:

Tenemos que definirlos como métodos de $scope para poder llamarlos desde la directiva ngClick en HTML.

El HTML

Aquí es donde AngularJS brilla: podemos usar HTML estándar con algunos atributos personalizados para unir todo.

Comencemos por definir el módulo principal usando una directiva ngApp. Coloca este atributo en la etiqueta <body> de tu documento:

Esto le dice a AngularJS que debería arrancar tu aplicación usando el módulo example.

Después de eso, podemos crear un formulario básico para enviar datos al servidor:

Usamos algunos atributos personalizados y directivas AngularJS allí:

  • ng-controller: Vincula el controlador especificado a este elemento, lo que te permite usar valores de su alcance.
  • ng-model: Crea un enlace de datos bidireccional entre el elemento y la propiedad de alcance especificada (un modelo), lo que te permite obtener valores de este elemento y modificarlo dentro del controlador.
  • ng-click: Adjunta un detector de eventos de tipo click que ejecuta una expresión específica (lee más sobre las expresiones de AngularJS)

Las llaves dobles también son expresiones de AngularJS, serán evaluadas (no te preocupes, no usa eval() de JavaScript) y su valor se insertará allí.

Si has hecho todo correctamente, deberías poder enviar datos al servidor haciendo clic en los botones y ver la respuesta en las etiquetas <div> correspondientes.


En resumen

En esta primera parte del tutorial, creamos la biblioteca Socket.IO para AngularJS que nos permitirá aprovechar WebSockets en nuestras aplicaciones de una sola página. En la segunda parte, te mostraré cómo puedes mejorar la capacidad de respuesta de tus aplicaciones usando esta combinación.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.