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.
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.
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.
MVC
M ó V ó C
<!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}}
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.
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
<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;
});<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
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);
}
);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()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()Se utiliza para ejecutar algun codigo. Luego llama a $digest() automaticamente.
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();
}
]
);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<my-dir></my-dir>
<span my-dir="exp"></span>
<!-- directive: my-dir exp -->
<span class="my-dir: exp;"></span>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
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();
}
]
);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.
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({
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))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/
Ciclo de vida
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.
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.
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);
}]);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;
}]);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
}])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.
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);
}])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');
}])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.
});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.
Instalar
https://docs.angularjs.org/api/ngRoute
Ejemplo con promesa
https://docs.angularjs.org/api/ngRoute/service/$route#example
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>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;
}]);
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