MEAN STACK - Nivel 3

Clase 1

  • ¿Que es AngularJS?
  • Implementacion
  • Directivas
  • TP

¿Que es AngularJS?

AngularJS, o simplemente Angular, es un framework de JavaScript de código abierto, mantenido por Google, que se utiliza para crear y mantener aplicaciones web de una sola página. Su objetivo es aumentar las aplicaciones basadas en navegador con capacidad de Modelo Vista Controlador (MVC), en un esfuerzo para hacer que el desarrollo y las pruebas sean más fáciles.

La biblioteca lee el HTML que contiene atributos de las etiquetas personalizadas adicionales, entonces obedece a las directivas de los atributos personalizados, y une las piezas de entrada o salida de la página a un modelo representado por las variables estándar de JavaScript. Los valores de las variables de JavaScript se pueden configurar manualmente, o recuperados de los recursos JSONestáticos o dinámicos.

Framework

En el desarrollo de software, un framework o infraestructura digital, es una estructura conceptual y tecnológica de soporte definido, normalmente con artefactos o módulos concretos de software, que puede servir de base para la organización y desarrollo de software. Típicamente, puede incluir soporte de programas, bibliotecas, y un lenguaje interpretado, entre otras herramientas, para así ayudar a desarrollar y unir los diferentes componentes de un proyecto.

Libreria

En informática, una biblioteca (del inglés library) es un conjunto de implementaciones funcionales, codificadas en un lenguaje de programación, que ofrece una interfaz bien definida para la funcionalidad que se invoca.

Framework

MVC

Libreria

M ó V ó C

Ejemplos de librerias

  • React
  • Vue
  • JQuery

Implementacion

  • Angular es un framework JS
  • Se ejecuta en el cliente
  • Actua sobre el DOM
  • Utiliza JQuery
<!doctype html>
<html ng-app>
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
  </head>
  <body>
    <div>
      <label>Name:</label>
      <input type="text" ng-model="yourName" placeholder="Enter a name here">
      <hr>
      <h1>Hello {{yourName}}!</h1>
    </div>
  </body>
</html>

ng-app

ng-model

{{yourName}}

Directivas

Las directivas son marcadores en un elemento del DOM (igual que un atributo, nombre de elemento, clase, etc) que le dicen al compilador HTML de Angular, que debe asociar esea directiva con un comportamiento (por ejemplo agregandole eventListeners) o o tansformando ese elemento y sus hijos.

HTML Compiler

Recorre el DOM buscando las diretivas que haya y las asocia a un scope ("alcance" o "espacio") y produce una nueva view (vista).

De esta forma el scope y la vista quedan unidos y conectados a traves del model (modelo), y si el scope cambia, se vera reflejado en la vista. Y si alguna interaccion del usuario cmabia el modelo en la vista, se cambiara en el scope

Como se compila una directiva

  1. $compile recorre el DOM encontrando directivas si las hay. Si encuentra un elemento que coincide con una directiva, entonces la directiva es agregada  a la lista de directivas que coinciden con ese elemento. Un elemento puede tener muchas directivas.

  2. Una vez que se identificaron todas las directivas, estas son ordenadas por prioridad (priority: 0) desde la mas alta a la mas baja. Cada directiva es ejecutada y tiene la oportunidad de modificar el DOM. Cada directiva devuelve entonces una funcion link. Estas funciones link son combinadas en una sola que invoca a las funciones link de cada directiva.

  3. $compile conecta el template con el scope a la funcion link del paso anterior (la que combina a las demas). por lo tanto se llama a las funciones link de cada directiva, registrando listeners en los elementos y seteando $watchs con el scope de cada directiva.

Directivas de Angular

Modulos

Son contenedores para las diferentes partes de nuestra aplicacion.

ngApp

  • Designa el elemento root de la aplicacion

  • Las aplicaciones no pueden anidarse

  • Se ejecuta con la funcion module()

<body ng-app="ngAppDemo">
    <div ng-controller="ngAppDemoController">
        I can add: {{a}} + {{b}} =  {{ a+b }}
    </div>
</body>
angular.
    module('ngAppDemo', []).
    controller('ngAppDemoController', function($scope) {
      $scope.a = 1;
      $scope.b = 2;
});

Controlador

Los controladores en AngularJS son objetos que permiten desarrollar la lógica de la aplicación, enlaza el ámbito, $scope, con la vista y permite tener un control total de los datos. Explicándolo de otra manera, es el encargado de gestionar los eventos.

$log

console.log() de angular

$timeout

setTimeout de angular

Clase 4

<div ng-repeat="n in [42, 42, 43, 43] track by $index">
  {{n}}
</div>

<div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
  {{n}}
</div>

<div ng-repeat="model in collection track by model.id">
  {{model.name}}
</div>

<div ng-repeat="obj in collection track by $id(obj)">
  {{obj.prop}}
</div>

ng-repeat track by

$watch(expression, listener)

Registra un listener como callback para watchExpression.

Dicho de otra forma, cuando se crea un @dta binding@ en Angular, se crea automaticamente un $watch que va a estar escuchando cualquier cambio en esa variable, ya sea en el Scope de la vista o del controlador.

$scope.$watch(
    function(scope) { return scope.data.myVar },
    function(newValue, oldValue) {
       console.log('oldValue', oldValue);
       console.log('newValue', newValue);
    }
);

$digest()

Procesa todos los watchers en un loop constante. Es quien se encarga de mantener actualizadas las variables en el "data binding". Llama a las funciones de cada $watch que encuentra.

Si ve que los valores de cada $watch cambiaron, llama a la funcion del $watch.

 

$scope.$digest()

$digest()

Realiza lo que se llama dirty-checking. Recorre todos los watch revisando si alguno informa de un cambio,  si alguno cambio, se corre de nuevo, hasta asegurarse de que ninguno necesite ser actualizado.

El $digest loop se dispara siempre y cuando el cambio de valor suceda en el contexto de angular.

 

$scope.$digest()

$apply()

Se utiliza para ejecutar algun codigo. Luego llama a $digest() automaticamente.

 

inyeccion de dependencias

La Inyección de Dependencias (DI - Dependency Injection) es un pilar fundamental de AngularJS, se relaciona con la forma en la que se hacen referencias desde el código. La Inyección de Dependencias es un patrón de diseño orientado a objetos. Este patrón nos dice que los objetos necesarios en una clase serán suministrados y que por tanto no necesitamos que la propia clase cree estos objetos.

 

El framework de AngularJS gestiona la inyección de dependencias, por lo tanto, nuestras dependencias, como por ejemplo de servicios, serán suministradas por AngularJS. Por ello, al crear un componente de AngularJS se deben especificar las dependencias que esperamos y será el propio framework el que nos proporcione los objetos que se solicitan. Por ejemplo, si necesitamos utilizar un servicio en un controlador, al crear el controlador debemos especificar nuestra dependencia del servicio y no intentar crear un objeto del servicio.

angular.module('app').controller('DashboardController', d);function d(a, b) { }
angular
    .module('app')
    .controller('DashboardController', DashboardController);

function DashboardController(common, dataservice) {

}
angular.module('exampleMod.services', [])
    .service('personasService', function () {
        /* 
        this.getPersonasList = function () {
            var _pList = [{
                nombre: "Soso Solicitoso",
                edad: 27,
                NIF: "123456-B"
            }, {
                nombre: "Resoso Solicitoso",
                edad: 54,
                NIF: "24681012-D"
            }];
            return _pList
        };
        */
});

angular.module("exampleMod", ['exampleMod.services']);

angular.module("exampleMod")
    .controller('personasController', 
                [
                    "$scope",
                    "personasService", 
                    function ($scope, personasService) {
                        $scope.personas = personasService.getPersonasList();
                    }
                ]
    );

Estructura de una aplicacion

Filtros

Filters

Normalizacion

Es el proceso por el cual Angular convierte y encuentra nombres.

A traves de este proceso, Angular encuentra un nombre de directiva en el DOM y puede asociarla a su respectiva directiva

<input ng-person-programmer="foo">
personProgrammer

ng-include

Creacion de directivas

4 formas de declarar una directva

<my-dir></my-dir>
<span my-dir="exp"></span>
<!-- directive: my-dir exp -->
<span class="my-dir: exp;"></span>

Directivas

myApp.directive("searchResult", function() {
   return {
       restrict: 'AECM',
       templateUrl: 'directives/searchresult.html',
       replace: true,
       scope: {
           personName: "@", // Text
           personObject: "=" // Objeto
           personFormatAddress: "&" //  funcion
       }
   }
});
<a href="#" class="list-group-item">
    <h4 class="list-group-item-heading">
        {{ personObject.name }}
    </h4>
    <p class="list-group-item-text">
        {{ formattedAddressFunction({ aperson: personObject }) }}
    </p>
</a>
<search-result 
    person-name="person.name"
    person-object="person" 
    formatted-address-function="formattedAddress(aperson)">
</search-result>

declaracion de la Directiva

template de la Directiva

definicion de la Directiva

Clase 5

  • Provider
  • Factory
  • Service
  • Constant
  • Value
  • $http
  • $q
  • Interceptors
  • JSONP en AngularJS

Servicios

Los servicios son componentes de una aplicacion que se conectan usando la injeccion de dependencias.

El servicio nunca interactua con la pagina. No esta conecatdo a ella.

Solo hay una instancia de los servicios. (singleton)

Nos permiten poner funcionalidad por fuera de los controladores y reutilizar el codigo, en contenedores "encapsulados".

Angular viene con una serie de servicios (es lo que lo define como un framework), pero tambien nos permite crear nuestros propios servicios.

Para esto define 5 tipos de servicios. Cada tipo sera como una "receta" (recipe), que posee ciertas caracteristicas especificas apra la resolucion de algun problema (patron de diseño)

angular.module('exampleMod.services', [])
    .service('personasService', function () {
        /* 
        this.getPersonasList = function () {
            var _pList = [{
                nombre: "Soso Solicitoso",
                edad: 27,
                NIF: "123456-B"
            }, {
                nombre: "Resoso Solicitoso",
                edad: 54,
                NIF: "24681012-D"
            }];
            return _pList
        };
        */
});

angular.module("exampleMod", ['exampleMod.services']);

angular.module("exampleMod")
    .controller('personasController', 
                [
                    "$scope",
                    "personasService", 
                    function ($scope, personasService) {
                        $scope.personas = personasService.getPersonasList();
                    }
                ]
    );

Service

Si un servicio nunca se va a usar , AngularJS no lo inicializará por lo tanto usando un service, nos podríamos ahorrar el gasto de crear la instancia si no llegara a usarse o al menos retrasarlo hasta que se use, mientras que con un value siempre se crearía.


Esto que puede parecer poca cosa, podría implicar gran gasto de recursos en grandes aplicaciones en las que hay gran cantidad de servicios y también debemos añadir todos los servicios que crean las librerías de terceros que usemos.

Service

function Rectangulo(tamanyoInicial) {
  this.ancho=tamanyoInicial.ancho;
  this.alto=tamanyoInicial.alto;
   
  this.setAncho=function(ancho) {
    this.ancho=ancho;
  }
   
  this.setAlto=function(alto) {
    this.alto=alto;
  }  
   
  this.getArea=function() {
    return this.ancho * this.alto;
  }
}
 
app.service("rectangulo",['tamanyoInicialRectangulo',Rectangulo]);

$http

  • Es un servicio que nos permite crear peticiones
$http({
    method: 'GET', 
    url: 'datos.json'
  }).success(function(data, status, headers, config) {
      $scope.seguro=data;
  }).error(function(data, status, headers, config) {
      alert("Ha fallado la petición. Estado HTTP:"+status);
  });
obj.metodo1(data, function(data1) {  
    obj.metodo2(data1, function(data2) {
        obj.metodo3(data2, function(data3) {
            obj.metodo4(data3, function(data4) {
                // Hasta el infinito y más allá
            })
        })
    })
})
obj  
 .metodo1(data)
 .then(obj.metodo2(data1))
 .then(obj.metodo3(data2)
 .then(obj.metodo4(data3))

$q

El servicio $q nos provee una forma facil de ejecutar funciones asincronas en serie, registrandolas en un objeto de tipo Promesa.

Las promesas pueden estar pendientes, resultas o rechazadas.

Son una sustitucion de los callbacks

 

https://carlosazaustre.es/blog/uso-de-promesas-en-angularjs/

El ciclo de vida de una aplicación en AngularJS se divide en dos fases: la de configuración y la de ejecución.

Ciclo de vida

Fase de configuración

La fase de configuración se ejecuta en primer lugar. Durante esta fase los servicios aún no pueden instanciarse (no pueden pasarse servicios por DI). El objetivo de esta fase es definir cual va a ser la configuración de nuestra aplicación a la hora de ejecutarse. Cuidado con querer configurar un servicio en la resolución de un método asíncrono en esta fase, por que el ciclo de configuración podría haber finalizado antes.
En esta fase, solo podremos inyectar constants y providers.

Fase de ejecución

La fase de ejecución es donde se ejecuta toda la lógica de la aplicación y empieza una vez ha concluido la fase de configuración. La interacción entre nuestras vistas, controladores y servicios, sucede en esta fase.
En esta fase podemos inyectar constants, values, services y factories.

app.config(function() {
    // Puede haber mas de uno
    // Se ejecutan antes que los run
    // Es codigo que se usa para configuracion
    // Un bloque config sólo existe para poder configurar un provider 
    // y ninguno de los servicios está aún creado 
});
app.run(function() {
    // Podemos usar cualquier codigo
    // todos los servicios ya está configurados 
    // y se pueden usar
});

A modo resumen, podemos decír que constant y value solo sirven para objetos simples que no necesitan de inyectar otros elementos, y que además constant (que debería guardar solo constantes) se puede utilizar para configurar la aplicación.

Por otro lado, tendríamos provider, factory y service, que nos permiten crear objetos mucho más complejos que dependen de otros objetos (por dependencia de inyecciones). Cada uno es un caso más concreto del anterior, y como gran elemento diferencial, provider permite generar una API para configurar el servicio resultante.

Constant

Puede ser una funcion, ademas de un valor.

Similar a la declaracion const de ES6.

Constant sirve para almacenar valores simples de cualquier tipo que no deben cambiar, NO podemos inyectar dependencias (DI) en su definición, y tampoco es configurable, pero SI puede inyectarse en funciones de configuración.

myApp.constant('SERVERS',
                {  
                    DEVELOPMENT: "http://localhost:8080/app", 
                    PRODUCTION:"http://myDomain.com/app"
                }
              );
myApp.config(['SERVERS', function(SERVERS){
    console.log(SERVERS.PRODUCTION);
}]);

Value

Como constant.

Varia donde puede inyectarse.

Value nos permite definir objetos simples y primitivas que se pueden inyectar únicamente durante la fase de ejecución. NO podemos inyectar dependencias (DI) en su definición ni es configurable.

myApp.value('randomize',function(){ 
    return Math.floor(Math.random()*10000);
})
myApp.value('token','a1234567890');
myApp.value('User',{'id': 'someId'})
myApp.run(['randomize', 'User', function(randomize, User){
    var num = randomize();
    User.id = num;
}]);

Service

Un servicio es una función constructor que define el servicio. Este servicio se puede inyectar únicamente durante la fase de ejecución. No obstante, SI podemos inyectar dependencias (DI) en su definición, aunque no es configurable.

myApp.service('AuthBearer', ['token', function(token) {
    this.authValue = "bearer " + token;
}]);
myApp.run(['AuthBearer', function(AuthBearer){
    console.log(AuthBearer.authValue);
}]);

myApp.controller('testController', ['AuthBearer', function(AuthBearer){
    $scope.value = AuthBearer.authValue
}])

Factory

Una factoría es un caso más genérico de service, más enfocado a la inicialización del servicio dado que no devuelve el constructor sino el objeto en sí mismo. Como en el servicio, se puede inyectar únicamente durante la fase de ejecución, y SIpodemos inyectar dependencias (DI) en su definición, aunque no es configurable.

Factory

myApp.factory('apiToken', ['$window', 'clientId', function apiTokenFactory($window, clientId) {
  var encrypt = function(data1, data2) {
    // NSA-proof encryption algorithm:
    return (data1 + ':' + data2).toUpperCase();
  };
  var secret = $window.localStorage.getItem('myApp.secret');
  var apiToken = encrypt(clientId, secret);

  return apiToken;
}]);
myApp.run(['apiToken', function(apiToken){
    console.log(apiToken);
}])

Provider

El provider es el caso más genérico de servicio, que además de generar un servicio inyectable durante la fase de ejecución e inyectar dependencias (DI) en su definición, proporciona una API para la configuración del servicio antes de que se inicie la aplicación.

myApp.provider('logger', function(){
  var logToConsole = false;

  this.enableConsole = function(flag){
    logToConsole = flag;
  };

  this.$get = function(){
    return { 
        debug: function(msg){  if(logToConsole){ console.log(msg);} }
    };
  };
})
myApp.config(['loggerProvider', function(loggerProvider){
  loggerProvider.enableConsole(true);
}])


myApp.run(['logger', function(logger){
    logger.debug('Hello world');
}])

JSONP

function showIP(data)
{
    // do stuff with JSON
}

var script = document.createElement('script');
script.src = 'http://ip.jsontest.com/?callback=showIP'

document.getElementsByTagName('head')[0].appendChild(script);
// or document.head.appendChild(script) in modern browsers
$http.jsonp('some/trusted/url', {jsonpCallbackParam: 'callback'})
.then(function successCallback(response) {
    // this callback will be called asynchronously
    // when the response is available
  }, function errorCallback(response) {
    // called asynchronously if an error occurs
    // or server returns response with an error status.
  });

Interceptor

AngularJS permite interceptar las llamadas http en segundo plano que se realizan con el soporte del propio framework, permitiendo modificar tanto el contenido de la petición como el de la respuesta.

En este tutorial veremos como configurar e implementar estos interceptores para probar a incluir una cabecera dentro de la petición http o modificar la URL de invocación al servicio de backEnd.

Lo interesante es que interceptamos TODAS las peticiones con una única configuración.

ngRoute

Instalar

https://docs.angularjs.org/api/ngRoute


Ejemplo con promesa

https://docs.angularjs.org/api/ngRoute/service/$route#example


ngRoute

var myApp = angular.module('myApp', ['ngRoute']);
myApp.config(function ($routeProvider) {
    
    $routeProvider
    .when('/', {
        templateUrl: 'pages/main.html',
        controller: 'mainController'
    })
    .when('/second', {
        templateUrl: 'pages/second.html',
        controller: 'secondController'
    })
    .when('/second/:num', {
        templateUrl: 'pages/second.html',
        controller: 'secondController'
    })
    
});
myApp.controller('secondController', ['$scope', '$log', '$routeParams', function($scope, $log, $routeParams) {    
    $scope.num = $routeParams.num || 1;
}]);
<div class="container">
    <div ng-view></div>
</div>

ngRoute

var myApp = angular.module('myApp', ['ngRoute']);

myApp.config(function ($routeProvider) {
    
    $routeProvider
    
    .when('/', {
        templateUrl: 'pages/main.html',
        controller: 'mainController'
    })
    
    .when('/second', {
        templateUrl: 'pages/second.html',
        controller: 'secondController'
    })
    
    .when('/second/:num', {
        templateUrl: 'pages/second.html',
        controller: 'secondController'
    })
    
});

myApp.controller('mainController', ['$scope', '$log', function($scope, $log) {
    
    $scope.name = 'Main';
    
}]);

myApp.controller('secondController', ['$scope', '$log', '$routeParams', function($scope, $log, $routeParams) {
    
    $scope.num = $routeParams.num || 1;
    
}]);

UI Router

ngRoute no permite cargar de forma simultanea varias vistas en una misma página.
Por otra parte, UI-Router trabaja con estados, y permite mayor interaccion con datos y metadata relacionada al route, como stateParams, o definir valores segun el state

gulp

pendientes

  • heroku
  • transclude
  • gulp

MEAN STACK - Nivel 3

By Pablo Hiyano

MEAN STACK - Nivel 3

  • 829