geeklab201503



geeklab201503

0 0


geeklab201503


On Github baskeboler / geeklab201503

Victor Gil, vgil@switch.com.uy, Marzo 2015

Desarrollo front end con Angular.js

Herramientas y buenas prácticas

Contenido

  • Introducción a Angular.js
    • Breve historia
    • Metas de diseño
    • Ejemplo
  • Core Concepts
    • modules
    • controllers, templates
    • services
    • scopes
    • DI
    • directives
    • filters

Contenido (cont.)

  • Integración con otras librerías "the angular way"
  • Herramientas
    • npm
    • bower
    • grunt
    • karma
  • Testing unitario
  • Automatización con protractor
  • angular 2
    • evolución

introducción

Breve historia

Desarrollado en 2009 por Miško Hevery y Adam Abrons en Brat Tech LLC para un servicio de storage online JSON que finalmente no prosperó, la librería fue publicada con licencia open source.

Abrons abandonó el proyecto y Hevery, que hoy trabaja en Google, continuó con el desarrollo y mantenimiento de la librería junto con otros empleados de Google.

introduccion

  • Es usado principalmente para desarrollar single page applications
  • Ideal para aplicaciones con muchos CRUDs
  • Separación de lógica de negocio, modelo de datos y vistas
  • Provee API para realizar peticiones AJAX con facilidad
  • Maneja el historial del browser transparentemente
  • Tests simples

Metas de Diseño

Principios

  • Desacoplar la manipulación del DOM de la lógica de aplicación
    • Facilita el testing.
  • Considerar igualmente importante el testing que escribir código de aplicación.
    • La dificultad del testing está fuertemente ligada con cómo estructuramos nuestro código.
  • Desacoplar el frontend del backend.
    • Permite el desarrollo en paralelo

herramientas

Una vez instalado node.js, instalamos lo siguiente:
$ npm install bower -g
$ npm install grunt-cli -g
$ npm install karma
$ npm install yo generator-angular

Ejemplo (Hello World)

Invoice:
Quantity:
Costs:
Total: {{qty * cost | currency}}

Notar: attr ng-app, ng-model y expresión en {{ }}

Ejemplo (cont.)

Controllers

  • Contiene sólo lógica de negocio
  • Expone datos y funciones en objeto $scope, accesibles desde la vista.
  • Se asocia al DOM desde la vista con la directiva ng-controller o desde module.config() a traves de los servicios de routing (p.e.: ngRoute o ui-router).

controllers (cont.)

js
angular.module('MyApp')
  .controller('MyCtrl', function($scope) {
    $scope.texto = 'Hello World';
    $scope.onButtonClick = function() {
			// modify $scope, use services, etc.
    };
  });

{{texto}}

Click Me

controllers (2-way data binding)

directives

  • Angular.js nos permite extender HTML con nuevos elementos y atributos mediante directivas
    • Más específicamente, son "marcadores" en un elemento DOM (p.e.: atributos, nombre de elemento, comentario o clase CSS) que le indican al framework que asocie un comportamiento específico a ese elemento DOM y/o transforme ese elemento y sus hijos

Directives

directives

dependency injection

Patrón de diseño que se encarga de cómo los componentes obtienen acceso de sus dependencias. El servicio $injector es el encargado de la creación de estos componentes, resolver sus dependencias y proveerlos a otros componentes cuando sean requeridos.

DI es usado en todos lados a lo largo y ancho de una aplicación angular

dependency injection 2

angular.module('myModule', [])
.factory('serviceId', ['depService', function(depService) {
  // ...
}])
.directive('directiveName', ['depService', function(depService) {
  // ...
}])
.filter('filterName', ['depService', function(depService) {
  // ...
}]);
	
factory methods
angular.module('myModule', [])
.config(['depProvider', function(depProvider) {
  // ...
}])
.run(['depService', function(depService) {
  // ...
}]);
module methods

dependency injection 3

someModule.controller('MyController', 
	['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
...
$scope.aMethod = function() {
...
}
...
}]);

dependency injection 4

Existen 3 formas de inyectar dependencias a un componente

  • inline array annotation
    • app.controller('Ctrl', ['$scope', 'greeter', function($scope, greeter) {..}]);
    • es la recomendada
  • a través de $inject
    • MyController.$inject = ['$scope', 'greeter'];
  • Implícitamente. Podemos inyectar las dependencias simplemente agregando un parametro a la función con el nombre del componente.
    • Puede romperse al ejecutar un minifier o un obfuscator
    • Existen herramientas para pasarlo automáticamente al formato inline array

Scopes

  • Qué es el scope?
    • El scope es el objeto que se refiere al application model
    • Es el contexto de ejecución para las {{expressions}} en nuestra vista.
    • La API de scopes provee funciones para observar ($watch) cambios en el modelo y propagar eventos ($apply).

Scopes

Isolated scope en una directiva.

Scopes

scopes

unit tests

JavaScript is a dynamically typed language which comes with great power of expression, but it also comes with almost no help from the compiler.
  • DI facilita el testing porque podemos hacer mocks de cualquier dependencia al testear un componente.
  • Herramientas para unit tests
    • Karma - programa de linea que inicia un browser y ejecuta los tests en su runtime.
    • Jasmine - framework de

unit tests

describe("sorting the list of users", function() {
  // individual tests go here
});
describe('sorting the list of users', function() {
  it('sorts in descending order by default', function() {
    // your test assertion goes here
  });
});
describe('sorting the list of users', function() {
  it('sorts in descending order by default', function() {
    var users = ['jack', 'igor', 'jeff'];
    var sorted = sortUsers(users);
    expect(sorted).toEqual(['jeff', 'jack', 'igor']);
  });
});

unit tests

Ejemplo grunt+karma+jasmine

e2e tests

El equipo de Angular.js ha construido una herramienta llamada protractor para ejecutar tests e2e.

  • Protractor es un programa node.js que ejecuta tests e2e escritos en javascript
  • Los tests usan el formato Jasmine

e2e tests

e2e tests (ejemplo)

describe('TODO list', function() {
  it('should filter results', function() {

    // Find the element with ng-model="user" and type "jacksparrow" into it
    element(by.model('user')).sendKeys('jacksparrow');

    // Find the first (and only) button on the page and click it
    element(by.css(':button')).click();

    // Verify that there are 10 tasks
    expect(element.all(by.repeater('task in tasks')).count()).toEqual(10);

    // Enter 'groceries' into the element with ng-model="filterText"
    element(by.model('filterText')).sendKeys('groceries');

    // Verify that now there is only one item in the task list
    expect(element.all(by.repeater('task in tasks')).count()).toEqual(1);
  });
});

referencias

gracias

0