Angular 2 Es PDF
Angular 2 Es PDF
#angular2
Tabla de contenido
Acerca de 1
Observaciones 2
Versiones 2
Examples 3
Requisitos previos: 3
Paso 1 6
Paso 2 6
Paso 3 8
Paso 5 9
Paso 6 9
Paso 7 10
Paso 8 10
¿Ahora que? 11
Comenzando con Angular 2 con node.js / expressjs backend (ejemplo http incluido) 13
Prerrequisitos 13
Mapa vial 13
Paso 1 13
Paso 2 13
Paso 3 14
Examples 24
Examples 25
Sintaxis 31
Observaciones 31
Examples 31
Angular 2 for-loop 31
Examples 34
Examples 37
Ejemplo basico 37
Observaciones 39
Examples 39
Formulario de datos 39
Observaciones 42
Examples 42
Formulario de cambio de contraseña simple con validación de control múltiple 42
pw-change.template.html 42
pw-change.component.ts 43
pw-validators.ts 43
Angular 2: Formas reactivas (también conocidas como formas dirigidas por modelos) 46
registration-form.component.ts 46
registration-form.html 47
app.module.ts 47
app.component.ts 47
app.component.html 48
validadores.ts 49
Introducción 51
Examples 51
Animación básica: hace la transición de un elemento entre dos estados controlados por un a 51
Examples 53
Angular2 CanActivate 53
Observaciones 54
Examples 54
Configuración básica 54
Examples 57
Entrada() 57
Introducción 59
Examples 59
Examples 60
Parámetros 64
Examples 64
Introducción 66
Examples 66
Requerimientos 68
Examples 69
Introducción 71
Examples 71
Usando barril 71
Capítulo 19: Bootstrap módulo vacío en angular 2 72
Examples 72
Un modulo vacío 72
Bootstrapping su módulo 72
Introducción 74
Examples 74
Introducción 76
Examples 76
* ngPara tubo 77
Introducción 78
Sintaxis 78
Examples 78
Para ejecutar una función al principio o al final de * ngFor loop Usando * ngIf 79
Examples 81
Introducción 84
Examples 84
Un componente simple 84
Plantillas y Estilos 84
Probando un componente 85
Componentes de anidación 87
Capítulo 25: Configuración de la aplicación ASP.net Core para trabajar con Angular 2 y Typ 88
Introducción 88
Examples 88
Introducción 94
Examples 94
Estructura de archivos 94
Servicio y modulo 94
Compilacion 95
Ajustes de NPM 96
Integración continua 97
Examples 99
Archivos de configuración 99
.gitignore 99
.npmignore 99
gulpfile.js 100
index.d.ts 100
index.js 100
paquete.json 100
Publicar 103
Sintaxis 104
Examples 104
Examples 106
Capítulo 30: Depuración de la aplicación mecanografiada Angular2 utilizando código de Visu 109
Examples 109
Examples 111
Observaciones 112
Examples 112
* ngPara 113
Sintaxis 118
Examples 118
Introducción 123
Examples 123
AsyncPipe 123
Capítulo 35: Directrices de atributos para afectar el valor de las propiedades en el nodo 126
Examples 126
@HostBinding 126
Examples 127
Md2Seleccionar 127
Md2Tooltip 127
Md2Toast 127
Md2Datepicker 128
Examples 129
Capítulo 38: Ejemplo para rutas como / route / subruta para urls estáticas 131
Examples 131
Observaciones 132
Examples 132
Examples 135
@Entrada() 135
Examples 137
ResolveData 140
Observaciones 145
Examples 145
Bootstrapping 145
Examples 153
Observaciones 155
Examples 155
OnInit 155
EnDestroy 156
OnChanges 156
AfterContentInit 156
AfterContentChecked 157
AfterViewInit 157
AfterViewChecked 158
DoCheck 158
Observaciones 159
Examples 159
Sintaxis 163
Parámetros 163
Examples 163
Introducción 168
Examples 168
Observaciones 176
Examples 176
Examples 179
Introducción 184
Observaciones 184
Examples 184
Introducción 185
Parámetros 185
Observaciones 185
Examples 185
Introducción 194
Examples 194
Examples 196
Introducción 197
Examples 197
5) Importe nuestro UserReducer en nuestro módulo principal para construir la Store 200
6) Utilice los datos de la Store para mostrar información en nuestra vista 201
Parámetros 204
Observaciones 204
Examples 208
Introducción 210
Examples 210
El tubo 210
Examples 213
Introducción 215
Examples 215
Introducción 217
Examples 217
Examples 219
Instalar 219
Verificar 219
Examples 228
BASIC 228
Obtener estado actual 229
Examples 231
Capítulo 64: Sujetos y observables angulares RXJS con solicitudes API 233
Observaciones 233
Examples 233
Introducción 236
Sintaxis 236
Examples 236
Introducción 237
Examples 237
Introducción 240
Parámetros 240
Observaciones 240
Examples 240
Ejemplo 242
hotel-booking.component.ts 242
hotel-reservation.template.html 242
Salida 242
Código 243
Salida 243
Observaciones 249
Examples 249
Introducción 250
Examples 250
NPM 250
Nota 250
Examples 252
Creditos 254
Acerca de
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: angular-2
It is an unofficial and free Angular 2 ebook created for educational purposes. All the content is
extracted from Stack Overflow Documentation, which is written by many hardworking individuals at
Stack Overflow. It is neither affiliated with Stack Overflow nor official Angular 2.
The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/es/home 1
Capítulo 1: Empezando con Angular 2
Observaciones
Esta sección proporciona una descripción general de cómo instalar y configurar Angular2 + para
su uso en diversos entornos e IDE mediante herramientas como la comunidad desarrollada de
angular-cli .
Versiones
4.3.3 2017-08-02
4.3.2 2017-07-26
4.3.1 2017-07-19
4.3.0 2017-07-14
4.2.0 2017-06-08
4.1.0 2017-04-26
4.0.0 2017-03-23
2.3.0 2016-12-08
2.2.0 2016-11-14
2.1.0 2016-10-13
2.0.2 2016-10-05
2.0.1 2016-09-23
2.0.0 2016-09-14
2.0.0-rc.7 2016-09-13
2.0.0-rc.6 2016-08-31
2.0.0-rc.5 2016-08-09
2.0.0-rc.4 2016-06-30
https://riptutorial.com/es/home 2
Versión Fecha de lanzamiento
2.0.0-rc.3 2016-06-21
2.0.0-rc.2 2016-06-15
2.0.0-rc.1 2016-05-03
2.0.0-rc.0 2016-05-02
Examples
Instalar angular2 con angular-cli
Este ejemplo es una configuración rápida de Angular 2 y cómo generar un proyecto de ejemplo
rápido.
Requisitos previos:
• Node.js v4 o superior.
• npm v3 o mayor o hilo .
ng new PROJECT_NAME
cd PROJECT_NAME
ng serve
Así es, ahora tiene un proyecto de ejemplo simple hecho con Angular 2. Ahora puede navegar al
enlace que se muestra en el terminal y ver qué está ejecutando.
https://riptutorial.com/es/home 3
Para agregar a un proyecto existente
Navegue a la raíz de su proyecto actual.
Ejecuta el comando:
ng init
Esto agregará los andamios necesarios para su proyecto. Los archivos se crearán en el directorio
actual, así que asegúrese de ejecutar esto en un directorio vacío.
ng serve
Si el servidor se inició correctamente, debe mostrar una dirección en la que se ejecuta el servidor.
Por lo general es esto:
http://localhost:4200
Fuera de la caja, este servidor de desarrollo local está conectado con la recarga de módulos
calientes, por lo que cualquier cambio en el html, mecanografiado o css, hará que el navegador
se vuelva a cargar automáticamente (pero se puede desactivar si se desea).
# The command below will generate a component in the folder you are currently at
ng generate component my-generated-component
# Using the alias (same outcome as above)
ng g component my-generated-component
https://riptutorial.com/es/home 4
Tipo de andamio Uso
También puede reemplazar el nombre del tipo por su primera letra. Por ejemplo:
Construcción / Bundling
Cuando haya terminado de construir su aplicación web Angular 2 y desee instalarla en un servidor
web como Apache Tomcat, todo lo que debe hacer es ejecutar el comando de compilación con o
sin el conjunto de indicadores de producción. La producción minimiza el código y se optimiza para
un entorno de producción.
ng build
ng build --prod
Luego busque en la carpeta raíz del proyecto una carpeta /dist , que contiene la compilación.
Si desea obtener los beneficios de un paquete de producción más pequeño, también puede usar
la compilación de la plantilla Anticipada, que elimina el compilador de la plantilla de la compilación
final:
Examen de la unidad
Angular 2 proporciona pruebas unitarias integradas, y cada elemento creado por angular-cli
genera una prueba unitaria básica, que puede ampliarse. Las pruebas unitarias se escriben con
jazmín y se ejecutan a través de Karma. Para iniciar la prueba ejecuta el siguiente comando:
ng test
https://riptutorial.com/es/home 5
Este comando ejecutará todas las pruebas en el proyecto y las volverá a ejecutar cada vez que
cambie un archivo fuente, ya sea una prueba o un código de la aplicación.
Angular 2.0.0-rc.4
En este ejemplo crearemos un "¡Hola mundo!" aplicación con un solo componente raíz (
AppComponent ) por simplicidad.
Requisitos previos:
• Node.js v5 o posterior
• npm v3 o posterior
Nota: puede verificar las versiones ejecutando los node -v y npm -v en la consola /
terminal.
Paso 1
Crea e ingresa una nueva carpeta para tu proyecto. Llamémoslo angular2-example .
mkdir angular2-example
cd angular2-example
Paso 2
Antes de comenzar a escribir nuestro código de aplicación, agregaremos los 4 archivos que se
proporcionan a continuación: package.json , tsconfig.json , typings.json y systemjs.config.js .
package.json: nos permite descargar todas las dependencias con npm y proporciona una
ejecución de script simple para hacer la vida más fácil para proyectos simples. (Debería
considerar usar algo como Gulp en el futuro para automatizar tareas).
{
"name": "angular2-example",
"version": "1.0.0",
"scripts": {
"start": "tsc && concurrently \"npm run tsc:w\" \"npm run lite\" ",
"lite": "lite-server",
"postinstall": "typings install",
"tsc": "tsc",
"tsc:w": "tsc -w",
"typings": "typings"
},
https://riptutorial.com/es/home 6
"license": "ISC",
"dependencies": {
"@angular/common": "2.0.0-rc.4",
"@angular/compiler": "2.0.0-rc.4",
"@angular/core": "2.0.0-rc.4",
"@angular/forms": "0.2.0",
"@angular/http": "2.0.0-rc.4",
"@angular/platform-browser": "2.0.0-rc.4",
"@angular/platform-browser-dynamic": "2.0.0-rc.4",
"@angular/router": "3.0.0-beta.1",
"@angular/router-deprecated": "2.0.0-rc.2",
"@angular/upgrade": "2.0.0-rc.4",
"systemjs": "0.19.27",
"core-js": "^2.4.0",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.6",
"zone.js": "^0.6.12",
"angular2-in-memory-web-api": "0.0.14",
"bootstrap": "^3.3.6"
},
"devDependencies": {
"concurrently": "^2.0.0",
"lite-server": "^2.2.0",
"typescript": "^1.8.10",
"typings":"^1.0.4"
}
}
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
}
}
typings.json - Hace que TypeScript reconozca las bibliotecas que estamos usando.
{
"globalDependencies": {
"core-js": "registry:dt/core-js#0.0.0+20160602141332",
"jasmine": "registry:dt/jasmine#2.2.0+20160621224255",
"node": "registry:dt/node#6.0.0+20160621231320"
}
}
/**
* System configuration for Angular 2 samples
https://riptutorial.com/es/home 7
* Adjust as necessary for your application's needs.
*/
(function(global) {
// map tells the System loader where to look for things
var map = {
'app': 'app', // 'dist',
'@angular': 'node_modules/@angular',
'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
'rxjs': 'node_modules/rxjs'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main.js', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' },
};
var ngPackageNames = [
'common',
'compiler',
'core',
'forms',
'http',
'platform-browser',
'platform-browser-dynamic',
'router',
'router-deprecated',
'upgrade',
];
// Individual files (~300 requests):
function packIndex(pkgName) {
packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' };
}
// Bundled (~40 requests):
function packUmd(pkgName) {
packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js',
defaultExtension: 'js' };
}
// Most environments should use UMD; some (Karma) need the individual index files
var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
// Add package entries for angular packages
ngPackageNames.forEach(setPackageConfig);
var config = {
map: map,
packages: packages
};
System.config(config);
})(this);
Paso 3
Instalemos las dependencias escribiendo
npm install
En la consola / terminal.
Etapa 4
https://riptutorial.com/es/home 8
Crea index.html dentro de la carpeta angular2-example .
<html>
<head>
<title>Angular2 example</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 1. Load libraries -->
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. Display the application -->
<body>
<my-app></my-app>
</body>
</html>
Sin embargo, Angular todavía no sabe qué renderizar. Para decirle eso, definiremos AppComponent .
Paso 5
Cree una subcarpeta llamada app donde podamos definir los componentes y servicios que
conforman nuestra aplicación. (En este caso, sólo se va a contener el AppComponent código y
main.ts ).
mkdir app
Paso 6
Crea el archivo app/app.component.ts
@Component({
selector: 'my-app',
template: `
<h1>{{title}}</h1>
<ul>
<li *ngFor="let message of messages">
{{message}}
</li>
</ul>
`
})
https://riptutorial.com/es/home 9
export class AppComponent {
title = "Angular2 example";
messages = [
"Hello World!",
"Another string",
"Another one"
];
}
¿Qué esta pasando? Primero, estamos importando el decorador @Component que usamos para
darle a Angular la etiqueta y la plantilla HTML para este componente. Luego, estamos creando la
clase AppComponent con variables de title y messages que podemos usar en la plantilla.
<h1>{{title}}</h1>
<ul>
<li *ngFor="let message of messages">
{{message}}
</li>
</ul>
Estamos mostrando la variable de title en una etiqueta h1 y luego hacemos una lista que
muestra cada elemento de la matriz de messages usando la directiva *ngFor . Para cada elemento
de la matriz, *ngFor crea una variable de message que usamos dentro del elemento li . El resultado
será:
<h1>Angular 2 example</h1>
<ul>
<li>Hello World!</li>
<li>Another string</li>
<li>Another one</li>
</ul>
Paso 7
Ahora creamos un archivo main.ts , que será el primer archivo que Angular main.ts .
bootstrap(AppComponent);
Estamos importando la función bootstrap y la clase AppComponent , luego usamos bootstrap para
decirle a Angular qué componente usar como raíz.
Paso 8
Es hora de encender tu primera aplicación. Tipo
https://riptutorial.com/es/home 10
npm start
¿Ahora que?
Consulte la guía oficial de Angular 2 y los otros temas en la documentación de StackOverflow .
También puede editar AppComponent para usar plantillas externas, estilos o agregar / editar
variables de componentes. Debería ver sus cambios inmediatamente después de guardar los
archivos.
Paso 4: agregue una nueva entrada con su ubicación de archivo Node.js (C: / program files /
nodejs), IMPORTANTE use los botones de flecha en el menú para mover su referencia a la parte
superior de la lista.
https://riptutorial.com/es/home 11
Paso 5: reinicie Visual Studios y ejecute una instalación npm, en su proyecto, desde la ventana
de comandos de npm
Si está intentando ejecutar un sitio Angular2 en su computadora de trabajo con Windows en XYZ
MegaCorp, es probable que tenga problemas para comunicarse con el proxy de la empresa.
Hay (al menos) dos administradores de paquetes que necesitan pasar por el proxy:
1. NPM
2. Mecanografía
proxy=http://[DOMAIN]%5C[USER]:[PASS]@[PROXY]:[PROXYPORT]/
https-proxy=http://[DOMAIN]%5C[USER]:[PASS]@[PROXY]:[PROXYPORT]/
proxy=http://[DOMAIN]%5C[USER]:[PASS]@[PROXY]:[PROXYPORT]/
https-proxy=http://[DOMAIN]%5C[USER]:[PASS]@[PROXY]:[PROXYPORT]/
rejectUnauthorized=false
Es probable que estos archivos aún no existan, por lo que puede crearlos como archivos de texto
en blanco. Se pueden agregar a la raíz del proyecto (en el mismo lugar que package.json o puede
https://riptutorial.com/es/home 12
colocarlos en %HOMEPATH% y estarán disponibles para todos sus proyectos).
La parte que no es evidente y es la razón principal por la que la gente piensa la configuración del
proxy no están funcionando es el %5C , que es la codificación URL de la \ para separar los
nombres de dominio y de usuario. Gracias a Steve Roberts por eso: usar npm detrás del proxy
corporativo .pac
Vamos a crear un simple "¡Hola mundo!" aplicación con Angular2 2.4.1 (cambio @NgModule ) con un
nodo.js (expressjs) backend.
Prerrequisitos
• Node.js v4.xx o superior
• npm v3.xx o superior o hilo
A continuación, ejecute npm install -g typescript o yarn global add typescript npm install -g
typescript yarn global add typescript para instalar typescript globalmente
Mapa vial
Paso 1
Cree una nueva carpeta (y el directorio raíz de nuestro back-end) para nuestra aplicación.
Llamémoslo Angular2-express .
línea de comando :
mkdir Angular2-express
cd Angular2-express
Paso 2
Cree el package.json (para dependencias) y app.js (para bootstrapping) para nuestra aplicación
node.js
paquete.json:
{
"name": "Angular2-express",
"version": "1.0.0",
"description": "",
"scripts": {
"start": "node app.js"
https://riptutorial.com/es/home 13
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.13.3",
"express": "^4.13.3"
}
}
app.js:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}) );
//send the index.html on every page refresh and let angular handle the routing
app.get('/*', function(req, res, next) {
console.log("Reloading");
res.sendFile('index.html', { root: __dirname });
});
A continuación, ejecute una npm install o yarn para instalar las dependencias.
Paso 3
Nuestro front-end debe estar en una carpeta llamada front dentro de nuestra carpeta Angular2-
express .
línea de comando:
mkdir front
cd front
Al igual que hicimos con nuestro back-end, nuestro front-end también necesita los archivos de
dependencia. Continuemos y systemjs.config.js los siguientes archivos: package.json ,
systemjs.config.js , tsconfig.json
paquete.json :
https://riptutorial.com/es/home 14
{
"name": "Angular2-express",
"version": "1.0.0",
"scripts": {
"tsc": "tsc",
"tsc:w": "tsc -w"
},
"licenses": [
{
"type": "MIT",
"url": "https://github.com/angular/angular.io/blob/master/LICENSE"
}
],
"dependencies": {
"@angular/common": "~2.4.1",
"@angular/compiler": "~2.4.1",
"@angular/compiler-cli": "^2.4.1",
"@angular/core": "~2.4.1",
"@angular/forms": "~2.4.1",
"@angular/http": "~2.4.1",
"@angular/platform-browser": "~2.4.1",
"@angular/platform-browser-dynamic": "~2.4.1",
"@angular/platform-server": "^2.4.1",
"@angular/router": "~3.4.0",
"core-js": "^2.4.1",
"reflect-metadata": "^0.1.8",
"rxjs": "^5.0.2",
"systemjs": "0.19.40",
"zone.js": "^0.7.4"
},
"devDependencies": {
"@types/core-js": "^0.9.34",
"@types/node": "^6.0.45",
"typescript": "2.0.2"
}
}
systemjs.config.js:
/**
* System configuration for Angular samples
* Adjust as necessary for your application needs.
*/
(function (global) {
System.config({
defaultJSExtensions:true,
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'app',
// angular bundles
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-
browser.umd.js',
https://riptutorial.com/es/home 15
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-
dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
// other libraries
'rxjs': 'npm:rxjs',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api',
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './main.js',
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
}
}
});
})(this);
tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
},
"compileOnSave": true,
"exclude": [
"node_modules/*"
]
}
A continuación, ejecute una npm install o yarn para instalar las dependencias.
Ahora que nuestros archivos de dependencia están completos. Vayamos a nuestro index.html :
index.html:
<html>
<head>
<base href="/">
<title>Angular2-express</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 1. Load libraries -->
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
https://riptutorial.com/es/home 16
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. Display the application -->
<body>
<my-app>Loading...</my-app>
</body>
</html>
Ahora estamos listos para crear nuestro primer componente. Crea una carpeta llamada app dentro
de nuestra carpeta front .
línea de comando:
mkdir app
cd app
main.ts:
app.module.ts:
@NgModule({
imports: [
BrowserModule,
HttpModule
],
declarations: [
AppComponent
],
providers:[ ],
bootstrap: [ AppComponent ]
})
export class AppModule {}
app.component.ts:
https://riptutorial.com/es/home 17
import { Component } from '@angular/core';
import { Http } from '@angular/http';
@Component({
selector: 'my-app',
template: 'Hello World!',
providers: []
})
export class AppComponent {
constructor(private http: Http){
//http get example
this.http.get('/test')
.subscribe((res)=>{
console.log(res);
});
}
}
Después de esto, compile los archivos mecanografiados en archivos javascript. Vaya a 2 niveles
desde el directorio actual (dentro de la carpeta Angular2-express) y ejecute el siguiente comando.
línea de comando:
cd ..
cd ..
tsc -p front
Angular2-express
├── app.js
├── node_modules
├── package.json
├── front
│ ├── package.json
│ ├── index.html
│ ├── node_modules
│ ├── systemjs.config.js
│ ├── tsconfig.json
│ ├── app
│ │ ├── app.component.ts
│ │ ├── app.component.js.map
│ │ ├── app.component.js
│ │ ├── app.module.ts
│ │ ├── app.module.js.map
│ │ ├── app.module.js
│ │ ├── main.ts
│ │ ├── main.js.map
│ │ ├── main.js
Angular 4 ya está disponible! En realidad, Angular usa semver desde Angular 2, lo que requiere
https://riptutorial.com/es/home 18
que se aumente el número mayor cuando se introdujeron cambios de ruptura. El equipo de
Angular pospuso las características que causan cambios de última hora, que se lanzarán con
Angular 4. Angular 3 se omitió para poder alinear los números de versión de los módulos
principales, porque el Router ya tenía la versión 3.
Según el equipo de Angular, las aplicaciones de Angular 4 consumirán menos espacio y serán
más rápidas que antes. Han separado el paquete de animación del paquete @ angular / core. Si
alguien no está utilizando el paquete de animación, el espacio adicional de código no terminará
en la producción. La sintaxis de enlace de plantilla ahora admite sintaxis de estilo if / else. Angular
4 ahora es compatible con la versión más reciente de Typescript 2.1 y 2.2. Entonces, Angular 4 va
a ser más emocionante.
Puede usar Angular-CLI (interfaz de línea de comandos), instalará todas las dependencias por
usted.
ng new Angular4-boilerplate
Ahora vamos a ver el segundo enfoque. Le mostraré cómo migrar Angular 2 a Angular 4. Para
eso necesita clonar cualquier proyecto de Angular 2 y actualizar las dependencias de Angular 2
con la dependencia de Angular 4 en su paquete.json de la siguiente manera:
https://riptutorial.com/es/home 19
"dependencies": {
"@angular/animations": "^4.1.0",
"@angular/common": "4.0.2",
"@angular/compiler": "4.0.2",
"@angular/core": "^4.0.1",
"@angular/forms": "4.0.2",
"@angular/http": "4.0.2",
"@angular/material": "^2.0.0-beta.3",
"@angular/platform-browser": "4.0.2",
"@angular/platform-browser-dynamic": "4.0.2",
"@angular/router": "4.0.2",
"typescript": "2.2.2"
}
Estas son las principales dependencias de Angular 4. Ahora puede instalar npm y luego npm
comenzar a ejecutar la aplicación. Para referencia mi package.json.
Antes de comenzar este paso, asegúrese de tener git instalado en su máquina. Abra su terminal y
clone la placa de calderas angular4 usando el siguiente comando:
[email protected]:CypherTree/angular4-boilerplate.git
npm install
npm start
Y ya ha terminado con la configuración de Angular 4. Todos los pasos son muy sencillos para que
pueda optar a cualquiera de ellos.
Angular4-boilerplate
-karma
-node_modules
-src
-mocks
-models
-loginform.ts
-index.ts
-modules
-app
-app.component.ts
-app.component.html
-login
-login.component.ts
-login.component.html
-login.component.css
-widget
-widget.component.ts
-widget.component.html
-widget.component.css
https://riptutorial.com/es/home 20
........
-services
-login.service.ts
-rest.service.ts
-app.routing.module.ts
-app.module.ts
-bootstrap.ts
-index.html
-vendor.ts
-typings
-webpack
-package.json
-tsconfig.json
-tslint.json
-typings.json
La carpeta de simulacros es para datos simulados que se utilizan para fines de prueba.
La carpeta de módulos contiene una lista de componentes como aplicación, inicio de sesión,
widget, etc. Todos los componentes contienen archivos mecanografiados, html y css. index.ts es
para exportar toda la clase.
https://riptutorial.com/es/home 21
</form>
En login.component.ts
@Component({
selector: 'login',
template: require('./login.component.html'),
styles: [require('./login.component.css')]
})
export class LoginComponent {
.....
import { LoginComponent } from './modules';
......
@NgModule({
bootstrap: [AppComponent],
declarations: [
https://riptutorial.com/es/home 22
LoginComponent
.....
.....
]
.....
})
export class AppModule { }
y después de eso npm install y npm start. ¡Aqui tienes! Puede consultar la pantalla de inicio de
sesión en su localhost. En caso de cualquier dificultad, puede referirse a la placa de caldera
angular4.
Básicamente, puedo sentir que el paquete de construcción es menor y una respuesta más rápida
con la aplicación Angular 4 y, aunque encontré Exactamente similar a Angular 2 en la
codificación.
https://riptutorial.com/es/home 23
Capítulo 2: Actualizar mecanografías
Examples
Actualice las tipografías cuando: se escriban WARN en desuso
Mensaje de advertencia:
https://riptutorial.com/es/home 24
Capítulo 3: Agregue componentes
dinámicamente usando
ViewContainerRef.createComponent
Examples
Un componente contenedor que agrega componentes dinámicos
declarativamente
Un componente personalizado que toma el tipo de un componente como entrada y crea una
instancia de ese tipo de componente dentro de sí mismo. Cuando la entrada se actualiza, el
componente dinámico agregado previamente se elimina y el nuevo se agrega en su lugar.
@Component({
selector: 'dcl-wrapper',
template: `<div #target></div>`
})
export class DclWrapper {
@ViewChild('target', {
read: ViewContainerRef
}) target;
@Input() type;
cmpRef: ComponentRef;
private isViewInitialized: boolean = false;
updateComponent() {
if (!this.isViewInitialized) {
return;
}
if (this.cmpRef) {
this.cmpRef.destroy();
}
this.resolver.resolveComponent(this.type).then((factory: ComponentFactory < any > ) => {
this.cmpRef = this.target.createComponent(factory)
// to access the created instance use
// this.cmpRef.instance.someProperty = 'someValue';
// this.cmpRef.instance.someOutput.subscribe(val => doSomething());
});
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
https://riptutorial.com/es/home 25
if (this.cmpRef) {
this.cmpRef.destroy();
}
}
}
<dcl-wrapper [type]="someComponentType"></dcl-wrapper>
Ejemplo de plunker
@Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<input type="button" value="Click me to add element" (click) = addElement()> // call the
function on click of the button
<div #parent> </div> // Dynamic component will be loaded here
</div>
`,
})
export class App {
name:string;
addElement(){
let childComponent =
this.componentFactoryResolver.resolveComponentFactory(ChildComponent);
this.componentRef = this.target.createComponent(childComponent);
}
}
childComp.ts:
@Component({
selector: 'child',
https://riptutorial.com/es/home 26
template: `
<p>This is Child</p>
`,
})
export class ChildComponent {
constructor(){
}
}
app.module.ts:
@NgModule({
imports: [ BrowserModule ],
declarations: [ App, ChildComponent ],
bootstrap: [ App ],
entryComponents: [ChildComponent] // define the dynamic component here in module.ts
})
export class AppModule {}
Ejemplo de plunker
Podemos crear componentes dinámicos y obtener las instancias de componentes en una matriz
y, finalmente, representarlos en una plantilla.
Por ejemplo, podemos considerar dos componentes de widgets, ChartWidget y PatientWidget que
extendieron la clase WidgetComponent que quería agregar en el contenedor.
ChartWidget.ts
@Component({
selector: 'chart-widget',
templateUrl: 'chart-widget.component.html',
providers: [{provide: WidgetComponent, useExisting: forwardRef(() => ChartWidget) }]
})
https://riptutorial.com/es/home 27
<p-panel [style]="{'margin-bottom':'20px'}">
<p-header>
<div class="ui-helper-clearfix">
<span class="ui-panel-title" style="font-size:14px;display:inline-block;margin-
top:2px">Chart Widget</span>
<div class="ui-toolbar-group-right">
<button pButton type="button" icon="fa-window-minimize"
(click)="minimize()"</button>
<button pButton type="button" icon="fa-refresh" (click)="refresh()"></button>
<button pButton type="button" icon="fa-expand" (click)="expand()" ></button>
<button pButton type="button" (click)="close()" icon="fa-window-close"></button>
</div>
</div>
</p-header>
some data
</p-panel>
DataWidget.ts
@Component({
selector: 'data-widget',
templateUrl: 'data-widget.component.html',
providers: [{provide: WidgetComponent, useExisting: forwardRef(() =>DataWidget) }]
})
WidgetComponent.ts
@Component({
selector: 'widget',
template: '<ng-content></ng-content>'
})
export class WidgetComponent{
}
@Component({
selector: 'dynamic-component',
template: `<div #container><ng-content></ng-content></div>`
https://riptutorial.com/es/home 28
})
export class DynamicComponent {
@ViewChild('container', {read: ViewContainerRef}) container: ViewContainerRef;
@Component({
selector: 'app-root',
templateUrl: './app/app.component.html',
styleUrls: ['./app/app.component.css'],
entryComponents: [ChartWidget, DataWidget],
})
this.dynamicComponent.resetContainer();
}
}
app.component.html
<hr>
Dynamic Components
<hr>
<widget *ngFor="let item of elements">
<div>{{item}}</div>
<div [innerHTML]="item._ngEl.nativeElement.innerHTML | sanitizeHtml">
</div>
</widget>
https://plnkr.co/edit/lugU2pPsSBd3XhPHiUP1?p=preview
https://riptutorial.com/es/home 29
Alguna modificación por @yurzui para usar el evento del mouse en los widgets
view.directive.ts
@Directive({
selector: '[view]'
})
export class ViewDirective {
constructor(private vcRef: ViewContainerRef) {}
@Input()
set view(view: ViewRef) {
this.vcRef.clear();
this.vcRef.insert(view);
}
ngOnDestroy() {
this.vcRef.clear()
}
}
app.component.ts
...
addComponent(widget: string ): void{
let component = this.dynamicComponent.addComponent(this.WidgetClasses[widget]);
let view: ViewRef = this.dynamicComponent.container.detach(0);
this.elements.push({view,component});
this.dynamicComponent.resetContainer();
}
app.component.html
https://plnkr.co/edit/JHpIHR43SvJd0OxJVMfV?p=preview
https://riptutorial.com/es/home 30
Capítulo 4: Angular - ForLoop
Sintaxis
1. <div * ngFor = "dejar elemento de elementos; dejar i = indexar"> {{i}} {{elemento}} </ div>
Observaciones
La directiva estructural *ngFor se ejecuta como un bucle en una colección y repite un fragmento de
html para cada elemento de una colección.
@View decorator ahora está en desuso. Los desarrolladores deben usar las propiedades de
template o 'templateUrl' para @Component decorator.
Examples
Angular 2 for-loop
<!doctype html>
<html>
<head>
<title>ng for loop in angular 2 with ES5.</title>
<script type="text/javascript" src="https://code.angularjs.org/2.0.0-
alpha.28/angular2.sfx.dev.js"></script>
<script>
var ngForLoop = function () {
this.msg = "ng for loop in angular 2 with ES5.";
this.users = ["Anil Singh", "Sunil Singh", "Sushil Singh", "Aradhya", 'Reena'];
};
ngForLoop.annotations = [
new angular.Component({
selector: 'ngforloop'
}),
new angular.View({
template: '<H1>{{msg}}</H1>' +
'<p> User List : </p>' +
'<ul>' +
'<li *ng-for="let user of users">' +
'{{user}}' +
'</li>' +
'</ul>',
directives: [angular.NgFor]
})
];
document.addEventListener("DOMContentLoaded", function () {
angular.bootstrap(ngForLoop);
});
</script>
https://riptutorial.com/es/home 31
</head>
<body>
<ngforloop></ngforloop>
<h2>
<a href="http://www.code-sample.com/" target="_blank">For more detail...</a>
</h2>
</body>
</html>
La directiva NgFor crea una instancia de una plantilla por elemento desde un iterable. El contexto
para cada plantilla instanciada se hereda del contexto externo con la variable de bucle dada
establecida en el elemento actual del iterable.
Opciones adicionales : NgFor proporciona varios valores exportados que pueden ser asignados
a las variables locales:
• El índice se establecerá en la iteración del bucle actual para cada contexto de plantilla.
• primero se establecerá en un valor booleano que indica si el elemento es el primero en la
iteración.
• el último se establecerá en un valor booleano que indica si el elemento es el último en la
iteración.
• incluso se establecerá en un valor booleano que indica si este elemento tiene un índice par.
• odd se establecerá en un valor booleano que indica si este elemento tiene un índice impar.
<table>
<thead>
<th>Name</th>
<th>Index</th>
</thead>
<tbody>
<tr *ngFor="let hero of heroes">
<td>{{hero.name}}</td>
</tr>
</tbody>
</table>
@Component({
https://riptutorial.com/es/home 32
selector: 'main-component',
template: '<example-component
*ngFor="let hero of heroes"
[hero]="hero"></example-component>'
})
@Component({
selector: 'example-component',
template: '<div>{{hero?.name}}</div>'
})
https://riptutorial.com/es/home 33
Capítulo 5: Angular 2 - Transportador
Examples
Prueba de enrutamiento de Navbar con transportador
describe('Navbar', () => {
beforeEach(() => {
browser.get('home'); // before each test navigate to home page.
});
function checkNavbarTexts(){
element(by.id('home-navbar')).getText().then(function(text){ // Promise
expect(text).toEqual('Home');
});
element(by.id('list-navbar')).getText().then(function(text){ // Promise
expect(text).toEqual('List');
});
element(by.id('create-navbar')).getText().then(function(text){ // Promise
expect(text).toEqual('Create');
});
}
function navigateToListPage(){
element(by.id('list-home')).click().then(function(){ // first find list-home a tag and
than click
browser.sleep(2000).then(function(){
browser.getCurrentUrl().then(function(actualUrl){ // promise
https://riptutorial.com/es/home 34
expect(actualUrl.indexOf('list') !== -1).toBeTruthy(); // check the current url is
list
});
});
});
}
});
const config = {
baseUrl: 'http://localhost:3000/',
specs: [
'./dev/**/*.e2e-spec.js'
],
exclude: [],
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
isVerbose: false,
includeStackTrace: false
},
directConnect: true,
capabilities: {
browserName: 'chrome',
shardTestFiles: false,
chromeOptions: {
'args': ['--disable-web-security ','--no-sandbox', 'disable-extensions', 'start-
maximized', 'enable-crash-reporter-for-testing']
}
},
onPrepare: function() {
const SpecReporter = require('jasmine-spec-reporter');
// add jasmine spec reporter
jasmine.getEnv().addReporter(new SpecReporter({ displayStacktrace: true }));
browser.ignoreSynchronization = false;
},
useAllAngular2AppRoots: true
};
https://riptutorial.com/es/home 35
if (process.env.TRAVIS) {
config.capabilities = {
browserName: 'firefox'
};
}
exports.config = config;
beforeEach(() => {
browser.get('http://google.com');
});
corre en cmd
protractor conf.js
https://riptutorial.com/es/home 36
Capítulo 6: Angular 2 Cambio de detección y
activación manual.
Examples
Ejemplo basico
Componente principal:
@Component({
selector: 'parent-component',
templateUrl: './parent-component.html'
})
export class ParentComponent {
users : Array<User> = [];
changeUsersActivation(user : User){
user.changeButtonState();
}
constructor(){
this.users.push(new User('Narco', false));
this.users.push(new User('Bombasto',false));
this.users.push(new User('Celeritas', false));
this.users.push(new User('Magneta', false));
}
}
changeButtonState(){
this.active = !this.active;
}
constructor(_firstName :string, _active : boolean){
this.firstName = _firstName;
this.active = _active;
}
HTML principal:
<div>
<child-component [usersDetails]="users"
(changeUsersActivation)="changeUsersActivation($event)">
</child-component>
</div>
componente hijo:
https://riptutorial.com/es/home 37
import {Component, Input, EventEmitter, Output} from '@angular/core';
import {User} from "./parent.component";
@Component({
selector: 'child-component',
templateUrl: './child-component.html',
styles: [`
.btn {
height: 30px;
width: 100px;
border: 1px solid rgba(0, 0, 0, 0.33);
border-radius: 3px;
margin-bottom: 5px;
}
`]
})
export class ChildComponent{
@Input() usersDetails : Array<User> = null;
@Output() changeUsersActivation = new EventEmitter();
triggerEvent(user : User){
this.changeUsersActivation.emit(user);
}
}
HTML hijo:
<div>
<div>
<table>
<thead>
<tr>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody *ngIf="user !== null">
<tr *ngFor="let user of usersDetails">
<td>{{user.firstName}}</td>
<td><button class="btn" (click)="triggerEvent(user)">{{user.active}}</button></td>
</tr>
</tbody>
</table>
</div>
</div>
https://riptutorial.com/es/home 38
Capítulo 7: Angular 2 Data Driven Forms
Observaciones
this.myForm = this.formBuilder.group
crea un objeto de formulario con la configuración del usuario y lo asigna a la variable this.myForm.
'loginCredentials': this.formBuilder.group
método crea un grupo de controles que consisten en un nombre de control de formulario, por
ejemplo. login y valor ['', Validators.required], donde el primer parámetro es el valor inicial de
la entrada del formulario y secons es un validador o una matriz de validadores como en 'email':
['', [Validators.required, customValidator]],
'hobbies': this.formBuilder.array
Crea una matriz de grupos donde el índice del grupo es formGroupName en la matriz y se
accede a él como:
onAddHobby() {
(<FormArray>this.myForm.find('hobbies')).push(new FormGroup({
'hobby': new FormControl('', Validators.required)
}))
}
este método de muestra agrega nuevo formGroup a la matriz. El acceso actual requiere
especificar el tipo de control al que queremos acceder, en este ejemplo, este tipo es: <FormArray>
removeHobby(index: number){
(<FormArray>this.myForm.find('hobbies')).removeAt(index);
}
Se aplican las mismas reglas que las anteriores para eliminar un control de formulario específico
de la matriz
Examples
Formulario de datos
Componente
https://riptutorial.com/es/home 39
import {Component, OnInit} from '@angular/core';
import {
FormGroup,
FormControl,
FORM_DIRECTIVES,
REACTIVE_FORM_DIRECTIVES,
Validators,
FormBuilder,
FormArray
} from "@angular/forms";
import {Control} from "@angular/common";
@Component({
moduleId: module.id,
selector: 'app-data-driven-form',
templateUrl: 'data-driven-form.component.html',
styleUrls: ['data-driven-form.component.css'],
directives: [FORM_DIRECTIVES, REACTIVE_FORM_DIRECTIVES]
})
export class DataDrivenFormComponent implements OnInit {
myForm: FormGroup;
ngOnInit() {
this.myForm = this.formBuilder.group({
'loginCredentials': this.formBuilder.group({
'login': ['', Validators.required],
'email': ['', [Validators.required, customValidator]],
'password': ['', Validators.required]
}),
'hobbies': this.formBuilder.array([
this.formBuilder.group({
'hobby': ['', Validators.required]
})
])
});
}
removeHobby(index: number){
(<FormArray>this.myForm.find('hobbies')).removeAt(index);
}
onAddHobby() {
(<FormArray>this.myForm.find('hobbies')).push(new FormGroup({
'hobby': new FormControl('', Validators.required)
}))
}
onSubmit() {
console.log(this.myForm.value);
}
}
https://riptutorial.com/es/home 40
Marcado HTML
<h3>Register page</h3>
<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<div formGroupName="loginCredentials">
<div class="form-group">
<div>
<label for="login">Login</label>
<input id="login" type="text" class="form-control" formControlName="login">
</div>
<div>
<label for="email">Email</label>
<input id="email" type="text" class="form-control" formControlName="email">
</div>
<div>
<label for="password">Password</label>
<input id="password" type="text" class="form-control" formControlName="password">
</div>
</div>
</div>
<div class="row" >
<div formGroupName="hobbies">
<div class="form-group">
<label>Hobbies array:</label>
<div *ngFor="let hobby of myForm.find('hobbies').controls; let i = index">
<div formGroupName="{{i}}">
<input id="hobby_{{i}}" type="text" class="form-control" formControlName="hobby">
<button *ngIf="myForm.find('hobbies').length > 1"
(click)="removeHobby(i)">x</button>
</div>
</div>
<button (click)="onAddHobby()">Add hobby</button>
</div>
</div>
</div>
<button type="submit" [disabled]="!myForm.valid">Submit</button>
</form>
https://riptutorial.com/es/home 41
Capítulo 8: Angular 2 Formas de
actualización
Observaciones
Angular 2 permite acceder a la instancia de ngForm creando una variable de plantilla local.
Angular 2 expone instancias de directivas como ngForm especificando la propiedad exportAs de
los metadatos de la directiva. Ahora, la ventaja aquí es que, sin mucha codificación, puede
acceder a la instancia de ngForm y usarla para acceder a los valores enviados o para verificar si
todos los campos son válidos usando propiedades (válido, enviado, valor, etc.).
(ngSubmit)= "login(f.value,f.submitted)"
Cuando se envía el formulario, f.value tiene el objeto JSON que representa los valores enviados.
Examples
Formulario de cambio de contraseña simple con validación de control
múltiple
pw-change.template.html
https://riptutorial.com/es/home 42
<label for="confirm">Confirm new password</label>
<input id="confirm" formControlName="confirm" type="password" required><br />
<div *ngIf="confirm.touched && confirm.errors.newMatchesConfirm">
The confirmation does not match.
</div>
<button type="submit">Submit</button>
</form>
pw-change.component.ts
@Component({
moduleId: module.id
selector: 'pw-change-form',
templateUrl: `./pw-change.template.html`,
directives: [REACTIVE_FORM_DIRECTIVES]
})
// Properties that store paths to FormControls makes our template less verbose
current: AbstractControl;
newPW: AbstractControl;
confirm: AbstractControl;
pw-validators.ts
https://riptutorial.com/es/home 43
var invalid = false;
if (control.value != PWChangeValidators.oldPW)
return { oldPasswordMustBeCorrect: true }
return null;
}
Una esencia que incluye algunas clases de bootstrap se puede encontrar aquí .
@Component({
selector: 'login',
template: `
<h2>Login</h2>
<form #f="ngForm" (ngSubmit)="login(f.value,f.valid)" novalidate>
<div>
<label>Username</label>
<input type="text" [(ngModel)]="username" placeholder="enter username" required>
</div>
<div>
<label>Password</label>
<input type="password" name="password" [(ngModel)]="password" placeholder="enter
password" required>
</div>
<input class="btn-primary" type="submit" value="Login">
</form>`
//For long form we can use **templateUrl** instead of template
})
if(valid){
console.log(valid);
https://riptutorial.com/es/home 44
}
}
}
Índice de aplicaciones ts
bootstrap(MyForm);
Validador personalizado
Componentes de la forma ts
@Component({
selector: 'my-form',
templateUrl: 'app/my-form.component.html',
directives: [FORM_DIRECTIVES],
styleUrls: ['styles.css']
})
export class MyForm {
email: Control;
password: Control;
group: ControlGroup;
constructor(builder: FormBuilder) {
this.email = new Control('',
Validators.compose([Validators.required, CustomValidators.emailFormat])
);
this.group = builder.group({
https://riptutorial.com/es/home 45
email: this.email,
password: this.password
});
}
onSubmit() {
console.log(this.group.value);
}
}
<div>
<label for="email">Email:</label>
<input type="email" id="email" [ngFormControl]="email">
<div>
<label for="password">Password:</label>
<input type="password" id="password" [ngFormControl]="password">
<button type="submit">Register</button>
</form>
registration-form.component.ts
import { FormGroup,
FormControl,
FormBuilder,
Validators } from '@angular/forms';
@Component({
templateUrl: "./registration-form.html"
})
export class ExampleComponent {
constructor(private _fb: FormBuilder) { }
https://riptutorial.com/es/home 46
exampleForm = this._fb.group({
name: ['DefaultValue', [<any>Validators.required, <any>Validators.minLength(2)]],
email: ['[email protected]', [<any>Validators.required, <any>Validators.minLength(2)]]
})
registration-form.html
app.module.ts
Agregue estos en su archivo app.module.ts para usar formularios reactivos
app.component.ts
https://riptutorial.com/es/home 47
export class AppComponent implements OnInit {
addForm: FormGroup;
constructor(private formBuilder: FormBuilder) {
}
ngOnInit() {
this.addForm = this.formBuilder.group({
username: ['', Validators.required],
email: ['', Validators.required],
role: ['', Validators.required],
password: ['', Validators.required],
password2: ['', Validators.required] },
{ validator: matchingPasswords('password', 'password2')
})
};
addUser() {
if (this.addForm.valid) {
var adduser = {
username: this.addForm.controls['username'].value,
email: this.addForm.controls['email'].value,
password: this.addForm.controls['password'].value,
profile: {
role: this.addForm.controls['role'].value,
name: this.addForm.controls['username'].value,
email: this.addForm.controls['email'].value
}
};
console.log(adduser);// adduser var contains all our form values. store it where you
want
this.addForm.reset();// this will reset our form values to null
}
}
}
app.component.html
<div>
<form [formGroup]="addForm">
<input type="text" placeholder="Enter username" formControlName="username" />
<input type="text" placeholder="Enter Email Address" formControlName="email"/>
<input type="password" placeholder="Enter Password" formControlName="password" />
<input type="password" placeholder="Confirm Password" name="password2"
formControlName="password2"/>
<div class='error' *ngIf="addForm.controls.password2.touched">
<div class="alert-danger errormessageadduser"
*ngIf="addForm.hasError('mismatchedPasswords')"> Passwords do
not match
</div>
</div>
<select name="Role" formControlName="role">
<option value="admin" >Admin</option>
<option value="Accounts">Accounts</option>
<option value="guest">Guest</option>
</select>
<br/>
<br/>
<button type="submit" (click)="addUser()"><span><i class="fa fa-user-plus" aria-
hidden="true"></i></span> Add User </button>
https://riptutorial.com/es/home 48
</form>
</div>
validadores.ts
FormComponent.ts
@Component({
selector: 'app-form',
templateUrl: './form.component.html',
styleUrls: ['./form.component.scss'],
providers : [FormBuilder]
})
constructor(fb: FormBuilder) {
this.form = fb.group({
FirstName : new FormControl({value: null}, Validators.compose([Validators.required,
Validators.maxLength(15)])),
LastName : new FormControl({value: null}, Validators.compose([Validators.required,
Validators.maxLength(15)])),
Email : new FormControl({value: null}, Validators.compose([
Validators.required,
Validators.maxLength(15),
Validators.pattern(this.emailRegex)]))
});
}
}
form.component.html
https://riptutorial.com/es/home 49
<form class="form-details" role="form" [formGroup]="form">
<div class="row input-label">
<label class="form-label" for="FirstName">First name</label>
<input
[formControl]="form.controls['FirstName']"
type="text"
class="form-control"
id="FirstName"
name="FirstName">
</div>
<div class="row input-label">
<label class="form-label" for="LastName">Last name</label>
<input
[formControl]="form.controls['LastName']"
type="text"
class="form-control"
id="LastName"
name="LastName">
</div>
<div class="row">
<label class="form-label" for="Email">Email</label>
<input
[formControl]="form.controls['Email']"
type="email"
class="form-control"
id="Email"
name="Email">
</div>
<div class="row">
<button
(click)="submit()"
role="button"
class="btn btn-primary submit-btn"
type="button"
[disabled]="!form.valid">Submit</button>
</div>
</div>
</form>
https://riptutorial.com/es/home 50
Capítulo 9: Angular2 animaciones
Introducción
El sistema de animación de Angular le permite crear animaciones que se ejecutan con el mismo
tipo de rendimiento nativo que las animaciones de CSS puro. También puede integrar
estrechamente su lógica de animación con el resto del código de su aplicación, para facilitar el
control.
Examples
Animación básica: hace la transición de un elemento entre dos estados
controlados por un atributo de modelo.
app.component.html
<div>
<div>
<div *ngFor="let user of users">
<button
class="btn"
[@buttonState]="user.active"
(click)="user.changeButtonState()">{{user.firstName}}</button>
</div>
</div>
</div>
app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styles: [`
.btn {
height: 30px;
width: 100px;
border: 1px solid rgba(0, 0, 0, 0.33);
border-radius: 3px;
margin-bottom: 5px;
}
`],
animations: [
trigger('buttonState', [
state('true', style({
background: '#04b104',
transform: 'scale(1)'
})),
https://riptutorial.com/es/home 51
state('false', style({
background: '#e40202',
transform: 'scale(1.1)'
})),
transition('true => false', animate('100ms ease-in')),
transition('false => true', animate('100ms ease-out'))
])
]
})
export class AppComponent {
users : Array<User> = [];
constructor(){
this.users.push(new User('Narco', false));
this.users.push(new User('Bombasto',false));
this.users.push(new User('Celeritas', false));
this.users.push(new User('Magneta', false));
}
}
changeButtonState(){
this.active = !this.active;
}
constructor(_firstName :string, _active : boolean){
this.firstName = _firstName;
this.active = _active;
}
https://riptutorial.com/es/home 52
Capítulo 10: Angular2 CanActivate
Examples
Angular2 CanActivate
Implementado en un enrutador:
El archivo canActivateRoute :
@Injectable()
export class CanActivateRoute implements CanActivate{
constructor(){}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
return true;
}
}
https://riptutorial.com/es/home 53
Capítulo 11: Angular2 en la memoria web de
la API
Observaciones
Solicité principalmente este tema porque no pude encontrar ninguna información sobre la
configuración de múltiples rutas API con Angular2-In-Memory-Web-Api. Terminé resolviéndolo yo
mismo, y pensé que esto podría ser útil para otros.
Examples
Configuración básica
mock-data.ts
return {mock};
}
}
main.ts
createDb()
Función (en este caso, MockData) que especifica las rutas de API simuladas para las solicitudes
SEED_DATA.
bootstrap(AppComponent, [
https://riptutorial.com/es/home 54
HTTP_PROVIDERS,
{ provide: XHRBackend, useClass: InMemoryBackendService },
{ provide: SEED_DATA, useClass: MockData }
]);
mock.service.ts
@Injectable()
export class MockService {
// URL to web api
private mockUrl = 'app/mock';
getData(): Promise<Mock[]> {
return this.http.get(this.mockUrl)
.toPromise()
.then(this.extractData)
.catch(this.handleError);
}
mock-data.ts
let data = [
{ id: '1', name: 'Data A' },
{ id: '2', name: 'Data B' },
{ id: '3', name: 'Data C' }
];
https://riptutorial.com/es/home 55
return { mock, data };
}
}
app/mock
app/data
https://riptutorial.com/es/home 56
Capítulo 12: Angular2 Entrada () salida ()
Examples
Entrada()
@Component({
selector: 'parent-component',
template: '<div>
<child-component [users]="users"></child-component>
</div>'
})
export class ParentComponent implements OnInit{
let users : List<User> = null;
ngOnInit() {
users.push(new User('A', 'A', '[email protected]');
users.push(new User('B', 'B', '[email protected]');
users.push(new User('C', 'C', '[email protected]');
}
}
@Component({
selector: 'child-component',
template: '<div>
<table *ngIf="users !== null">
<thead>
<th>Name</th>
<th>FName</th>
<th>Email</th>
</thead>
<tbody>
<tr *ngFor="let user of users">
<td>{{user.name}}</td>
<td>{{user.fname}}</td>
<td>{{user.email}}</td>
</tr>
</tbody>
</table>
</div>',
})
export class ChildComponent {
@Input() users : List<User> = null;
}
https://riptutorial.com/es/home 57
fname : string;
email : string;
<child-component [isSelected]="inputPropValue"></child-component>
Elemento padre ts
<div [class.simpleCssClass]="inputPropValue"></div>
Este código enviará el inputPropValue desde el componente principal al hijo y tendrá el valor que
hemos establecido en el componente principal cuando llegue allí, falso en nuestro caso. Luego
podemos usar ese valor en el componente secundario para, por ejemplo, agregar una clase a un
elemento.
https://riptutorial.com/es/home 58
Capítulo 13: Angular2 proporciona datos
externos a la aplicación antes de bootstrap
Introducción
En esta publicación, demostraré cómo pasar datos externos a la aplicación Angular antes de que
la aplicación se inicie. Estos datos externos pueden ser datos de configuración, datos heredados,
servidores renderizados, etc.
Examples
Vía de inyección de dependencia
En lugar de invocar directamente el código de inicio del Angular, envuelva el código de inicio en
una función y exporte la función. Esta función también puede aceptar parámetros.
require(["myAngular2App"], function(app) {
app.runAngular2App(legacyModel); // Input to your APP
});
https://riptutorial.com/es/home 59
Capítulo 14: Angular2 utilizando webpack
Examples
Configuración de webpack angular 2
webpack.config.js
module.exports = {
"resolve": {
"extensions": ['.ts', '.js'],
},
"module": {
"rules": [
{
"test": /\.ts$/,
"loaders": [
{
"loader": 'awesome-typescript-loader',
"options": {
"configFileName": helpers.root("./tsconfig.json")
}
},
"angular2-template-loader"
]
},
],
},
"plugins": [
https://riptutorial.com/es/home 60
"manifest": helpers.root("config/polyfills-manifest.json")
}),
// minify compiled js
new webpack.optimize.UglifyJsPlugin(),
],
}
vendor.config.js
module.exports = {
// specify vendor file where all vendors are imported
"entry": {
// optionally add your shims as well
"polyfills": [helpers.root("src/app/shims.ts")],
"vendor": [helpers.root("src/app/vendor.ts")],
},
"resolve": {
"extensions": ['.ts', '.js'],
},
"module": {
"rules": [
{
"test": /\.ts$/,
"loaders": [
{
"loader": 'awesome-typescript-loader',
"options": {
"configFileName": helpers.root("./tsconfig.json")
}
},
]
},
],
},
"plugins": [
https://riptutorial.com/es/home 61
"name": "[name]",
"context": helpers.root("src/app"),
"path": helpers.root("config/[name]-manifest.json")
}),
// minify generated js
new webpack.optimize.UglifyJsPlugin(),
],
}
helpers.js
function root(args) {
args = Array.prototype.slice.call(arguments, 0);
return path.join.apply(path, [_root].concat(args));
}
exports.root = root;
vendor.ts
import "@angular/platform-browser"
import "@angular/platform-browser-dynamic"
import "@angular/core"
import "@angular/common"
import "@angular/http"
import "@angular/router"
import "@angular/forms"
import "rxjs"
index.html
<!DOCTYPE html>
<html>
<head>
<title>Angular 2 webpack</title>
paquete.json
{
"name": "webpack example",
"version": "0.0.0",
"description": "webpack",
"scripts": {
https://riptutorial.com/es/home 62
"build:webpack": "webpack --config config/webpack.config.js",
"build:vendor": "webpack --config config/vendor.config.js",
"watch": "webpack --config config/webpack.config.js --watch"
},
"devDependencies": {
"@angular/common": "2.4.7",
"@angular/compiler": "2.4.7",
"@angular/core": "2.4.7",
"@angular/forms": "2.4.7",
"@angular/http": "2.4.7",
"@angular/platform-browser": "2.4.7",
"@angular/platform-browser-dynamic": "2.4.7",
"@angular/router": "3.4.7",
"webpack": "^2.2.1",
"awesome-typescript-loader": "^3.1.2",
},
"dependencies": {
}
}
https://riptutorial.com/es/home 63
Capítulo 15: Angular2 Validaciones
personalizadas
Parámetros
parámetro descripción
Examples
Ejemplos de validadores personalizados:
Angular 2 tiene dos tipos de validadores personalizados. Validadores síncronos como en el primer
ejemplo que se ejecutarán directamente en el cliente y validadores asíncronos (el segundo
ejemplo) que puede usar para llamar a un servicio remoto y hacer la validación por usted. En este
ejemplo, el validador debe llamar al servidor para ver si un valor es único.
return null;
}
Si su valor de control es válido, simplemente devuelve el valor nulo a la persona que llama. De lo
contrario, puede devolver un objeto que describe el error.
constructor(fb: FormBuilder) {
this.form = fb.group({
https://riptutorial.com/es/home 64
firstInput: ['', Validators.compose([Validators.required,
CustomValidators.cannotContainSpace]), CustomValidators.shouldBeUnique],
secondInput: ['', Validators.required]
});
}
Aquí usamos el FormBuilder para crear un formulario muy básico con dos cuadros de entrada. El
FromBuilder toma una matriz para tres argumentos para cada control de entrada.
1. Al inicializar:
exampleForm : FormGroup;
constructor(fb: FormBuilder){
this.exampleForm = fb.group({
name : new FormControl({value: 'default name'}, Validators.compose([Validators.required,
Validators.maxLength(15)]))
});
}
2.Después de inicializar:
this.exampleForm.controls['name'].setValue('default name');
https://riptutorial.com/es/home 65
Capítulo 16: Angular-cli
Introducción
Aquí encontrará cómo comenzar con angular-cli, generando nuevo componente / service / pipe /
module con angular-cli, agregue 3 partes como bootstrap, construya un proyecto angular.
Examples
Crear una aplicación Angular2 vacía con angular-cli
Requisitos:
Ejecute los siguientes comandos con cmd desde la nueva carpeta del directorio:
simplemente use su cmd: puede usar el comando ng generate (o simplemente ng g) para generar
componentes angulares:
https://riptutorial.com/es/home 66
1. npm install ng2-bootstrap --save o yarn add ng2-bootstrap
"scripts": [
"../node_modules/jquery/dist/jquery.js",
"../node_modules/bootstrap/dist/js/bootstrap.js"
]
Los archivos de estilo predeterminados generados y compilados por @angular/cli son css .
Yarn es una alternativa para npm, el gestor de paquetes predeterminado en @ angular / cli. Si
https://riptutorial.com/es/home 67
desea utilizar hilados como gestor de paquetes para @ angular / cli, siga estos pasos:
Requerimientos
• hilo ( npm install --global yarn o vea la página de instalación )
• @ angular / cli ( npm install -g @angular/cli o yarn global add @angular/cli )
https://riptutorial.com/es/home 68
Capítulo 17: Animación
Examples
Transición entre estados nulos
@Component({
...
animations: [
trigger('appear', [
transition(':enter', [
style({
//style applied at the start of animation
}),
animate('300ms ease-in', style({
//style applied at the end of animation
}))
])
])
]
})
class AnimComponent {
}
]
El <div> en esta plantilla crece a 50px y luego a 100px y luego se reduce a 20px al hacer clic en el
botón.
La lógica para cualquier state esté activo puede administrarse en la lógica del componente. En
este caso, el size variable del componente contiene el valor de cadena "pequeño", "mediano" o
"grande".
El elemento <div> responde a ese valor a través del trigger especificado en los metadatos de
@Component : [@size]="size" .
@Component({
template: '<div [@size]="size">Some Text</div><button
(click)="toggleSize()">TOGGLE</button>',
animations: [
trigger('size', [
state('small', style({
height: '20px'
})),
state('medium', style({
height: '50px'
})),
state('large', style({
https://riptutorial.com/es/home 69
height: '100px'
})),
transition('small => medium', animate('100ms')),
transition('medium => large', animate('200ms')),
transition('large => small', animate('300ms'))
])
]
})
export class TestComponent {
size: string;
constructor(){
this.size = 'small';
}
toggleSize(){
switch(this.size) {
case 'small':
this.size = 'medium';
break;
case 'medium':
this.size = 'large';
break;
case 'large':
this.size = 'small';
}
}
}
https://riptutorial.com/es/home 70
Capítulo 18: Barril
Introducción
Un barril es una forma de acumular exportaciones de varios módulos ES2015 en un único módulo
de conveniencia ES2015. El propio barril es un archivo de módulo ES2015 que reexporta
exportaciones seleccionadas de otros módulos ES2015.
Examples
Usando barril
Aún así, esto puede convertirse en una línea muy larga; que podría reducirse aún más.
https://riptutorial.com/es/home 71
Capítulo 19: Bootstrap módulo vacío en
angular 2
Examples
Un modulo vacío
@NgModule({
declarations: [], // components your module owns.
imports: [], // other modules your module needs.
providers: [], // providers available to your module.
bootstrap: [] // bootstrap this root component.
})
export class MyModule {}
// app.module.ts
@NgModule({
declarations: [MyRootComponent],
imports: [BrowserModule, HttpModule],
bootstrap: [MyRootComponent]
})
export class MyModule {}
Bootstrapping su módulo
platformBrowserDynamic().bootstrapModule( MyModule );
https://riptutorial.com/es/home 72
Módulo raíz de aplicación
@NgModule({
imports: [ BrowserModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Podemos arrancar una aplicación de forma estática tomando la salida de Javascript ES5 de las
clases de fábrica generadas. Entonces podemos usar esa salida para arrancar la aplicación:
Esto hará que el paquete de aplicaciones sea mucho más pequeño, ya que toda la compilación
de la plantilla ya se realizó en un paso de compilación, usando ngc o llamando directamente a sus
componentes internos.
https://riptutorial.com/es/home 73
Capítulo 20: cobertura de la prueba angular-
cli
Introducción
la cobertura de prueba se define como una técnica que determina si nuestros casos de prueba
cubren realmente el código de la aplicación y la cantidad de código que se ejerce cuando
ejecutamos esos casos de prueba.
La CLI angular ha incorporado una función de cobertura de código con solo un simple comando
ng test --cc
Examples
Una simple prueba de la base de comando angular-cli cobertura
Si desea ver las estadísticas generales de cobertura de prueba que, por supuesto, en CLI
angular, puede simplemente escribir el siguiente comando y ver la parte inferior de la ventana del
símbolo del sistema para obtener resultados.
Si desea ver la cobertura individual de las pruebas de los componentes, siga estos pasos.
https://riptutorial.com/es/home 74
tenga en cuenta que la lista de reporteros está separada por comas, ya que hemos agregado un
nuevo reportero, teamcity.
después de ejecutar este comando, puede ver la coverage la carpeta en su directorio y abrir
index.html para obtener una vista gráfica de la cobertura de la prueba.
También puede establecer el umbral de cobertura que desea alcanzar, en karma.conf.js , así.
coverageIstanbulReporter: {
reports: ['html', 'lcovonly'],
fixWebpackSourcePaths: true,
thresholds: {
statements: 90,
lines: 90,
branches: 90,
functions: 90
}
},
https://riptutorial.com/es/home 75
Capítulo 21: Cómo usar ngfor
Introducción
ngFor utiliza la directiva ngFor para crear una instancia de una plantilla para cada elemento de un
objeto iterable. Esta directiva vincula lo iterable con el DOM, por lo que si el contenido de los
iterables cambios, el contenido del DOM también se cambiará.
Examples
Ejemplo de lista desordenada
<ul>
<li *ngFor="let item of items">{{item.name}}</li>
</ul>
En este caso, tomaré el valor de índice, que es la iteración actual del bucle.
Angular2 proporciona varios valores exportados que pueden ser asignados a las variables
locales. Estos son:
• índice
• primero
• último
• incluso
• impar
Excepto el index , los otros toman un valor Boolean . Como en el ejemplo anterior que usa el
índice, se puede usar cualquiera de estos valores exportados:
https://riptutorial.com/es/home 76
<div *ngFor="let item of items; let firstItem = first; let lastItem = last">
<p *ngIf="firstItem">I am the first item and I am gonna be showed</p>
<p *ngIf="firstItem">I am not the first item and I will not show up :(</p>
<p *ngIf="lastItem">But I'm gonna be showed as I am the last item :)</p>
</div>
* ngPara tubo
@Component({
selector: 'example-component',
template: '<div>
<div *ngFor="let number of numbers | even">
{{number}}
</div>
</div>'
})
https://riptutorial.com/es/home 77
Capítulo 22: Cómo usar ngif
Introducción
* NgIf : elimina o recrea una parte del árbol DOM en función de la evaluación de una expresión.
Es una directiva estructural y las directivas estructurales modifican el diseño del DOM al agregar,
reemplazar y eliminar sus elementos.
Sintaxis
• <div * ngIf = "false"> test </div> <! - se evalúa como falso ->
• <div * ngIf = "undefined"> test </div> <! - se evalúa como falso ->
• <div * ngIf = "null"> test </div> <! - se evalúa como falso ->
• <div * ngIf = "0"> prueba </div> <! - se evalúa como falso ->
• <div * ngIf = "NaN"> test </div> <! - se evalúa como falso ->
• <div * ngIf = ""> test </div> <! - se evalúa como falso ->
• Todos los demás valores se evalúan como verdaderos.
Examples
Mostrar un mensaje de carga
Si nuestro componente no está listo y está esperando datos del servidor, podemos agregar el
cargador usando * ngIf. Pasos:
ngOnInit() {
this.loading = true;
}
y después de obtener datos completos del servidor, establezca que carga booleano en falso.
this.loading=false;
https://riptutorial.com/es/home 78
Mostrar mensaje de alerta en una condición
<p class="alert alert-success" *ngIf="names.length > 2">Currently there are more than 2
names!</p>
Para ejecutar una función al principio o al final de * ngFor loop Usando * ngIf
NgFor proporciona algunos valores que pueden ser asignados a las variables locales.
Si bien no se le permite usar *ngIf y *ngFor en el mismo div (dará un error en el tiempo de
ejecución), puede anidar el *ngIf en el *ngFor para obtener el comportamiento deseado.
</div>
</div>
Pero considere este caso de uso donde un elemento div necesita ser iterado (usando * ngFor)
y también incluye una verificación de si el elemento necesita ser eliminado o no (usando * ngIf),
https://riptutorial.com/es/home 79
pero no es preferible agregar un div adicional. En este caso, puede usar la etiqueta de template
para el * ngFor:
https://riptutorial.com/es/home 80
Capítulo 23: Compilación anticipada (AOT)
con Angular 2
Examples
1. Instalar dependencias de Angular 2 con compilador.
NOTA: para obtener los mejores resultados, asegúrese de que su proyecto se haya creado
utilizando Angular-CLI.
No tiene que realizar este paso si el proyecto ya tiene angular 2 y todas estas dependencias
instaladas. Sólo asegúrese de que el compiler está allí.
...
"angularCompilerOptions": {
"genDir": "./ngfactory"
}
...
desde la raíz de su proyecto ./node_modules/.bin/ngc -p src donde src es donde vive todo su
código angular 2. Esto generará una carpeta llamada ngfactory donde ngfactory todo el código
compilado.
https://riptutorial.com/es/home 81
En este punto deberías poder ejecutar tu proyecto. En este caso, mi proyecto se creó utilizando
Angular-CLI.
> ng serve
P. ¿Por qué necesitamos compilación? Respuesta Necesitamos una compilación para lograr un
mayor nivel de eficiencia de nuestras aplicaciones Angulares.
// ...
compile: function (el, scope) {
var dirs = this._getElDirectives(el);
var dir;
var scopeCreated;
dirs.forEach(function (d) {
dir = Provider.get(d.name + Provider.DIRECTIVES_SUFFIX);
if (dir.scope && !scopeCreated) {
scope = scope.$new();
scopeCreated = true;
}
dir.link(el, scope, d.value);
});
Array.prototype.slice.call(el.children).forEach(function (c) {
this.compile(c, scope);
}, this);
},
// ...
<ul>
<li *ngFor="let name of names"></li>
</ul>
// ...
this._text_9 = this.renderer.createText(this._el_3, '\n', null);
this._text_10 = this.renderer.createText(parentRenderNode, '\n\n', null);
this._el_11 = this.renderer.createElement(parentRenderNode, 'ul', null);
this._text_12 = this.renderer.createText(this._el_11, '\n ', null);
this._anchor_13 = this.renderer.createTemplateAnchor(this._el_11, null);
this._appEl_13 = new import2.AppElement(13, 11, this, this._anchor_13);
this._TemplateRef_13_5 = new import17.TemplateRef_(this._appEl_13,
viewFactory_HomeComponent1);
this._NgFor_13_6 = new import15.NgFor(this._appEl_13.vcRef, this._TemplateRef_13_5,
this.parentInjector.get(import18.IterableDiffers), this.ref);
// ...
https://riptutorial.com/es/home 82
En contraste, con AoT pasamos por los siguientes pasos:
Aunque el proceso anterior parece un poco más complicado, el usuario solo sigue los pasos:
Como puede ver, falta el tercer paso, lo que significa que UX más rápido / mejor, y además de
herramientas como angular2-seed y angle-cli, automatizará dramáticamente el proceso de
construcción.
La interfaz de línea de comandos de Angular CLI tiene soporte de compilación de AoT desde la
versión beta 17.
https://riptutorial.com/es/home 83
Capítulo 24: Componentes
Introducción
Los componentes angulares son elementos compuestos por una plantilla que representará su
aplicación.
Examples
Un componente simple
Para crear un componente, agregamos el decorador @Component en una clase que pasa algunos
parámetros:
Hay otros parámetros que puede configurar, pero los enumerados son los que más utilizará.
Un ejemplo simple:
@Component({
selector: 'app-required',
styleUrls: ['required.component.scss'],
// template: `This field is required.`,
templateUrl: 'required.component.html',
})
export class RequiredComponent { }
Plantillas y Estilos
@Component({
https://riptutorial.com/es/home 84
templateUrl: 'hero.component.html',
})
@Component({
template: `<div>My template here</div>`,
})
Las plantillas pueden contener estilos. Los estilos declarados en @Component son diferentes de su
archivo de estilo de aplicación, todo lo que se aplique en el componente estará restringido a este
alcance. Por ejemplo, digamos que usted agrega:
Todos los div s dentro del componente serán rojos, pero si tiene otros componentes, otros divs en
su HTML no se cambiarán en absoluto.
@Component({
styleUrls: ['hero.component.css'],
})
No debe usar los styles con require ya que no funcionará cuando compile su aplicación para
producción.
Probando un componente
hero.component.html
hero.component.ts
https://riptutorial.com/es/home 85
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-hero',
templateUrl: 'hero.component.html',
})
export class HeroComponent {
public form = new FormGroup({
name: new FormControl('', Validators.required),
});
submit(event) {
console.log(event);
console.log(this.form.controls.name.value);
}
}
hero.component.spec.ts
describe('HeroComponent', () => {
let component: HeroComponent;
let fixture: ComponentFixture<HeroComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [HeroComponent],
imports: [ReactiveFormsModule],
}).compileComponents();
fixture = TestBed.createComponent(HeroComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should log hero name in the console when user submit form', async(() => {
const heroName = 'Saitama';
const element = <HTMLFormElement>fixture.debugElement.nativeElement.querySelector('form');
spyOn(console, 'log').and.callThrough();
component.form.controls['name'].setValue(heroName);
element.querySelector('button').click();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(console.log).toHaveBeenCalledWith(heroName);
});
}));
https://riptutorial.com/es/home 86
it('should validate name field as required', () => {
component.form.controls['name'].setValue('');
expect(component.form.invalid).toBeTruthy();
});
});
Componentes de anidación
Los componentes se representarán en su selector respectivo, por lo que puede usar eso para
anidar componentes.
@Component({
selector: 'app-required',
template: `{{name}} is required.`
})
export class RequiredComponent {
@Input()
public name: String = '';
}
Puede usarlo dentro de otro componente usando la app-required (el selector de este
componente):
@Component({
selector: 'app-sample',
template: `
<input type="text" name="heroName" />
<app-required name="Hero Name"></app-required>
`
})
export class RequiredComponent {
@Input()
public name: String = '';
}
https://riptutorial.com/es/home 87
Capítulo 25: Configuración de la aplicación
ASP.net Core para trabajar con Angular 2 y
TypeScript
Introducción
ESCENARIO: ASP.NET Core background Angular 2 Front-End Angular 2 Componentes usando
Asp.net Core Controllers
De esta forma se puede implementar la aplicación Angular 2 sobre Asp.Net Core. También nos
permite llamar a los Controladores MVC desde los componentes de Angular 2 con la vista de
resultados de MVC que admite Angular 2.
Examples
Asp.Net Core + Angular2 + Gulp
Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using CoreAngular000.Data;
using CoreAngular000.Models;
using CoreAngular000.Services;
using Microsoft.Extensions.FileProviders;
using System.IO;
namespace CoreAngular000
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange:
true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional:
true);
if (env.IsDevelopment())
https://riptutorial.com/es/home 88
{
builder.AddUserSecrets<Startup>();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new
PhysicalFileProvider(Path.Combine(env.ContentRootPath, "node_modules")),
RequestPath = "/node_modules"
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
https://riptutorial.com/es/home 89
}
}
}
tsConfig.json
{
"compilerOptions": {
"diagnostics": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [ "es2015", "dom" ],
"listFiles": true,
"module": "commonjs",
"moduleResolution": "node",
"noImplicitAny": true,
"outDir": "wwwroot",
"removeComments": false,
"rootDir": "wwwroot",
"sourceMap": true,
"suppressImplicitAnyIndexErrors": true,
"target": "es5"
},
"exclude": [
"node_modules",
"wwwroot/lib/"
]
}
Paquete.json
{
"name": "angular dependencies and web dev package",
"version": "1.0.0",
"description": "Angular 2 MVC. Samuel Maícas Template",
"scripts": {},
"dependencies": {
"@angular/common": "~2.4.0",
"@angular/compiler": "~2.4.0",
"@angular/core": "~2.4.0",
"@angular/forms": "~2.4.0",
"@angular/http": "~2.4.0",
"@angular/platform-browser": "~2.4.0",
"@angular/platform-browser-dynamic": "~2.4.0",
"@angular/router": "~3.4.0",
"angular-in-memory-web-api": "~0.2.4",
"systemjs": "0.19.40",
"core-js": "^2.4.1",
"rxjs": "5.0.1",
"zone.js": "^0.7.4"
},
"devDependencies": {
"del": "^2.2.2",
"gulp": "^3.9.1",
"gulp-concat": "^2.6.1",
"gulp-cssmin": "^0.1.7",
"gulp-htmlmin": "^3.0.0",
"gulp-uglify": "^2.1.2",
"merge-stream": "^1.0.1",
https://riptutorial.com/es/home 90
"tslint": "^3.15.1",
"typescript": "~2.0.10"
},
"repository": {}
}
Bundleconfig.json
[
{
"outputFileName": "wwwroot/css/site.min.css",
"inputFiles": [
"wwwroot/css/site.css"
]
},
{
"outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [
"wwwroot/js/site.js"
],
"minify": {
"enabled": true,
"renameLocals": true
},
"sourceMap": false
}
]
Convierta bundleconfig.json en gulpfile (haga clic con el botón derecho del ratón en
bundleconfig.json en Solution Explorer, Bundler & Minifier> Convert to Gulp
@{
ViewData["Title"] = "Home Page";
}
<div>{{ nombre }}</div>
wwwroot / Index.html
<html>
<head>
<title>SMTemplate Angular2 & ASP.NET Core</title>
<base href="/">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
https://riptutorial.com/es/home 91
<script src="systemjs.config.js"></script>
<script>
System.import('main.js').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>Loading AppComponent here ...</my-app>
</body>
</html>
@Component({
selector: 'my-app',
templateUrl: '/home/index',
})
export class AppComponent { nombre = 'Samuel Maícas'; }
1. Descargar semilla
2. Ejecutar dotnet restore
3. Ejecutar npm instalar
Siempre. Disfrutar.
https://github.com/SamML/CoreAngular000
Y carga componente angular en el html. Aquí podemos decidir si queremos trabajar con el mismo
o diferente módulo. Depende de la situación.
<!DOCTYPE html>
<html>
<head>
<title>About Page</title>
<base href="/">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../css/site.min.css" rel="stylesheet" type="text/css"/>
https://riptutorial.com/es/home 92
<script src="../node_modules/core-js/client/shim.min.js"></script>
<script src="../node_modules/zone.js/dist/zone.js"></script>
<script src="../node_modules/systemjs/dist/system.src.js"></script>
<script src="../systemjs.config.js"></script>
<script>
System.import('../main.js').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<aboutpage>Loading AppComponent here ...</aboutpage>
</body>
</html>
Cómo: LLAMAR ASP.NET Core Controller para mostrar una vista MVC con soporte Angular2:
@Component({
selector: 'aboutpage',
templateUrl: '/home/about',
})
export class AboutComponent {
Lea Configuración de la aplicación ASP.net Core para trabajar con Angular 2 y TypeScript en
línea: https://riptutorial.com/es/angular2/topic/9543/configuracion-de-la-aplicacion-asp-net-core-
para-trabajar-con-angular-2-y-typescript
https://riptutorial.com/es/home 93
Capítulo 26: Creación de una biblioteca de
npm Angular
Introducción
Cómo publicar su NgModule, escrito en TypeScript en el registro de npm. Configuración de
proyecto npm, compilador de scripts, rollup y compilación de integración continua.
Examples
Módulo mínimo con clase de servicio.
Estructura de archivos
/
-src/
awesome.service.ts
another-awesome.service.ts
awesome.module.ts
-index.ts
-tsconfig.json
-package.json
-rollup.config.js
-.npmignore
Servicio y modulo
Coloque su trabajo impresionante aquí.
src / awesome.service.ts:
src / awesome.module.ts:
@NgModule({
providers: [AwesomeService, AnotherAwesomeService]
https://riptutorial.com/es/home 94
})
export class AwesomeModule {}
/index.ts:
Compilacion
En compilerOptions.paths debe especificar todos los módulos externos que utilizó en su paquete.
/tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"stripInternal": true,
"experimentalDecorators": true,
"strictNullChecks": false,
"noImplicitAny": true,
"module": "es2015",
"moduleResolution": "node",
"paths": {
"@angular/core": ["node_modules/@angular/core"],
"rxjs/*": ["node_modules/rxjs/*"]
},
"rootDir": ".",
"outDir": "dist",
"sourceMap": true,
"inlineSources": true,
"target": "es5",
"skipLibCheck": true,
"lib": [
"es2015",
"dom"
]
},
"files": [
"index.ts"
],
"angularCompilerOptions": {
"strictMetadataEmit": true
}
}
/rollup.config.js
https://riptutorial.com/es/home 95
export default {
entry: 'dist/index.js',
dest: 'dist/bundles/awesome.module.umd.js',
sourceMap: false,
format: 'umd',
moduleName: 'ng.awesome.module',
globals: {
'@angular/core': 'ng.core',
'rxjs': 'Rx',
'rxjs/Observable': 'Rx',
'rxjs/ReplaySubject': 'Rx',
'rxjs/add/operator/map': 'Rx.Observable.prototype',
'rxjs/add/operator/mergeMap': 'Rx.Observable.prototype',
'rxjs/add/observable/fromEvent': 'Rx.Observable',
'rxjs/add/observable/of': 'Rx.Observable'
},
external: ['@angular/core', 'rxjs']
}
Ajustes de NPM
Ahora, vamos a colocar algunas instrucciones para npm
/package.json
{
"name": "awesome-angular-module",
"version": "1.0.4",
"description": "Awesome angular module",
"main": "dist/bundles/awesome.module.umd.min.js",
"module": "dist/index.js",
"typings": "dist/index.d.ts",
"scripts": {
"test": "",
"transpile": "ngc",
"package": "rollup -c",
"minify": "uglifyjs dist/bundles/awesome.module.umd.js --screw-ie8 --compress --mangle --
comments --output dist/bundles/awesome.module.umd.min.js",
"build": "rimraf dist && npm run transpile && npm run package && npm run minify",
"prepublishOnly": "npm run build"
},
"repository": {
"type": "git",
"url": "git+https://github.com/maciejtreder/awesome-angular-module.git"
},
"keywords": [
"awesome",
"angular",
"module",
"minimal"
],
"author": "Maciej Treder <[email protected]>",
"license": "MIT",
"bugs": {
"url": "https://github.com/maciejtreder/awesome-angular-module/issues"
},
"homepage": "https://github.com/maciejtreder/awesome-angular-module#readme",
https://riptutorial.com/es/home 96
"devDependencies": {
"@angular/compiler": "^4.0.0",
"@angular/compiler-cli": "^4.0.0",
"rimraf": "^2.6.1",
"rollup": "^0.43.0",
"typescript": "^2.3.4",
"uglify-js": "^3.0.21"
},
"dependencies": {
"@angular/core": "^4.0.0",
"rxjs": "^5.3.0"
}
}
/.npmignore
node_modules
npm-debug.log
Thumbs.db
.DS_Store
src
!dist/src
plugin
!dist/plugin
*.ngsummary.json
*.iml
rollup.config.js
tsconfig.json
*.ts
!*.d.ts
.idea
Integración continua
Finalmente puedes configurar la integración continua.
.travis.yml
language: node_js
node_js:
- node
deploy:
provider: npm
email: [email protected]
api_key:
secure: <your api key>
on:
tags: true
repo: maciejtreder/awesome-angular-module
https://riptutorial.com/es/home 97
Lea Creación de una biblioteca de npm Angular en línea:
https://riptutorial.com/es/angular2/topic/10704/creacion-de-una-biblioteca-de-npm-angular
https://riptutorial.com/es/home 98
Capítulo 27: Crear un paquete Angular 2+
NPM
Introducción
A veces necesitamos compartir algún componente entre algunas aplicaciones y publicarlo en npm
es una de las mejores formas de hacerlo.
Hay algunos trucos que necesitamos saber para poder usar un componente normal como
paquete npm sin cambiar la estructura como estilos externos integrados.
Examples
Paquete mas simple
Aquí compartimos un flujo de trabajo mínimo para crear y publicar un paquete Angular 2+ npm.
Archivos de configuración
Necesitamos algunos archivos de configuración para decirle a git , npm , gulp y typescript cómo
actuar.
.gitignore
npm-debug.log
node_modules
jspm_packages
.idea
build
.npmignore
En segundo lugar, creamos un archivo .npmignore para evitar la publicación de archivos y carpetas
no deseados. El contenido es:
examples
node_modules
src
https://riptutorial.com/es/home 99
gulpfile.js
Necesitamos crear un gulpfile.js para decirle a Gulp cómo compilar nuestra aplicación. Esta
parte es necesaria porque debemos minimizar e incluir todas las plantillas y estilos externos antes
de publicar nuestro paquete. El contenido es:
gulp.task('js:build', function () {
gulp.src('src/*.ts') // also can use *.js files
.pipe(embedTemplates({sourceType:'ts'}))
.pipe(inlineNg2Styles({ base: '/src' }))
.pipe(gulp.dest('./dist'));
});
index.d.ts
index.js
Este es el punto de entrada del paquete. Cuando instale este paquete usando NPM e importe en
su aplicación, solo necesita pasar el nombre del paquete y su aplicación aprenderá dónde
encontrar cualquier componente EXPORTADO de su paquete.
exports.AngularXMinimalNpmPackageModule = require('./lib').AngularXMinimalNpmPackageModule;
Usamos la carpeta lib porque cuando compilamos nuestro código, la salida se coloca dentro de
la carpeta /lib .
paquete.json
Este archivo se utiliza para configurar su publicación npm y define los paquetes necesarios para
que funcione.
{
"name": "angular-x-minimal-npm-package",
"version": "0.0.18",
"description": "An Angular 2+ Data Table that uses HTTP to create, read, update and delete
data from an external API such REST.",
"main": "index.js",
"scripts": {
"watch": "tsc -p src -w",
"build": "gulp js:build && rm -rf lib && tsc -p dist"
},
https://riptutorial.com/es/home 100
"repository": {
"type": "git",
"url": "git+https://github.com/vinagreti/angular-x-minimal-npm-package.git"
},
"keywords": [
"Angular",
"Angular2",
"Datatable",
"Rest"
],
"author": "[email protected]",
"license": "MIT",
"bugs": {
"url": "https://github.com/vinagreti/angular-x-minimal-npm-package/issues"
},
"homepage": "https://github.com/vinagreti/angular-x-minimal-npm-package#readme",
"devDependencies": {
"gulp": "3.9.1",
"gulp-angular-embed-templates": "2.3.0",
"gulp-inline-ng2-styles": "0.0.1",
"typescript": "2.0.0"
},
"dependencies": {
"@angular/common": "2.4.1",
"@angular/compiler": "2.4.1",
"@angular/core": "2.4.1",
"@angular/http": "2.4.1",
"@angular/platform-browser": "2.4.1",
"@angular/platform-browser-dynamic": "2.4.1",
"rxjs": "5.0.2",
"zone.js": "0.7.4"
}
}
dist / tsconfig.json
Crea una carpeta dist y coloca este archivo dentro. Este archivo se utiliza para indicar a
Typescript cómo compilar su aplicación. Dónde obtener la carpeta mecanografiada y dónde
colocar los archivos compilados.
{
"compilerOptions": {
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"mapRoot": "",
"rootDir": ".",
"target": "es5",
"lib": ["es6", "es2015", "dom"],
"inlineSources": true,
"stripInternal": true,
"module": "commonjs",
"moduleResolution": "node",
"removeComments": true,
"sourceMap": true,
"outDir": "../lib",
"declaration": true
}
}
https://riptutorial.com/es/home 101
Después de crear los archivos de configuración, debemos crear nuestro componente y módulo.
Este componente recibe un clic y muestra un mensaje. Se utiliza como una etiqueta html
<angular-x-minimal-npm-package></angular-x-minimal-npm-package> . Simplemente instale este
paquete npm y cargue su módulo en el modelo que desea usar.
src / angular-x-minimal-npm-package.component.ts
src / angular-x-minimal-npm-package.component.html
<div>
<h1 (click)="onClick()">{{message}}</h1>
</div>
src / angular-x-data-table.component.css
h1{
color: red;
}
src / angular-x-minimal-npm-package.module.ts
@NgModule({
imports: [ CommonModule ],
declarations: [ AngularXMinimalNpmPackageComponent ],
exports: [ AngularXMinimalNpmPackageComponent ],
entryComponents: [ AngularXMinimalNpmPackageComponent ],
})
export class AngularXMinimalNpmPackageModule {}
https://riptutorial.com/es/home 102
Construir y compilar
Para construir usamos gulp y para compilar usamos tsc . El comando se establece en el archivo
package.json, en la opción scripts.build . Tenemos este conjunto gulp js:build && rm -rf lib &&
tsc -p dist . Esta es nuestra cadena de tareas que hará el trabajo por nosotros.
Publicar
Ahora solo necesitamos publicar nuestro paquete para poder instalarlo a través de npm. Para
eso, simplemente ejecuta el comando:
npm publish
¡¡¡Eso es todo!!!
https://riptutorial.com/es/home 103
Capítulo 28: CRUD en Angular2 con API
Restful
Sintaxis
• @Injectable () // Indica al inyector de dependencia que inyecte dependencias al crear una
instancia de este servicio.
Examples
Leer de una API Restful en Angular2
Para separar la lógica de la API del componente, estamos creando el cliente de la API como una
clase separada. Esta clase de ejemplo realiza una solicitud a la API de Wikipedia para obtener
artículos de wiki aleatorios.
@Injectable()
export class WikipediaService{
constructor(private http: Http) {}
getRandomArticles(numberOfArticles: number)
{
var request =
this.http.get("https://en.wikipedia.org/w/api.php?action=query&list=random&format=json&rnlimit="
+ numberOfArticles);
return request.map((response: Response) => {
return response.json();
},(error) => {
console.log(error);
//your want to implement your own error handling here.
});
}
}
https://riptutorial.com/es/home 104
import { WikipediaService } from './wikipedia.Service';
@Component({
selector: 'wikipedia',
templateUrl: 'wikipedia.component.html'
})
export class WikipediaComponent implements OnInit {
constructor(private wikiService: WikipediaService) { }
https://riptutorial.com/es/home 105
Capítulo 29: custom ngx-bootstrap
datepicker + entrada
Examples
fecha ngx-bootstrap datepicker
datepicker.component.html
datepicker.component.ts
@Component({
selector: 'custom-datepicker',
templateUrl: 'datepicker.component.html',
providers: [DatePipe, NgModel],
host: {
'(document:mousedown)': 'onClick($event)',
}
})
inputElement : ElementRef;
dt: Date = null;
showDatepicker: boolean = false;
https://riptutorial.com/es/home 106
@Input() disabledDatePicker: boolean = false;
@Input() value: string = null;
@Input() id: string;
@Input() min: Date = null;
@Input() max: Date = null;
changedDate(){
if(this.value === ''){
this.dateModelChange.emit(null);
}else if(this.value.split('/').length === 3){
this.dateModelChange.emit(DatepickerComponent.convertToDate(this.value));
}
}
clickOutSide(event : Event){
if(this.inputElement.nativeElement !== event.target) {
console.log('click outside', event);
}
}
onClick(event) {
if (!this.inputElement.nativeElement.contains(event.target)) {
this.close();
}
}
ngOnChanges(changes: SimpleChanges): void {
if (this.value !== null && this.value !== undefined && this.value.length > 0) {
this.value = null;
this.dt = null;
}else {
if(this.value !== null){
this.dt = new Date(this.value);
this.value = moment(this.value).format('MM/DD/YYYY');
}
}
}
openCloseDatepicker(): void {
if (!this.disabledDatePicker) {
this.showDatepicker = !this.showDatepicker;
}
}
open(): void {
this.showDatepicker = true;
}
close(): void {
this.showDatepicker = false;
}
https://riptutorial.com/es/home 107
this.value = DatepickerComponent.transformDate(this.dt);
this.dateModelChange.emit(this.dt);
}
https://riptutorial.com/es/home 108
Capítulo 30: Depuración de la aplicación
mecanografiada Angular2 utilizando código
de Visual Studio
Examples
Configuración de Launch.json para tu espacio de trabajo
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Extension",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceRoot}"
],
"stopOnEntry": false,
"sourceMaps": true,
"outDir": "${workspaceRoot}/out",
"preLaunchTask": "npm"
}
]
}
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"type": "node",
"request": "launch",
"program": "${workspaceRoot}/app/main.js", // put your main.js path
"stopOnEntry": false,
https://riptutorial.com/es/home 109
"args": [],
"cwd": "${workspaceRoot}",
"preLaunchTask": null,
"runtimeExecutable": null,
"runtimeArgs": [
"--nolazy"
],
"env": {
"NODE_ENV": "development"
},
"console": "internalConsole",
"sourceMaps": false,
"outDir": null
},
{
"name": "Attach",
"type": "node",
"request": "attach",
"port": 5858,
"address": "localhost",
"restart": false,
"sourceMaps": false,
"outDir": null,
"localRoot": "${workspaceRoot}",
"remoteRoot": null
},
{
"name": "Attach to Process",
"type": "node",
"request": "attach",
"processId": "${command.PickProcess}",
"port": 5858,
"sourceMaps": false,
"outDir": null
}
]
}
3. Ahora que la depuración está funcionando, muestra una ventana emergente de notificación
para la depuración paso a paso
https://riptutorial.com/es/home 110
Capítulo 31: Detectar eventos de
redimensionamiento
Examples
Un componente que escucha en el evento de cambio de tamaño de la
ventana.
@Component({
...
template: `
<div>
<p [hidden]="!visible" (window:resize)="onResize($event)" >Now you see me...</p>
<p>now you dont!</p>
</div>
`
...
})
export class MyComponent {
visible: boolean = false;
breakpoint: number = 768;
constructor() {
}
onResize(event) {
const w = event.target.innerWidth;
if (w >= this.breakpoint) {
this.visible = true;
} else {
// whenever the window is less than 768, hide this component.
this.visible = false;
}
}
}
Una etiqueta p en nuestra plantilla se ocultará cuando sea visible falso. visible cambiará el valor
cada vez que se onResize controlador de eventos onResize . Su llamada se produce cada
window:resize tiempo window:resize dispara un evento.
https://riptutorial.com/es/home 111
Capítulo 32: Directivas
Sintaxis
• <input [value]="value"> - Enlaza el name miembro de la clase de valor del atributo.
Observaciones
La principal fuente de información sobre las directivas de Angular 2 es la documentación oficial
https://angular.io/docs/ts/latest/guide/attribute-directives.html
Examples
Directiva de atributos
<div [class.active]="isActive"></div>
<span [style.color]="'red'"></span>
Directivas estructurales
<span *ngIf="isVisible"></span>
Directiva personalizada
https://riptutorial.com/es/home 112
import {Directive, ElementRef, Renderer} from '@angular/core';
@Directive({
selector: '[green]',
})
class GreenDirective {
constructor(private _elementRef: ElementRef,
private _renderer: Renderer) {
_renderer.setElementStyle(_elementRef.nativeElement, 'color', 'green');
}
}
Uso:
* ngPara
form1.component.ts:
Salida:
<div>Apples</div>
<div>Oranges</div>
<div>Bananas</div>
<div>Limes</div>
<div>Lemons</div>
<select required>
<option value="Apples">Apples</option>
<option value="Oranges">Oranges</option>
<option value="Bananas">Bananas</option>
<option value="Limes">Limes</option>
<option value="Lemons">Lemons</option>
</select>
En su forma más simple, *ngFor tiene dos partes: let variableName of object/array
https://riptutorial.com/es/home 113
En el caso de la fruit = ['Apples', 'Oranges', 'Bananas', 'Limes', 'Lemons']; ,
Las manzanas, las naranjas, etc. son los valores dentro de la variedad de fruit .
Referencias:
Angular2 | ngPara
Angular2 | Formas
En este ejemplo, vamos a crear una directiva para copiar un texto en el portapapeles haciendo
clic en un elemento
copy-text.directive.ts
import {
Directive,
Input,
HostListener
} from "@angular/core";
@Directive({
selector: '[text-copy]'
})
export class TextCopyDirective {
constructor() {
}
// The HostListener will listen to click events and run the below function, the
HostListener supports other standard events such as mouseenter, mouseleave etc.
@HostListener('click') copyText() {
// We need to create a dummy textarea with the text to be copied in the DOM
var textArea = document.createElement("textarea");
https://riptutorial.com/es/home 114
textArea.style.width = '2em';
textArea.style.height = '2em';
textArea.style.padding = '0';
textArea.style.border = 'none';
textArea.style.outline = 'none';
textArea.style.boxShadow = 'none';
textArea.style.background = 'transparent';
// Set the texarea's content to our value defined in our [text-copy] attribute
textArea.value = this.text;
document.body.appendChild(textArea);
try {
// Most modern browsers support execCommand('copy'|'cut'|'paste'), if it doesn't
it should throw an error
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
// Let the user know the text has been copied, e.g toast, alert etc.
console.log(msg);
} catch (err) {
// Tell the user copying is not supported and give alternative, e.g alert window
with the text to copy
console.log('unable to copy');
}
some-page.component.html
...
<!-- Insert variable as the attribute's value, let textToBeCopied = 'http://facebook.com/'
-->
<button [text-copy]="textToBeCopied">Copy URL</button>
<button [text-copy]="'https://www.google.com/'">Copy URL</button>
...
https://riptutorial.com/es/home 115
constructor(private el: ElementRef) { }
@HostListener('mouseenter')
onMouseEnter() {
this.highlight(this.highlightColor || 'red');
}
@HostListener('mouseleave')
onMouseLeave() {
this.highlight(null);
}
@Component({
selector: 'app-test-container',
template: `
<div>
<span id="red" appHighlight>red text</span>
<span id="green" [appHighlight]="'green'">green text</span>
<span id="no">no color</span>
</div>
`
})
class ContainerComponent { }
const mouseEvents = {
get enter() {
const mouseenter = document.createEvent('MouseEvent');
mouseenter.initEvent('mouseenter', true, true);
return mouseenter;
},
get leave() {
const mouseleave = document.createEvent('MouseEvent');
mouseleave.initEvent('mouseleave', true, true);
return mouseleave;
},
};
describe('HighlightDirective', () => {
let fixture: ComponentFixture<ContainerComponent>;
let container: ContainerComponent;
let element: HTMLElement;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ContainerComponent, HighlightDirective],
providers: [
{ provide: ComponentFixtureAutoDetect, useValue: true },
],
https://riptutorial.com/es/home 116
});
fixture = TestBed.createComponent(ContainerComponent);
// fixture.detectChanges(); // without the provider
container = fixture.componentInstance;
element = fixture.nativeElement;
});
it('should set background-color to empty when mouse leaves with directive without
arguments', () => {
const targetElement = <HTMLSpanElement>element.querySelector('#red');
targetElement.dispatchEvent(mouseEvents.leave);
expect(targetElement.style.backgroundColor).toEqual('');
});
it('should set background-color to empty when mouse leaves with directive with arguments',
() => {
const targetElement = <HTMLSpanElement>element.querySelector('#green');
targetElement.dispatchEvent(mouseEvents.leave);
expect(targetElement.style.backgroundColor).toEqual('');
});
targetElement.dispatchEvent(mouseEvents.enter);
expect(targetElement.style.backgroundColor).toEqual('red');
});
targetElement.dispatchEvent(mouseEvents.enter);
expect(targetElement.style.backgroundColor).toEqual('green');
});
});
https://riptutorial.com/es/home 117
Capítulo 33: Directivas y componentes:
@Input @Output
Sintaxis
1. Enlace unidireccional del componente principal al componente anidado: [propertyName]
2. Enlace unidireccional de componente anidado a componente principal: (propertyName)
3. Enlace bidireccional (también conocido como notación de caja de banana): [(propertyName)]
Examples
Ejemplo de entrada
<car-component [car]="car"></car-component>
Ejemplo completo:
1. car.entity.ts
2. car.component.ts
@Component({
https://riptutorial.com/es/home 118
selector: 'car-component',
template: require('./templates/car.html'),
})
constructor() {
console.log('gros');
}
}
3. garage.component.ts
@Component({
selector: 'garage',
template: require('./templates/garage.html'),
directives: [CarComponent]
})
constructor() {
var carOne : CarEntity = new CarEntity('renault', 'blue');
var carTwo : CarEntity = new CarEntity('fiat', 'green');
var carThree : CarEntity = new CarEntity('citroen', 'yellow');
this.cars = [carOne, carTwo, carThree];
}
}
4. garage.html
5. car.html
<div>
<span>{{ car.brand }}</span> |
<span>{{ car.color }}</span>
</div>
Una directiva de botón que acepta un @Input() para especificar un límite de clic hasta que el botón
se deshabilite. El componente principal puede escuchar un evento que se emitirá cuando se
alcance el límite de clics a través de @Output :
https://riptutorial.com/es/home 119
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'limited-button',
template: `<button (click)="onClick()"
[disabled]="disabled">
<ng-content></ng-content>
</button>`,
directives: []
})
onClick() {
this.clickCount++;
if (this.clickCount === this.clickLimit) {
this.disabled = true;
this.limitReached.emit(this.clickCount);
}
}
}
Componente principal que utiliza la directiva Button y alerta un mensaje cuando se alcanza el
límite de clics:
@Component({
selector: 'my-parent-component',
template: `<limited-button [clickLimit]="2"
(limitReached)="onLimitReached($event)">
You can only click me twice
</limited-button>`,
directives: [LimitedButton]
})
https://riptutorial.com/es/home 120
Componente padre con llamada asíncrona a
un punto final
import { Component, OnChanges, OnInit } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ChildComponent } from './child.component';
@Component ({
selector : 'parent-component',
template : `
<child-component [data]="asyncData"></child-component>
`
})
export class ParentComponent {
asyncData : any;
constructor(
private _http : Http
){}
ngOnInit () {
this._http.get('some.url')
.map(this.extractData)
.subscribe(this.handleData)
.catch(this.handleError);
}
extractData (res:Response) {
let body = res.json();
return body.data || { };
}
handleData (data:any) {
this.asyncData = data;
}
handleError (error:any) {
console.error(error);
}
}
https://riptutorial.com/es/home 121
import { Component, OnChanges, Input } from '@angular/core';
@Component ({
selector : 'child-component',
template : `
<p *ngIf="doesDataExist">Hello child</p>
`
})
export class ChildComponent {
https://riptutorial.com/es/home 122
Capítulo 34: Directivas y servicios
comúnmente incorporados.
Introducción
@ angular / común: directivas y servicios que se necesitan comúnmente @ angular / core - la
estructura del núcleo angular
Examples
Clase de ubicación
La ubicación es un servicio que las aplicaciones pueden usar para interactuar con la URL de un
navegador. Dependiendo de la LocationStrategy que se use, la ubicación permanecerá en la ruta
de la URL o en el segmento de hash de la URL.
@Component({
selector: 'app-component'
})
class AppCmp {
constructor(_location: Location) {
//Changes the browsers URL to the normalized version of the given URL,
//and pushes a new item onto the platform's history.
_location.go('/foo');
backClicked() {
//Navigates back in the platform's history.
this._location.back();
}
forwardClicked() {
//Navigates forward in the platform's history.
this._location.back();
}
}
AsyncPipe
https://riptutorial.com/es/home 123
debe verificar para detectar cambios. Cuando el componente se destruye, la tubería asíncrona se
cancela automáticamente para evitar posibles pérdidas de memoria.
@Component({
selector: 'async-observable-pipe',
template: '<div><code>observable|async</code>: Time: {{ time | async }}</div>'
})
export class AsyncObservablePipeComponent {
time = new Observable<string>((observer: Subscriber<string>) => {
setInterval(() => observer.next(new Date().toString()), 1000);
});
}
Para mostrar la versión actual, podemos usar VERSION del paquete @ angular / core.
@Component({
selector: 'my-app',
template: `<h1>Hello {{name}}</h1>
<h2>Current Version: {{ver}}</h2>
`,
})
export class AppComponent {
name = 'Angular2';
ver = VERSION.full;
}
Pipa de la moneda
La canalización de moneda le permite trabajar con sus datos como números regulares pero
mostrarlos con el formato de moneda estándar (símbolo de moneda, decimales, etc.) en la vista.
@Component({
selector: 'currency-pipe',
template: `<div>
<p>A: {{myMoney | currency:'USD':false}}</p>
<p>B: {{yourMoney | currency:'USD':true:'4.2-2'}}</p>
</div>`
})
export class CurrencyPipeComponent {
myMoney: number = 100000.653;
yourMoney: number = 5.3495;
}
https://riptutorial.com/es/home 124
https://angular.io/docs/ts/latest/api/common/index/CurrencyPipe-pipe.html
https://riptutorial.com/es/home 125
Capítulo 35: Directrices de atributos para
afectar el valor de las propiedades en el nodo
host mediante el decorador @HostBinding.
Examples
@HostBinding
@Directive({
selector: '[appButtonPress]'
})
export class ButtonPressDirective {
@HostBinding('attr.role') role = 'button';
@HostBinding('class.pressed') isPressed: boolean;
@HostListener('mousedown') hasPressed() {
this.isPressed = true;
}
@HostListener('mouseup') hasReleased() {
this.isPressed = false;
}
}
Tenga en cuenta que para ambos casos de uso de @HostBinding estamos pasando un valor de
cadena por el cual queremos afectar la propiedad. Si no suministramos una cadena al decorador,
entonces se usará el nombre del miembro de la clase. En el primer @HostBinding, estamos
configurando de forma estática el atributo de función para el botón. Para el segundo ejemplo, la
clase presionada se aplicará cuando isPressed sea verdadero
Lea Directrices de atributos para afectar el valor de las propiedades en el nodo host mediante el
decorador @HostBinding. en línea: https://riptutorial.com/es/angular2/topic/9455/directrices-de-
atributos-para-afectar-el-valor-de-las-propiedades-en-el-nodo-host-mediante-el-decorador--
hostbinding-
https://riptutorial.com/es/home 126
Capítulo 36: Diseño de material angular
Examples
Md2Seleccionar
Componente :
<md2-select></md2-select>
<md2-option></md2-option>
<md2-select-header></md2-select-header>
Md2Tooltip
Md2Toast
@Component({
selector: "..."
})
...
constructor(private toast: Md2Toast) { }
toastMe() {
https://riptutorial.com/es/home 127
this.toast.show('Toast message...');
--- or ---
...
Md2Datepicker
<md2-datepicker [(ngModel)]="date"></md2-datepicker>
Md2Accordion y Md2Collapse
Ejemplos
<div [collapse]="isCollapsed">
Lorum Ipsum Content
</div>
Ejemplos
<md2-accordion [multiple]="multiple">
<md2-accordion-tab *ngFor="let tab of accordions"
[header]="tab.title"
[active]="tab.active"
[disabled]="tab.disabled">
{{tab.content}}
</md2-accordion-tab>
<md2-accordion-tab>
<md2-accordion-header>Custom Header</md2-accordion-header>
test content
</md2-accordion-tab>
</md2-accordion>
https://riptutorial.com/es/home 128
Capítulo 37: Dropzone en Angular2
Examples
Zona de descenso
@NgModule({
...
imports: [
...
DropzoneModule.forRoot(DROPZONE_CONFIG)
]
})
USO DE COMPONENTES
onUploadError(args: any) {
console.log('onUploadError:', args);
}
https://riptutorial.com/es/home 129
onUploadSuccess(args: any) {
console.log('onUploadSuccess:', args);
}
}
https://riptutorial.com/es/home 130
Capítulo 38: Ejemplo para rutas como / route
/ subruta para urls estáticas
Examples
Ejemplo de ruta básica con árbol de rutas secundarias
app.module.ts
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, mainModule.forRoot(), RouterModule.forRoot(routes)],
providers: [],
bootstrap: [AppComponent]
})
app.routes.ts
subTreeRoutes.ts
Lea Ejemplo para rutas como / route / subruta para urls estáticas en línea:
https://riptutorial.com/es/angular2/topic/8910/ejemplo-para-rutas-como---route---subruta-para-urls-
estaticas
https://riptutorial.com/es/home 131
Capítulo 39: Ejemplos de componentes
avanzados
Observaciones
Recuerda que Angular 2 tiene que ver con la responsabilidad singular. No importa lo pequeño que
sea su componente, dedique una lógica separada para cada componente. Ya sea un botón, un
enlace de anclaje elegante, un encabezado de diálogo o incluso un subelemento de sidenav.
Examples
Selector de imágenes con vista previa
En este ejemplo, vamos a crear un selector de imágenes que muestra una vista previa de la
imagen antes de subirla. La vista previa también admite archivos de arrastrar y soltar en la
entrada. En este ejemplo, solo cubriré la carga de archivos individuales, pero puede hacer un
pequeño esfuerzo para que la carga de múltiples archivos funcione.
image-preview.html
<!-- file input, accepts images only. Detect when file has been picked/changed with Angular's
native (change) event listener -->
<input type="file" accept="image/*" (change)="updateSource($event)">
<!-- img placeholder when a file has been picked. shows only when 'source' is not empty -->
<img *ngIf="source" [src]="source" src="">
image-preview.ts
import {
Component,
Output,
EventEmitter,
} from '@angular/core';
@Component({
selector: 'image-preview',
styleUrls: [ './image-preview.css' ],
templateUrl: './image-preview.html'
})
export class MtImagePreviewComponent {
https://riptutorial.com/es/home 132
// Emit an event when a file has been picked. Here we return the file itself
@Output() onChange: EventEmitter<File> = new EventEmitter<File>();
constructor() {}
// If the input has changed(file picked) we project the file into the img previewer
updateSource($event: Event) {
// We access he file with $event.target['files'][0]
this.projectImage($event.target['files'][0]);
}
another.component.html
<form (ngSubmit)="submitPhoto()">
<image-preview (onChange)="getFile($event)"></image-preview>
<button type="submit">Upload</button>
</form>
Y eso es. Mucho más fácil de lo que era en AngularJS 1.x. Realmente hice este componente
basado en una versión anterior que hice en AngularJS 1.5.5.
@Component({
selector: 'component',
template: `
<input [formControl]="control" />
<div *ngFor="let item of content">
{{item.id}} - {{item.name}}
</div>
`
})
export class MyComponent implements OnInit, OnDestroy {
https://riptutorial.com/es/home 133
public content: { id: number; name: string; }[];
private originalContent = [
{ id: 1, name: 'abc' },
{ id: 2, name: 'abce' },
{ id: 3, name: 'ced' }
];
public ngOnInit() {
this.subscription = this.control.valueChanges.subscribe(value => {
this.content = this.originalContent.filter(item => item.name.startsWith(value));
});
}
public ngOnDestroy() {
this.subscription.unsubscribe();
}
https://riptutorial.com/es/home 134
Capítulo 40: Encuadernación de datos
Angular2
Examples
@Entrada()
@Component({
selector: 'parent-component',
template: '<div>
<child-component [users]="users"></child-component>
</div>'
})
export class ParentComponent implements OnInit{
let users : List<User> = null;
ngOnInit() {
users.push(new User('A', 'A', '[email protected]');
users.push(new User('B', 'B', '[email protected]');
users.push(new User('C', 'C', '[email protected]');
}
}
@Component({
selector: 'child-component',
template: '<div>
<table *ngIf="users !== null">
<thead>
<th>Name</th>
<th>FName</th>
<th>Email</th>
</thead>
<tbody>
<tr *ngFor="let user of users">
<td>{{user.name}}</td>
<td>{{user.fname}}</td>
<td>{{user.email}}</td>
</tr>
</tbody>
</table>
</div>',
})
export class ChildComponent {
@Input() users : List<User> = null;
}
https://riptutorial.com/es/home 135
export class User {
name : string;
fname : string;
email : string;
https://riptutorial.com/es/home 136
Capítulo 41: Enrutamiento
Examples
Enrutamiento básico
El enrutador permite la navegación de una vista a otra según las interacciones del usuario con la
aplicación.
Los siguientes son los pasos para implementar el enrutamiento básico en Angular 2:
<base href='/'>
como el primer hijo debajo de su etiqueta de cabecera en su archivo index.html. Esta etiqueta
dice que su carpeta de aplicaciones es la raíz de la aplicación. Angular 2 entonces sabría
organizar sus enlaces.
El primer paso es verificar si está señalando las dependencias de enrutamiento correctas / más
recientes en package.json -
"dependencies": {
......
"@angular/router": "3.0.0-beta.1",
......
}
class Route {
path : string
pathMatch : 'full'|'prefix'
component : Type|string
.........
}
En un archivo de rutas ( route/routes.ts ), importe todos los componentes que necesita configurar
para diferentes rutas de enrutamiento. La ruta vacía significa que la vista se carga de forma
predeterminada. ":" en la ruta indica un parámetro dinámico pasado al componente cargado.
https://riptutorial.com/es/home 137
import { LoginComponent } from '../components/login.component';
import { SignupComponent } from '../components/signup.component';
En sus main.ts (Puede ser cualquier nombre. Básicamente, debe estar definido en el archivo
principal en systemjs.config)
El cuarto paso es cargar / mostrar los componentes del enrutador según la ruta a la que se
accede. La directiva se utiliza para indicar a angular dónde cargar el componente. Para utilizar
importar los ROUTER_DIRECTIVES.
@Component({
selector: 'demo-app',
template: `
....................................
<div>
<router-outlet></router-outlet>
</div>
....................................
`,
// Add our router directives we will be using
directives: [ROUTER_DIRECTIVES]
})
Quinto paso es enlazar las otras rutas. De forma predeterminada, RouterOutlet cargará el
componente para el cual se especifica la ruta vacía en el RouterConfig. La directiva RouterLink se
usa con la etiqueta de anclaje html para cargar los componentes adjuntos a las rutas. RouterLink
genera el atributo href que se utiliza para generar enlaces. Por ejemplo:
@Component({
selector: 'demo-app',
template: `
<a [routerLink]="['/login']">Login</a>
https://riptutorial.com/es/home 138
<a [routerLink]="['/signup']">Signup</a>
<a [routerLink]="['/dashboard']">Dashboard</a>
<div>
<router-outlet></router-outlet>
</div>
`,
// Add our router directives we will be using
directives: [ROUTER_DIRECTIVES]
})
export class AppComponent { }
Ahora, estamos bien con el enrutamiento a la ruta estática. RouterLink también admite la ruta
dinámica al pasar parámetros adicionales junto con la ruta.
importar {Componente} desde '@ angular / core'; importe {ROUTER_DIRECTIVES} desde '@
angular / router';
@Component({
selector: 'demo-app',
template: `
<ul>
<li *ngFor="let bar of bars | async">
<a [routerLink]="['/bars', bar.id]">
{{bar.name}}
</a>
</li>
</ul>
<div>
<router-outlet></router-outlet>
</div>
`,
// Add our router directives we will be using
directives: [ROUTER_DIRECTIVES]
})
export class AppComponent { }
RouterLink toma una matriz donde el primer elemento es la ruta de enrutamiento y los elementos
subsiguientes son para los parámetros de enrutamiento dinámico.
Rutas infantiles
A veces tiene sentido anidar vistas o rutas entre sí. Por ejemplo, en el panel de control desea
varias vistas secundarias, similares a las pestañas pero implementadas a través del sistema de
enrutamiento, para mostrar los proyectos, contactos y mensajes de los usuarios. Para soportar
tales escenarios, el enrutador nos permite definir rutas secundarias.
Primero ajustamos nuestro RouterConfig desde arriba y agregamos las rutas secundarias:
https://riptutorial.com/es/home 139
{ path: '', redirectTo: 'projects', pathMatch: 'full' },
{ path: 'projects', component: 'ProjectsComponent' },
{ path: 'messages', component: 'MessagesComponent' }
] },
{ path: 'bars/:id', component: BarDetailComponent },
{ path: 'login', component: LoginComponent },
{ path: 'signup', component: SignupComponent }
];
Ahora que tenemos nuestras rutas secundarias definidas, tenemos que asegurarnos de que esas
rutas secundarias se puedan mostrar dentro de nuestro DashboardComponent , ya que ahí es donde
hemos agregado las secundarias. Anteriormente aprendimos que los componentes se muestran
en una etiqueta <router-outlet></router-outlet> . Similar declaramos otro RouterOutlet en el
DashboardComponent :
@Component({
selector: 'dashboard',
template: `
<a [routerLink]="['projects']">Projects</a>
<a [routerLink]="['messages']">Messages</a>
<div>
<router-outlet></router-outlet>
</div>
`
})
export class DashboardComponent { }
Como puede ver, hemos agregado otro RouterOutlet en el que se mostrarán las rutas
secundarias. Por lo general, la ruta con una ruta vacía se mostrará, sin embargo, configuramos
una redirección a la ruta de los projects , porque queremos que se muestre inmediatamente
cuando se carga la ruta del dashboard . Dicho esto, necesitamos una ruta vacía, de lo contrario
obtendrá un error como este:
Entonces, al agregar la ruta vacía , es decir, una ruta con una ruta vacía, hemos definido un punto
de entrada para el enrutador.
ResolveData
Este ejemplo le mostrará cómo puede resolver los datos obtenidos de un servicio antes de
representar la vista de su aplicación.
users.service.ts
...
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Rx';
https://riptutorial.com/es/home 140
import { User } from './user.ts';
@Injectable()
export class UsersService {
constructor(public http:Http) {}
/**
* Returns all users
* @returns {Observable<User[]>}
*/
index():Observable<User[]> {
return this.http.get('http://mywebsite.com/api/v1/users')
.map((res:Response) => res.json());
}
/**
* Returns a user by ID
* @param id
* @returns {Observable<User>}
*/
get(id:number|string):Observable<User> {
usuarios.resolver.ts
...
import { UsersService } from './users.service.ts';
import { Observable } from 'rxjs/Rx';
import {
Resolve,
ActivatedRouteSnapshot,
RouterStateSnapshot
} from "@angular/router";
@Injectable()
export class UsersResolver implements Resolve<User[] | User> {
https://riptutorial.com/es/home 141
users.component.ts
Este es un componente de la página con una lista de todos los usuarios. Funcionará de manera
similar para el componente de la página de detalles del usuario, reemplazará data.users con
data.user o cualquier tecla definida en app.routes.ts (ver más abajo)
...
import { ActivatedRoute} from "@angular/router";
@Component(...)
export class UsersComponent {
users:User[];
constructor(route: ActivatedRoute) {
route.data.subscribe(data => {
// data['Match key defined in RouterConfig, see below']
this.users = data.users;
});
}
/**
* It is not required to unsubscribe from the resolver as Angular's HTTP
* automatically completes the subscription when data is received from the server
*/
}
app.routes.ts
...
import { UsersResolver } from './resolvers/users.resolver';
https://riptutorial.com/es/home 142
app.resolver.ts
IMPORTANTE: los servicios que se utilizan en la resolución deben importarse primero o obtendrá
un 'No hay proveedor para ... Error de resolución'. Recuerde que estos servicios estarán
disponibles en todo el mundo y que ya no tendrá que declararlos en ningún providers de
componentes. Asegúrese de darse de baja de cualquier suscripción para evitar la pérdida de
memoria
...
import { UsersService } from './users.service';
import { UsersResolver } from './users.resolver';
main.browser.ts
...
import {bootstrap} from '@angular/platform-browser-dynamic';
import { ROUTE_RESOLVERS } from './app.resolver';
bootstrap(<Type>App, [
...
...ROUTE_RESOLVERS
])
.catch(err => console.error(err));
El siguiente ejemplo muestra las rutas de inicio, inicio / contador y inicio / contador / obtener
datos. Las primeras y últimas rutas son ejemplos de redirecciones. Finalmente, al final del
ejemplo es una forma adecuada de exportar la Ruta a importar en un archivo separado. Por ej.
app.module.ts
Para explicar con más detalle, Angular requiere que tenga una ruta sin ruta en la matriz
secundaria que incluye el componente principal, para representar la ruta principal. Es un poco
confuso, pero si piensa en una URL en blanco para una ruta secundaria, esencialmente sería
igual a la misma URL que la ruta principal.
https://riptutorial.com/es/home 143
import { RouterModule, Routes } from "@angular/router";
@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
]
})
export class AppRoutingModule { }
https://riptutorial.com/es/home 144
Capítulo 42: Enrutamiento (3.0.0+)
Observaciones
Hay algunos trucos más que podemos hacer con el enrutador (como restringir el acceso), pero se
pueden cubrir en un tutorial separado.
Si necesita una nueva ruta, simplemente modifique app.routes.ts y siga los siguientes pasos:
1. Importar el componente
2. Añadir a la matriz de routes . Asegúrese de incluir una nueva path y component .
Examples
Bootstrapping
Ahora que las rutas están definidas, debemos informar a nuestra aplicación sobre las rutas. Para
hacer esto, reinicie al proveedor que exportamos en el ejemplo anterior.
Encuentre su configuración de arranque (debería estar en main.ts , pero su millaje puede variar
).
//main.ts
bootstrap(App, [
APP_ROUTES_PROVIDER,
])
.catch(err => console.error(err));
Ahora que el enrutador está configurado y nuestra aplicación sabe cómo manejar las rutas,
debemos mostrar los componentes reales que configuramos.
Para hacerlo, configure su plantilla / archivo HTML para su componente de nivel superior
(aplicación) de la siguiente manera:
//app.ts
https://riptutorial.com/es/home 145
@Component({
selector: 'app',
templateUrl: 'app.html',
styleUrls: ['app.css'],
directives: [
ROUTER_DIRECTIVES,
]
})
export class App {
constructor() {
}
}
Por ejemplo: Digamos que quería una barra de herramientas en cada página que se mantiene
constante entre las rutas, de forma similar al aspecto del Desbordamiento de pila. Puede anidar el
<router-outlet> bajo los elementos para que solo cambien ciertas partes de la página.
Ahora que las rutas están configuradas, necesitamos alguna forma de cambiar realmente las
rutas.
Este ejemplo mostrará cómo cambiar las rutas usando la plantilla, pero es posible cambiar las
rutas en TypeScript.
<a routerLink="/home">Home</a>
Si el usuario hace clic en ese enlace, se dirigirá a /home . El enrutador sabe cómo manejar /home ,
por lo que mostrará el componente de Home .
Lo que requeriría que existiera una matriz llamada links , así que agregue esto a app.ts :
public links[] = [
'home',
'login'
]
https://riptutorial.com/es/home 146
Esto recorrerá la matriz y agregará un elemento <a> con la directiva routerLink = el valor del
elemento actual en la matriz, creando esto:
<a routerLink="home">home</a>
<a routerLink="login">login</a>
Esto es particularmente útil si tiene muchos enlaces, o tal vez los enlaces necesitan ser
cambiados constantemente. Dejamos que Angular maneje el ajetreado trabajo de agregar
enlaces con solo darle la información que requiere.
En este momento, los links[] son estáticos, pero es posible alimentarlos con datos de otra fuente.
//app.routes.ts
En la primera línea, importamos provideRouter para que podamos informarle a nuestra aplicación
cuáles son las rutas durante la fase de arranque.
Homey Profile son solo dos componentes como ejemplo. Deberá importar cada Component que
necesite como ruta.
path : la ruta al componente. NO NECESITA USAR '/ ........' Angular lo hará automáticamente
https://riptutorial.com/es/home 147
Control de acceso desde o hacia una ruta
Estas interfaces se pueden implementar en su guardia para otorgar o eliminar el acceso a ciertos
procesos de navegación.
https://riptutorial.com/es/home 148
Guardia de ruta sincrónica
@Injectable()
export class SynchronousGuard implements CanActivate {
canActivate() {
console.log('SynchronousGuard#canActivate called');
return true;
}
}
Para un comportamiento más complejo, un protector de ruta puede bloquear de forma asíncrona
la navegación. Un protector de ruta asíncrono puede devolver una Observable o Promesa.
Esto es útil para situaciones como esperar la entrada del usuario para responder una pregunta,
esperar para guardar con éxito los cambios en el servidor o esperar a recibir datos de un servidor
remoto.
@Injectable()
export class AsynchronousGuard implements CanActivate {
constructor(private router: Router, private auth: MockAuthenticationService) {}
canActivate(route:ActivatedRouteSnapshot,
state:RouterStateSnapshot):Observable<boolean>|boolean {
this.auth.subscribe((authenticated) => {
if (authenticated) {
return true;
}
this.router.navigateByUrl('/login');
return false;
});
}
}
Archivo app.routes
https://riptutorial.com/es/home 149
Las rutas protegidas se han podido canActivate a Guard
//components
import { LoginComponent } from './login/login.component';
import { DashboardComponent } from './dashboard/dashboard.component';
bootstrap(AppComponent, [
APP_ROUTER_PROVIDERS
])
.then(success => console.log(`Bootstrap success`))
.catch(error => console.log(error));
Estamos utilizando una protección de nivel superior en nuestra configuración de ruta para
capturar al usuario actual en la carga de la primera página, y una resolución para almacenar el
valor del currentUser , que es nuestro usuario autenticado desde el backend.
https://riptutorial.com/es/home 150
export const routes = [
{
path: 'Dash',
pathMatch : 'prefix',
component: DashCmp,
canActivate: [AuthGuard],
resolve: {
currentUser: CurrentUserResolver
},
children: [...[
path: '',
component: ProfileCmp,
resolve: {
currentUser: currentUser
}
]]
}
];
@Injectable()
export class AuthService {
constructor(http: Http) {
this.http = http;
@Injectable()
export class AuthGuard implements CanActivate {
constructor(auth: AuthService) {
this.auth = auth;
}
canActivate(route, state) {
return Observable
.merge(this.auth.fetchCurrentUser(), Observable.of(true))
.filter(x => x == true);
}
https://riptutorial.com/es/home 151
}
@Injectable()
export class CurrentUserResolver implements Resolve {
constructor(auth: AuthService) {
this.auth = auth;
}
resolve(route, state) {
return this.auth.currentUser;
}
}
https://riptutorial.com/es/home 152
Capítulo 43: examen de la unidad
Examples
Prueba unitaria basica
archivo componente
@Component({
selector: 'example-test-compnent',
template: '<div>
<div>{{user.name}}</div>
<div>{{user.fname}}</div>
<div>{{user.email}}</div>
</div>'
})
Archivo de prueba
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ExampleTestComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ExampleTestComponent );
component = fixture.componentInstance;
fixture.detectChanges();
});
expect(component.user.name).toEqual('name');
expect(component.user.fname).toEqual('fname');
https://riptutorial.com/es/home 153
expect(component.user.email).toEqual('email');
});
});
https://riptutorial.com/es/home 154
Capítulo 44: Ganchos de ciclo de vida
Observaciones
Disponibilidad de eventos
AfterViewInit y AfterViewChecked solo están disponibles en Componentes , y no en Directivas .
Orden de eventos
• OnChanges (varias veces)
• OnInit (una vez)
• DoCheck (varias veces)
• AfterContentInit (una vez)
• AfterContentChecked (varias veces)
• AfterViewInit (una vez) (solo componente)
• AfterViewChecked (varias veces) (solo componente)
• OnDestroy (una vez)
Otras lecturas
• Documentación angular - Ganchos de ciclo de vida
Examples
OnInit
@Component({
selector: 'so-oninit-component',
templateUrl: 'oninit-component.html',
styleUrls: ['oninit-component.']
})
class OnInitComponent implements OnInit {
ngOnInit(): void {
console.log('Component is ready !');
}
}
https://riptutorial.com/es/home 155
EnDestroy
@Component({
selector: 'so-ondestroy-component',
templateUrl: 'ondestroy-component.html',
styleUrls: ['ondestroy-component.']
})
class OnDestroyComponent implements OnDestroy {
ngOnDestroy(): void {
console.log('Component was destroyed !');
}
}
OnChanges
Se activa cuando una o más de las propiedades del componente o directiva han sido cambiadas.
@Component({
selector: 'so-onchanges-component',
templateUrl: 'onchanges-component.html',
styleUrls: ['onchanges-component.']
})
class OnChangesComponent implements OnChanges {
@Input() name: string;
message: string;
name: {
currentValue: 'new name value',
previousValue: 'old name value'
},
message: {
currentValue: 'new message value',
previousValue: 'old message value'
}
AfterContentInit
Incendio una vez finalizada la inicialización del contenido del componente o directiva.
https://riptutorial.com/es/home 156
import { Component, AfterContentInit } from '@angular/core';
@Component({
selector: 'so-aftercontentinit-component',
templateUrl: 'aftercontentinit-component.html',
styleUrls: ['aftercontentinit-component.']
})
class AfterContentInitComponent implements AfterContentInit {
ngAfterContentInit(): void {
console.log('Component content have been loaded!');
}
}
AfterContentChecked
@Component({
selector: 'so-aftercontentchecked-component',
templateUrl: 'aftercontentchecked-component.html',
styleUrls: ['aftercontentchecked-component.']
})
class AfterContentCheckedComponent implements AfterContentChecked {
ngAfterContentChecked(): void {
console.log('Component content have been checked!');
}
}
AfterViewInit
@Component({
selector: 'so-afterviewinit-component',
templateUrl: 'afterviewinit-component.html',
styleUrls: ['afterviewinit-component.']
})
class AfterViewInitComponent implements AfterViewInit {
ngAfterViewInit(): void {
console.log('This event fire after the content init have been loaded!');
}
}
https://riptutorial.com/es/home 157
AfterViewChecked
@Component({
selector: 'so-afterviewchecked-component',
templateUrl: 'afterviewchecked-component.html',
styleUrls: ['afterviewchecked-component.']
})
class AfterViewCheckedComponent implements AfterViewChecked {
ngAfterViewChecked(): void {
console.log('This event fire after the content have been checked!');
}
}
DoCheck
@Component({
selector: 'so-docheck-component',
templateUrl: 'docheck-component.html',
styleUrls: ['docheck-component.']
})
class DoCheckComponent implements DoCheck {
@Input() elements: string[];
differ: any;
ngDoCheck(): void {
// get value for elements property
const changes = this.differ.diff(this.elements);
if (changes) {
changes.forEachAddedItem(res => console.log('Added', r.item));
changes.forEachRemovedItem(r => console.log('Removed', r.item));
}
}
}
https://riptutorial.com/es/home 158
Capítulo 45: Instalar complementos de
terceros con [email protected]
Observaciones
Es posible instalar otras bibliotecas siguiendo este enfoque, sin embargo, puede ser necesario
especificar el tipo de módulo, el archivo principal y la extensión predeterminada.
'lodash': {
format: 'cjs',
defaultExtension: 'js',
main: 'index.js'
}
'moment': {
main: 'moment.js'
}
Examples
Añadiendo librería jquery en proyecto angular-cli.
Examine los node_modules y busque los archivos y carpetas que desea agregar a la
carpeta del proveedor.
module.exports = function(defaults) {
return new Angular2App(defaults, {
https://riptutorial.com/es/home 159
vendorNpmFiles: [
// ...
'jquery/dist/*.js'
]
});
};
};
@Component({
https://riptutorial.com/es/home 160
})
export class YourComponent {
ngOnInit() {
$.("button").click(function(){
// now you can DO, what ever you want
});
console.log();
}
}
Si siguió los pasos correctamente, ahora debería tener una biblioteca jQuery trabajando en su
proyecto. ¡Disfrutar!
Algunas bibliotecas o complementos pueden no tener tipografías. Sin estos, TypeScript no puede
escribirlos y, por lo tanto, provoca errores de compilación. Estas bibliotecas se pueden seguir
utilizando de forma diferente a los módulos importados.
• Estos scripts deben agregar un global (por ejemplo, THREE , mapbox , $ , etc.) o
adjuntarlos a un global
2. En el componente que los requiere, use declare para inicializar una variable que coincida
con el nombre global utilizado por la biblioteca. Esto permite que TypeScript sepa que ya se
ha inicializado. 1
Algunas bibliotecas se adjuntan a la window , que deberían extenderse para poder acceder a
la aplicación.
@Component { ... }
export class AppComponent implements AfterViewInit {
...
ngAfterViewInit() {
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
window.Intercom('boot', { ... }
}
}
https://riptutorial.com/es/home 161
• NOTA: Algunas bibliotecas pueden interactuar con el DOM y deben usarse en el
método de ciclo de vida del componente apropiado.
https://riptutorial.com/es/home 162
Capítulo 46: Interacciones de los
componentes
Sintaxis
• <element [variableName]="value"></element> //Declaring input to child when using @Input()
method.
• <element (childOutput)="parentFunction($event)"></element> //Declaring output from child
when using @Output() method.
• @Output() pageNumberClicked = new EventEmitter(); //Used for sending output data from child
component when using @Output() method.
• this.pageNumberClicked.emit(pageNum); //Used to trigger data output from child component.
when using @Output() method.
• @ViewChild(ComponentClass) //Property decorator is required when using ViewChild.
Parámetros
Nombre Valor
Examples
Interacción padre - hijo usando las propiedades @Input y @Output
PagerComponent crea una lista de números de página en función del número total de páginas
que recibe de DataListComponent. PagerComponent también le permite a DataListComponent
saber cuándo el usuario hace clic en cualquier número de página a través de la propiedad Salida.
@Component({
selector: 'datalist',
template: `
<table>
<tr *ngFor="let person of personsData">
https://riptutorial.com/es/home 163
<td>{{person.name}}</td>
<td>{{person.surname}}</td>
</tr>
</table>
pageChanged(pageNumber: number){
var response = this.dataListService.getData(pageNumber); //Request data from the
service with new page number
this.personsData = response.persons;
}
}
@NgModule({
imports: [CommonModule],
exports: [],
declarations: [DataListComponent, PagerComponent],
providers: [DataListService],
})
export class DataListModule { }
@Component({
selector: 'pager',
template: `
<div id="pager-wrapper">
<span *ngFor="#page of pageCount" (click)="pageClicked(page)">{{page}}</span>
</div>
`
})
export class PagerComponent {
@Input() pageCount: number;
@Output() pageNumberClicked = new EventEmitter();
constructor() { }
pageClicked(pageNum){
this.pageNumberClicked.emit(pageNum); //Send clicked page number as output
}
}
https://riptutorial.com/es/home 164
Viewchild ofrece una forma de interacción de padres a hijos. No hay comentarios o resultados del
niño cuando se usa ViewChild.
@Component({
selector: 'datalist',
template: `<input type='text' [(ngModel)]="searchText" />
<button (click)="getData()">Search</button>
<table>
<tr *ngFor="let person of personsData">
<td>{{person.name}}</td>
<td>{{person.surname}}</td>
</tr>
</table>
<pager></pager>
`
})
export class DataListComponent {
private personsData = null;
private searchText: string;
@ViewChild(PagerComponent)
private pagerComponent: PagerComponent;
getData(){
var response = this.dataListService.getData(this.searchText);
this.personsData = response.data;
this.pagerComponent.setPaging(this.personsData / 10); //Show 10 records per page
}
}
@NgModule({
imports: [CommonModule],
exports: [],
declarations: [DataListComponent, PagerComponent],
providers: [DataListService],
})
export class DataListModule { }
El componente hijo no está disponible hasta que el componente padre se representa. Intentar
acceder al niño antes que a los padres AfterViewInit life cyle hook causará una excepción.
https://riptutorial.com/es/home 165
Servicio que se utiliza para la comunicación:
@Injectable()
export class ComponentCommunicationService {
componentChanged$ = this.componentChangeSource.asObservable();
dateCreated$ = this.newDateCreationSource.asObservable();
refresh() {
this.componentChangeSource.next();
}
broadcastDate(date: Date) {
this.newDateCreationSource.next(date);
}
}
Componente principal:
@Component({
selector: 'parent',
template: `
<button (click)="refreshSubsribed()">Refresh</button>
<h1>Last date from child received: {{lastDate}}</h1>
<child-component></child-component>
`
})
export class ParentComponent implements OnInit {
lastDate: Date;
constructor(private communicationService: ComponentCommunicationService) { }
ngOnInit() {
this.communicationService.dateCreated$.subscribe(newDate => {
this.lastDate = newDate;
});
}
refreshSubsribed() {
this.communicationService.refresh();
}
}
Componente hijo:
@Component({
https://riptutorial.com/es/home 166
selector: 'child-component',
template: `
<h1>Last refresh from parent: {{lastRefreshed}}</h1>
<button (click)="sendNewDate()">Send new date</button>
`
})
export class ChildComponent implements OnInit {
lastRefreshed: Date;
constructor(private communicationService: ComponentCommunicationService) { }
ngOnInit() {
this.communicationService.componentChanged$.subscribe(event => {
this.onRefresh();
});
}
sendNewDate() {
this.communicationService.broadcastDate(new Date());
}
onRefresh() {
this.lastRefreshed = new Date();
}
}
AppModule:
@NgModule({
declarations: [
ParentComponent,
ChildComponent
],
providers: [ComponentCommunicationService],
bootstrap: [AppComponent] // not included in the example
})
export class AppModule {}
https://riptutorial.com/es/home 167
Capítulo 47: Interacciones de los
componentes
Introducción
Compartir información entre diferentes directivas y componentes.
Examples
Pase datos de padre a hijo con enlace de entrada
Use un establecedor de propiedades de entrada para interceptar y actuar sobre un valor del
padre.
https://riptutorial.com/es/home 168
Aquí está el NameParentComponent que muestra las variaciones de nombre, incluido un nombre
con todos los espacios:
El componente hijo expone una propiedad EventEmitter con la que emite eventos cuando ocurre
algo. El padre se une a esa propiedad de evento y reacciona a esos eventos.
La propiedad EventEmitter del niño es una propiedad de salida, típicamente adornada con una
decoración @Output como se ve en este VoterComponent:
Al hacer clic en un botón se activa la emisión de un verdadero o falso (la carga útil booleana).
https://riptutorial.com/es/home 169
(onVoted)="onVoted($event)">
</my-voter>
`
})
export class VoteTakerComponent {
agreed = 0;
disagreed = 0;
voters = ['Mr. IQ', 'Ms. Universe', 'Bombasto'];
onVoted(agreed: boolean) {
agreed ? this.agreed++ : this.disagreed++;
}
}
Un componente principal no puede utilizar el enlace de datos para leer propiedades secundarias o
invocar métodos secundarios. Podemos hacer ambas cosas creando una variable de referencia
de plantilla para el elemento secundario y luego hacer referencia a esa variable dentro de la
plantilla principal como se ve en el siguiente ejemplo.
Tenemos un hijo CountdownTimerComponent que repetidamente cuenta atrás hasta cero y lanza
un cohete. Tiene métodos de inicio y detención que controlan el reloj y muestra un mensaje de
estado de cuenta regresiva en su propia plantilla.
https://riptutorial.com/es/home 170
import { Component } from '@angular/core';
import { CountdownTimerComponent } from './countdown-timer.component';
@Component({
selector: 'countdown-parent-lv',
template: `
<h3>Countdown to Liftoff (via local variable)</h3>
<button (click)="timer.start()">Start</button>
<button (click)="timer.stop()">Stop</button>
<div class="seconds">{{timer.seconds}}</div>
<countdown-timer #timer></countdown-timer>
`,
styleUrls: ['demo.css']
})
export class CountdownLocalVarParentComponent { }
El componente principal no puede enlazar datos a los métodos de inicio y parada del niño ni a su
propiedad de segundos.
Podemos colocar una variable local (#timer) en la etiqueta () que representa el componente
secundario. Eso nos da una referencia al componente secundario en sí mismo y la capacidad de
acceder a cualquiera de sus propiedades o métodos desde la plantilla principal.
En este ejemplo, conectamos los botones principales al inicio y al final del niño y utilizamos la
interpolación para mostrar la propiedad de los segundos del niño.
El enfoque de la variable local es simple y fácil. Pero está limitado porque el cableado padre-hijo
debe hacerse completamente dentro de la plantilla padre. El componente principal en sí no tiene
acceso al elemento secundario.
Cuando la clase de componente principal requiere ese tipo de acceso, inyectamos el componente
secundario en el principal como un ViewChild.
https://riptutorial.com/es/home 171
<h3>Countdown to Liftoff (via ViewChild)</h3>
<button (click)="start()">Start</button>
<button (click)="stop()">Stop</button>
<div class="seconds">{{ seconds() }}</div>
<countdown-timer></countdown-timer>
`,
styleUrls: ['demo.css']
})
export class CountdownViewChildParentComponent implements AfterViewInit {
@ViewChild(CountdownTimerComponent)
private timerComponent: CountdownTimerComponent;
seconds() { return 0; }
ngAfterViewInit() {
// Redefine `seconds()` to get from the `CountdownTimerComponent.seconds` ...
// but wait a tick first to avoid one-time devMode
// unidirectional-data-flow-violation error
setTimeout(() => this.seconds = () => this.timerComponent.seconds, 0);
}
start() { this.timerComponent.start(); }
stop() { this.timerComponent.stop(); }
}
Se necesita un poco más de trabajo para obtener la vista secundaria en la clase de componente
principal.
La variable local #timer desaparece de los metadatos del componente. En su lugar, enlazamos
los botones con los propios métodos de inicio y detención del componente principal y
presentamos los segundos de tic-tac en una interpolación alrededor del método de segundos del
componente principal.
El gancho del ciclo de vida de ngAfterViewInit es una arruga importante. El componente del
temporizador no está disponible hasta que Angular muestra la vista principal. Así que mostramos
0 segundos inicialmente.
Luego Angular llama al gancho del ciclo de vida de ngAfterViewInit, momento en el cual es
demasiado tarde para actualizar la visualización de la cuenta principal de los segundos de la
cuenta regresiva. La regla de flujo de datos unidireccional de Angular nos impide actualizar las
vistas principales en el mismo ciclo. Tenemos que esperar un turno antes de poder mostrar los
segundos.
Usamos setTimeout para esperar una marca y luego revisar el método de los segundos para que
tome valores futuros del componente del temporizador.
Un componente padre y sus hijos comparten un servicio cuya interfaz permite la comunicación
https://riptutorial.com/es/home 172
bidireccional dentro de la familia.
MissionControlComponent proporciona la instancia del servicio que comparte con sus hijos (a
través de la matriz de metadatos del proveedor) e inyecta esa instancia en sí misma a través de
su constructor:
https://riptutorial.com/es/home 173
missionService.missionConfirmed$.subscribe(
astronaut => {
this.history.push(`${astronaut} confirmed the mission`);
});
}
announce() {
let mission = this.missions[this.nextMission++];
this.missionService.announceMission(mission);
this.history.push(`Mission "${mission}" announced`);
if (this.nextMission >= this.missions.length) { this.nextMission = 0; }
}
}
https://riptutorial.com/es/home 174
AstronautComponent. Este es un paso de guardia de fuga de memoria. No hay riesgo real en esta
aplicación porque la vida útil de un AstronautComponent es la misma que la vida misma de la
aplicación. Eso no siempre sería cierto en una aplicación más compleja.
https://riptutorial.com/es/home 175
Capítulo 48: Interceptor Http
Observaciones
Lo que hacemos con la clase HttpServiceLayer es extender la clase Http desde angular y
agregarle nuestra propia lógica.
Luego inyectamos esa clase en la clase bootstrap de la aplicación y le decimos a Angular que
importamos la clase Http, en la parte posterior para insertar HttpServiceLayer.
Examples
Clase simple Extendiendo la clase Http de Angular
/**
* This class extends the Http class from angular and adds automaticaly the server URL(if in
development mode) and 2 headers by default:
* Headers added: 'Content-Type' and 'X-AUTH-TOKEN'.
* 'Content-Type' can be set in any othe service, and if set, it will NOT be overwritten in
this class any more.
*/
export class HttpServiceLayer extends Http {
/**
* This method checks if there are any headers added and if not created the headers map and
ads 'Content-Type' and 'X-AUTH-TOKEN'
https://riptutorial.com/es/home 176
* 'Content-Type' is not overwritten if it is allready available in the headers map
*/
getRequestOptionArgs(options?: RequestOptionsArgs): RequestOptionsArgs {
if (options == null) {
options = new RequestOptions();
}
if (options.headers == null) {
options.headers = new Headers();
}
if (!options.headers.get('Content-Type')) {
options.headers.append('Content-Type', 'application/json');
}
if (this.appConfig.getAuthToken() != null) {
options.headers.append('X-AUTH-TOKEN', this.appConfig.getAuthToken());
}
return options;
}
/**
* This method as the name sugests intercepts the request and checks if there are any errors.
* If an error is present it will be checked what error there is and if it is a general one
then it will be handled here, otherwise, will be
* thrown up in the service layers
*/
intercept(observable: Observable<Response>): Observable<Response> {
// return observable;
return observable.catch((err, source) => {
if (err.status == 401) {
this._router.navigate(['/login']);
//return observable;
return Observable.empty();
} else {
//return observable;
return Observable.throw(err);
}
});
}
}
Después de extender la clase Http, necesitamos decirle a angular que use esta clase en lugar de
la clase Http.
Para hacer esto, en nuestro módulo principal (o según las necesidades, solo un módulo en
particular), debemos escribir en la sección de proveedores:
https://riptutorial.com/es/home 177
import { Router } from '@angular/router';
@NgModule({
declarations: [ ... ],
imports: [ ... ],
exports: [ ... ],
providers: [
ApplicationConfiguration,
{
provide: Http,
useFactory: httpServiceFactory,
deps: [XHRBackend, RequestOptions, Router, ApplicationConfiguration]
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
Nota: ApplicationConfiguration es solo un servicio que utilizo para guardar algunos valores
durante la duración de la aplicación.
@Injectable()
export class AuthHeaderInterceptor implements HttpInterceptor {
https://riptutorial.com/es/home 178
Capítulo 49: Inyección de Dependencia y
Servicios.
Examples
Servicio de ejemplo
servicios / my.service.ts
@Injectable()
export class MyService {
data: any = [1, 2, 3];
getData() {
return this.data;
}
}
El registro del proveedor de servicios en el método bootstrap hará que el servicio esté disponible
globalmente.
main.ts
bootstrap(AppComponent, [MyService]);
En la versión RC5, el registro del proveedor de servicios global se puede realizar dentro del
archivo del módulo. Para obtener una única instancia de su servicio para toda su aplicación, el
servicio debe ser declarado en la lista de proveedores en el módulo de su aplicación.
app_module.ts
@NgModule({
declarations: [ AppComponent ],
imports: [ BrowserModule,
routing,
https://riptutorial.com/es/home 179
RouterModule,
HttpModule ],
providers: [ appRoutingProviders,
MyService
],
bootstrap: [AppComponent],
})
export class AppModule {}
Uso en MyComponent
componentes / my.component.ts
@Component({
...
...
providers:[MyService] //
})
export class MyComponent implements OnInit {
data: any[];
// Creates private variable myService to use, of type MyService
constructor(private myService: MyService) { }
ngOnInit() {
this.data = this.myService.getData();
}
}
servicios / my.service.ts
@Injectable()
export class MyService {
data: any = [1, 2, 3];
getData() {
return Promise.resolve(this.data);
}
}
getData() ahora actúa como una llamada REST que crea una Promesa, que se resuelve de
inmediato. Los resultados pueden ser portátiles dentro de .then() y también se pueden detectar
errores. Esta es una buena práctica y convención para métodos asíncronos.
componentes / my.component.ts
https://riptutorial.com/es/home 180
import { Component, OnInit } from '@angular/core';
import { MyService } from '../services/my.service';
@Component({...})
export class MyComponent implements OnInit {
data: any[];
// Creates private variable myService to use, of type MyService
constructor(private myService: MyService) { }
ngOnInit() {
// Uses an "arrow" function to set data
this.myService.getData().then(data => this.data = data);
}
}
Probando un servicio
import 'rxjs/add/operator/toPromise';
interface LoginCredentials {
password: string;
user: string;
}
@Injectable()
export class AuthService {
constructor(private http: Http) { }
return response.json();
}
}
describe('AuthService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [
https://riptutorial.com/es/home 181
AuthService,
Http,
{ provide: ConnectionBackend, useClass: MockBackend },
]
});
});
// Alternative 1
it('should login user if right credentials are passed', async(
inject([AuthService], async (authService) => {
const backend: MockBackend = TestBed.get(ConnectionBackend);
const http: Http = TestBed.get(Http);
expect(result).toEqual({
accessToken: 'abcdef',
});
}))
);
// Alternative 2
it('should login user if right credentials are passed', async () => {
const backend: MockBackend = TestBed.get(ConnectionBackend);
const http: Http = TestBed.get(Http);
expect(result).toEqual({
accessToken: 'abcdef',
});
https://riptutorial.com/es/home 182
});
// Alternative 3
it('should login user if right credentials are passed', async (done) => {
const authService: AuthService = TestBed.get(AuthService);
try {
const result = await authService.signIn({ password: 'ok', user: 'bruno' });
expect(result).toEqual({
accessToken: 'abcdef',
});
done();
} catch (err) {
fail(err);
done();
}
});
});
https://riptutorial.com/es/home 183
Capítulo 50: Mejora de fuerza bruta
Introducción
Si desea actualizar la versión de Angular CLI de su proyecto, puede encontrar errores y errores
difíciles de solucionar simplemente al cambiar el número de versión de Angular CLI en su
proyecto. Además, debido a que la CLI angular oculta gran parte de lo que ocurre en el proceso
de compilación y agrupación, realmente no se puede hacer mucho cuando las cosas van mal allí.
A veces, la forma más sencilla de actualizar la versión de Angular CLI del proyecto es
simplemente armar un nuevo proyecto con la versión de Angular CLI que desea utilizar.
Observaciones
Debido a que Angular 2 es tan modular y encapsulado, puede simplemente copiar todos sus
componentes, servicios, tuberías, directivas y luego completar el NgModule como estaba en el
proyecto anterior.
Examples
Andamios un nuevo proyecto de CLI angular
ng new NewProject
ng init NewProject
https://riptutorial.com/es/home 184
Capítulo 51: Mocking @ ngrx / Tienda
Introducción
@ ngrx / Store se está utilizando cada vez más en los proyectos de Angular 2. Como tal, se
requiere que la Tienda se inyecte en el constructor de cualquier Componente o Servicio que
desee usarla. Pruebas unitarias La tienda no es tan fácil como probar un servicio simple. Al igual
que con muchos problemas, hay una gran variedad de formas de implementar soluciones. Sin
embargo, la receta básica es escribir una clase simulada para la interfaz Observer y escribir una
clase simulada para Tienda. Luego puedes inyectar Store como proveedor en tu TestBed.
Parámetros
nombre descripción
error descripción
súper descripción
observador simulado que no hace nada a menos que esté definido para
acción $
hacerlo en la clase simulada
acciónReductor observador simulado que no hace nada a menos que esté definido para
$ hacerlo en la clase simulada
Observaciones
El observador es un genérico, pero debe ser de any tipo para evitar la complejidad de las pruebas
unitarias. La razón de esta complejidad, es que el constructor de la Tienda espera argumentos de
observador con diferentes tipos genéricos. El uso de any evita esta complicación.
Es posible pasar valores nulos al súper constructor de StoreMock, pero esto restringe el número
de aserciones que se pueden usar para probar a la clase en el futuro.
El Componente que se usa en este ejemplo solo se usa como contexto para la forma en que uno
podría inyectar la Tienda como un suministro en la configuración de la prueba.
Examples
https://riptutorial.com/es/home 185
Mock observador
constructor() {}
describe('Component:Typeahead', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [...],
declarations: [Typeahead],
providers: [
{provide: Store, useClass: StoreMock} // NOTICE useClass instead of useValue
]
}).compileComponents();
});
});
Esta es una prueba unitaria de un componente que tiene Almacén como una dependencia. Aquí,
estamos creando una nueva clase llamada MockStore que se inyecta en nuestro componente en
lugar de la tienda habitual.
class MockStore {
public dispatch(obj) {
console.log('dispatching from the mock store!')
}
https://riptutorial.com/es/home 186
public select(obj) {
console.log('selecting from the mock store!');
return Observable.of({})
}
}
describe('AppComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent,
SmartComponentComponent,
DumbComponentComponent,
],
imports: [
StoreModule.provideStore({mainReducer})
],
providers: [
{provide: Store, useClass: MockStore}
]
});
});
Esta es una prueba unitaria de un componente que tiene Almacén como una dependencia. Aquí,
podemos usar una tienda con el "estado inicial" predeterminado y, al mismo tiempo, evitar que se
realicen acciones de envío cuando se llama a store.dispatch () .
describe('AppComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent,
SmartComponentComponent,
DumbComponentComponent,
],
imports: [
StoreModule.provideStore({mainReducer})
]
https://riptutorial.com/es/home 187
});
});
}));
});
Servicio
@Injectable()
export class PostService {
Componente
https://riptutorial.com/es/home 188
@Component({
selector: 'app-post',
templateUrl: './post.component.html',
styleUrls: ['./post.component.scss'],
providers : [PostService]
})
export class PostComponent{
servicio de prueba
• cuando quiera probar el servicio que usa http, debe usar mockBackend. y se lo inyectan.
• Necesitas también inyectar postService.
https://riptutorial.com/es/home 189
});
service
.postRequest(PostModel)
.subscribe((response) => {
expect(response).toBeDefined();
});
}));
});
componente de prueba
let mockRouter = {
navigate: jasmine.createSpy('navigate')
};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [PostComponent],
imports: [RouterTestingModule.withRoutes([]),ModalModule.forRoot() ],
providers: [PostService ,MockBackend,BaseRequestOptions,
{provide: Http, deps: [MockBackend, BaseRequestOptions],
useFactory: (backend: XHRBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions);
}
},
{provide: Router, useValue: mockRouter}
],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(PostComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
component.postExample();
let postModel = new PostModel();
let response = {
'message' : 'message',
'ok' : true
};
mockBackend.connections.subscribe((connection: MockConnection) => {
https://riptutorial.com/es/home 190
postComponent.result = 'Success'
connection.mockRespond(new Response(
new ResponseOptions({
body: response
})
))
});
service.postRequest(postModel)
.subscribe((data) => {
expect(component.result).toBeDefined();
expect(PostComponent.result).toEqual('Success');
expect(data).toEqual(response);
});
}));
});
Tienda simple
simple.action.ts
simple.efficts.ts
@Injectable()
export class simpleEffects {
@Effect()
addAction$: Observable<simpleAction> = this.actions$
.ofType(simpleActionTpye.add)
.switchMap((action: simpleAction) => {
console.log(action);
https://riptutorial.com/es/home 191
}
simple.reducer.ts
tienda / index.ts
app.module.ts
@NgModule({
declarations: [
AppComponent
],
imports: [
https://riptutorial.com/es/home 192
BrowserModule,
// store
store,
effects
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
resultado 0 1 3 6
https://riptutorial.com/es/home 193
Capítulo 52: Módulos
Introducción
Los módulos angulares son contenedores para diferentes partes de su aplicación.
Puede tener módulos anidados, su app.module ya está anidando otros módulos como BrowserModule
y puede agregar RouterModule y así sucesivamente.
Examples
Un modulo simple
Un módulo es una clase con el decorador @NgModule . Para crear un módulo agregamos @NgModule
pasando algunos parámetros:
• bootstrap : El componente que será la raíz de su aplicación. Esta configuración solo está
presente en su módulo raíz
• declarations : Recursos que el módulo declara. Cuando agrega un nuevo componente, debe
actualizar las declaraciones ( ng generate component hace automáticamente)
• exports : recursos que el módulo exporta que se pueden usar en otros módulos.
• imports : recursos que el módulo utiliza de otros módulos (solo se aceptan clases de
módulos)
• providers : Recursos que pueden inyectarse (di) en un componente.
Un ejemplo simple:
@NgModule({
bootstrap: [AppComponent]
declarations: [AppComponent],
exports: [],
imports: [BrowserModule],
providers: [],
})
export class AppModule { }
Módulos de anidamiento
Los módulos pueden ser anidadas mediante el uso de la imports parámetro de @NgModule
decorador.
Podemos crear un core.module en nuestra aplicación que contendrá cosas genéricas, como un
ReservePipe (una tubería que invierte una cadena) y agruparlas en este módulo:
https://riptutorial.com/es/home 194
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { ReversePipe } from '../reverse.pipe';
@NgModule({
imports: [
CommonModule
],
exports: [ReversePipe], // export things to be imported in another module
declarations: [ReversePipe],
})
export class CoreModule { }
Luego en el app.module :
@NgModule({
declarations: [...], // ReversePipe is available without declaring here
// because CoreModule exports it
imports: [
CoreModule, // import things from CoreModule
...
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
https://riptutorial.com/es/home 195
Capítulo 53: Módulos de funciones
Examples
Un módulo de funciones
// my-feature.module.ts
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
@NgModule({
imports: [ CommonModule ],
declarations: [ MyComponent, MyDirective, MyPipe ],
exports: [ MyComponent ],
providers: [ MyService ]
})
export class MyFeatureModule { }
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@NgModule({
// import MyFeatureModule in root module
imports: [ BrowserModule, MyFeatureModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
https://riptutorial.com/es/home 196
Capítulo 54: ngrx
Introducción
Ngrx es una biblioteca poderosa que puedes usar con Angular2 . La idea subyacente es
combinar dos conceptos que funcionen bien juntos para tener una aplicación reactiva con un
contenedor de estado predecible: - [Redux] [1] - [RxJs] [2] Las principales ventajas: - Compartir
datos en su aplicación entre sus componentes va a ser más fácil: probar la lógica central de su
aplicación consiste en probar funciones puras, sin ninguna dependencia de Angular2 (¡muy fácil!)
[1]: http://redux.js.org [2]: http: // reactivex. io / rxjs
Examples
Ejemplo completo: iniciar sesión / cerrar sesión de un usuario
Prerrequisitos
https://riptutorial.com/es/home 197
Y aquí está la interfaz que IUser :
user.interface.ts
// for UI
isConnecting: boolean;
isConnected: boolean;
};
Ahora tenemos que pensar qué tipo de acciones se supone que deben manejar nuestros
reductores .
Vamos a decir aquí:
user.actions.ts
Pero antes de usar esas acciones, permítame explicar por qué vamos a necesitar un servicio para
enviar algunas de esas acciones para nosotros:
Digamos que queremos conectar a un usuario. Entonces, haremos clic en el botón de inicio de
sesión y esto es lo que sucederá:
user.service.ts
https://riptutorial.com/es/home 198
@Injectable()
export class UserService {
constructor(public store$: Store<AppState>) { }
login(username: string) {
// first, dispatch an action saying that the user's tyring to connect
// so we can lock the button until the HTTP request finish
this.store$.dispatch({ type: UserActions.USR_IS_CONNECTING });
logout() {
// first, dispatch an action saying that the user's tyring to connect
// so we can lock the button until the HTTP request finish
this.store$.dispatch({ type: UserActions.USR_IS_DISCONNECTING });
user.state.ts
// for UI
isConnecting: false,
isConnected: false,
isDisconnecting: false
};
};
https://riptutorial.com/es/home 199
• El estado actual
• Una Action de tipo Action<{type: string, payload: any}>
user.reducer.ts
// ...
}
Con suerte, hay una forma más fácil de escribir eso al usar nuestra función de factory para
devolver un objeto y dentro del reductor usar un valor de parámetros predeterminado (ES6):
Luego, debemos manejar cada acción en nuestro reductor: SUGERENCIA : use la función ES6
Object.assign para mantener nuestro estado inmutable
case UserActions.USR_IS_CONNECTED:
return Object.assign({}, user, { isConnecting: false, isConnected: true, username:
action.payload.username });
case UserActions.USR_IS_DISCONNECTING:
return Object.assign({}, user, { isDisconnecting: true });
case UserActions.USR_IS_DISCONNECTED:
return Object.assign({}, user, { isDisconnecting: false, isConnected: false });
default:
return user;
}
};
https://riptutorial.com/es/home 200
5) Importe nuestro en nuestro módulo
UserReducer
app.module.ts
@NgModule({
declarations: [
AppComponent
],
imports: [
// angular modules
// ...
user.component.ts
@Component({
selector: 'user',
styles: [
'.table { max-width: 250px; }',
'.truthy { color: green; font-weight: bold; }',
'.falsy { color: red; }'
],
template: `
<h2>User information :</h2>
https://riptutorial.com/es/home 201
<table class="table">
<tr>
<th>Property</th>
<th>Value</th>
</tr>
<tr>
<td>username</td>
<td [class.truthy]="user.username" [class.falsy]="!user.username">
{{ user.username ? user.username : 'null' }}
</td>
</tr>
<tr>
<td>email</td>
<td [class.truthy]="user.email" [class.falsy]="!user.email">
{{ user.email ? user.email : 'null' }}
</td>
</tr>
<tr>
<td>isConnecting</td>
<td [class.truthy]="user.isConnecting" [class.falsy]="!user.isConnecting">
{{ user.isConnecting }}
</td>
</tr>
<tr>
<td>isConnected</td>
<td [class.truthy]="user.isConnected" [class.falsy]="!user.isConnected">
{{ user.isConnected }}
</td>
</tr>
<tr>
<td>isDisconnecting</td>
<td [class.truthy]="user.isDisconnecting" [class.falsy]="!user.isDisconnecting">
{{ user.isDisconnecting }}
</td>
</tr>
</table>
`
})
export class UserComponent {
@Input() user;
constructor() { }
}
login.component.ts
@Component({
selector: 'login',
template: `
<form
*ngIf="!(user | async).isConnected"
#loginForm="ngForm"
(ngSubmit)="login(loginForm.value.username)"
>
https://riptutorial.com/es/home 202
<input
type="text"
name="username"
placeholder="Username"
[disabled]="(user | async).isConnecting"
ngModel
>
<button
type="submit"
[disabled]="(user | async).isConnecting || (user | async).isConnected"
>Log me in</button>
</form>
<button
*ngIf="(user | async).isConnected"
(click)="logout()"
[disabled]="(user | async).isDisconnecting"
>Log me out</button>
`
})
export class LoginComponent {
public user: Observable<IUser>;
login(username: string) {
this.userService.login(username);
}
logout() {
this.userService.logout();
}
}
Como Ngrx es una combinación de los conceptos de Redux y RxJs , puede ser bastante difícil de
entender al principio. Pero este es un patrón poderoso que le permite, como hemos visto en este
ejemplo, tener una aplicación reactiva en la que puede compartir fácilmente sus datos. ¡No olvide
que hay un Plunkr disponible y puede hacerlo para hacer sus propias pruebas!
Espero que haya sido útil, aunque el tema es bastante largo, ¡salud!
https://riptutorial.com/es/home 203
Capítulo 55: Omitir la desinfección para
valores de confianza
Parámetros
Parámetros Detalles
una cadena que representa html que se insertará donde sea que esté la
plantilla
etiqueta <selector> . templateUrl es una ruta a un archivo html con el
(templateUrl)
mismo comportamiento
tubería una matriz de tuberías que son utilizadas por este componente.
Observaciones
SUPER IMPORTANTE!
EL DESHABILITAR EL DESINFECTANTE LE PERMITE AL
RIESGO DE XSS (secuencias de comandos entre sitios) Y
OTROS VECTORES DE ATAQUE. POR FAVOR ASEGÚRESE
DE QUE CONFIA EN LO QUE ESTÁ OBTENIENDO EL 100%
El uso de Pipes le relega a cambiar solo los valores de los atributos de esta manera:
o de esta manera
Examples
Derivación de desinfección con tuberías (para la reutilización del código)
https://riptutorial.com/es/home 204
El proyecto sigue la estructura de la guía de inicio rápido de Angular2 aquí .
RootOfProject
|
+-- app
| |-- app.component.ts
| |-- main.ts
| |-- pipeUser.component.ts
| \-- sanitize.pipe.ts
|
|-- index.html
|-- main.html
|-- pipe.html
main.ts
bootstrap(AppComponent);
app.component.ts
@Component({
selector: 'main-app',
templateUrl: 'main.html',
directives: [PipeUserComponent]
})
Este es el componente de nivel superior que agrupa otros componentes que se utilizan.
pipeUser.component.ts
@Component({
selector: 'pipe-example',
templateUrl: "pipe.html",
pipes: [IgnoreSanitize]
})
https://riptutorial.com/es/home 205
return this.unsafeValue.concat(input);
// returns : "unsafe/picUrl?id=input"
} else {
return "fallback/to/something";
}
}
}
sanitize.pipe.ts
@Pipe({
name: 'sanitaryPipe'
})
export class IgnoreSanitize implements PipeTransform {
index.html
<head>
Stuff goes here...
</head>
<body>
<main-app>
main.html will load inside here.
</main-app>
</body>
main.html
<othertags>
</othertags>
<pipe-example>
pipe.html will load inside here.
</pipe-example>
<moretags>
</moretags>
pipe.html
https://riptutorial.com/es/home 206
<img [src]="getUrl('1234') | sanitaryPipe">
<embed [src]="getUrl() | sanitaryPipe">
Si fueras a inspeccionar el html mientras la aplicación se está ejecutando, verías que se ve así:
<head>
Stuff goes here...
</head>
<body>
<othertags>
</othertags>
<moretags>
</moretags>
</body>
https://riptutorial.com/es/home 207
Capítulo 56: Optimización de la
representación mediante
ChangeDetectionStrategy
Examples
Predeterminado vs OnPush
Considere el siguiente componente con una entrada myInput y un valor interno llamado
someInternalValue . Ambos se utilizan en la plantilla de un componente.
@Component({
template:`
<div>
<p>{{myInput}}</p>
<p>{{someInternalValue}}</p>
</div>
`
})
class MyComponent {
@Input() myInput: any;
someInternalValue: any;
// ...
}
Sin embargo, supongamos que solo queremos volver a renderizar cuando cambian las entradas.
Considere el siguiente componente con changeDetection: configurado en
ChangeDetectionStrategy.OnPush
@Component({
changeDetection: ChangeDetectionStrategy.OnPush
template:`
<div>
<p>{{myInput}}</p>
<p>{{someInternalValue}}</p>
</div>
`
https://riptutorial.com/es/home 208
})
class MyComponent {
@Input() myInput: any;
someInternalValue: any;
// ...
}
https://riptutorial.com/es/home 209
Capítulo 57: Orden por pipa
Introducción
Cómo escribir el tubo de pedido y usarlo.
Examples
El tubo
La implementación de Pipe
@Pipe({
name: 'orderBy',
pure: false
})
export class OrderBy implements PipeTransform {
value:string[] =[];
//Basic array
if(!propertyToCheck || propertyToCheck === '-' || propertyToCheck === '+'){
https://riptutorial.com/es/home 210
return !desc ? value.sort() : value.sort().reverse();
}else {
let property:string = propertyToCheck.substr(0, 1) === '+' ||
propertyToCheck.substr(0, 1) === '-'
? propertyToCheck.substr(1)
: propertyToCheck;
return value.sort(function(a:any,b:any){
return !desc
? OrderBy._orderByComparator(a[property], b[property])
: -OrderBy._orderByComparator(a[property], b[property]);
});
}
} else {
//Loop over property of the array in order and sort
return value.sort(function(a:any,b:any){
for(let i:number = 0; i < config.length; i++){
let desc = config[i].substr(0, 1) === '-';
let property = config[i].substr(0, 1) === '+' || config[i].substr(0, 1) === '-'
? config[i].substr(1)
: config[i];
<table>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let user of users | orderBy : ['firstName']>
<td>{{user.firstName}}</td>
<td>{{user.lastName}}</td>
<td>{{user.age}}</td>
</tr>
</tbody>
</table>
https://riptutorial.com/es/home 211
<table>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let user of users | orderBy : ['-firstName']>
<td>{{user.firstName}}</td>
<td>{{user.lastName}}</td>
<td>{{user.age}}</td>
</tr>
</tbody>
</table>
https://riptutorial.com/es/home 212
Capítulo 58: Perezoso cargando un modulo
Examples
Ejemplo de carga perezosa
Los módulos de carga diferida nos ayudan a disminuir el tiempo de inicio. Con la carga lenta
nuestra aplicación no necesita cargar todo a la vez, solo necesita cargar lo que el usuario espera
ver cuando se carga la aplicación por primera vez. Los módulos que se cargan perezosamente
solo se cargarán cuando el usuario navegue a sus rutas.
app / app.module.ts
app / app.component.ts
app / app.routing.ts
https://riptutorial.com/es/home 213
{ path: 'eager', component: EagerComponent },
{ path: 'lazy', loadChildren: './lazy.module' }
];
export const routing: ModuleWithProviders = RouterModule.forRoot(routes);
app / eager.component.ts
app / lazy.module.ts
app / lazy.routing.ts
app / lazy.component.ts
https://riptutorial.com/es/home 214
Capítulo 59: Plantillas
Introducción
Las plantillas son muy similares a las plantillas en Angular 1, aunque hay muchos pequeños
cambios sintácticos que hacen más claro lo que está sucediendo.
Examples
Plantillas angulares 2
Comencemos con una plantilla muy simple que muestra nuestro nombre y nuestra cosa favorita:
<div>
Hello my name is {{name}} and I like {{thing}} quite a lot.
</div>
{}: RENDER
My name is {{name}}
Las canalizaciones, antes conocidas como "Filtros", transforman un valor en un nuevo valor,
como localizar una cadena o convertir un valor de punto flotante en una representación de
moneda:
Para resolver y enlazar una variable a un componente, use la sintaxis []. Si tenemos
este.currentVolume en nuestro componente, lo pasaremos a nuestro componente y los valores
permanecerán sincronizados:
<video-control [volume]="currentVolume"></video-control>
(): HANDLING EVENTS
<my-component (click)="onClick($event)"></my-component>
Para mantener un enlace actualizado con la entrada del usuario y otros eventos, use la sintaxis
[()]. Piense en ello como una combinación de manejar un evento y vincular una propiedad:
https://riptutorial.com/es/home 215
<input [(ngModel)] = "myName"> El valor this.myName de su componente se mantendrá
sincronizado con el valor de entrada.
* : EL ASTERISCO
Indica que esta directiva trata este componente como una plantilla y no lo dibujará como está. Por
ejemplo, ngFor toma nuestro y lo estampa para cada artículo en artículos, pero nunca muestra
nuestra inicial ya que es una plantilla:
Otras directivas similares que funcionan con plantillas en lugar de componentes renderizados son
* ngIf y * ngSwitch.
https://riptutorial.com/es/home 216
Capítulo 60: Probando ngModel
Introducción
Es un ejemplo de cómo puede probar un componente en Angular2 que tiene un ngModel.
Examples
Prueba basica
describe('MyComponent:',()=> {
const template = `
<div>
<my-component type="text" [(ngModel)]="value" name="TestName" size="9" min="3" max="8"
placeholder="testPlaceholder" disabled=false required=false></my-component>
</div>
`;
let fixture:any;
let element:any;
let context:any;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [InlineEditorComponent],
imports: [
FormsModule,
InlineEditorModule]
});
fixture = TestBed.overrideComponent(InlineEditorComponent, {
set: {
selector:"inline-editor-test",
template: template
}})
.createComponent(InlineEditorComponent);
context = fixture.componentInstance;
fixture.detectChanges();
});
https://riptutorial.com/es/home 217
let input = fixture.nativeElement.querySelector("input");
input.value = "Username";
dispatchEvent(input, 'input');
fixture.detectChanges();
fixture.whenStable().then(() => {
//this button dispatch event for save the text in component.value
fixture.nativeElement.querySelectorAll('button')[0].click();
expect(context.value).toBe("Username");
});
});
});
https://riptutorial.com/es/home 218
Capítulo 61: Probando una aplicación
Angular 2
Examples
Instalando el framework de pruebas Jasmine
La forma más común de probar aplicaciones de Angular 2 es con el marco de prueba Jasmine.
Jasmine te permite probar tu código en el navegador.
Instalar
Para comenzar, todo lo que necesita es el paquete jasmine-core (no jasmine ).
Verificar
Para verificar que Jasmine está configurado correctamente, cree el archivo ./src/unit-tests.html
con el siguiente contenido y ábralo en el navegador.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>Ng App Unit Tests</title>
<link rel="stylesheet" href="../node_modules/jasmine-core/lib/jasmine-core/jasmine.css">
<script src="../node_modules/jasmine-core/lib/jasmine-core/jasmine.js"></script>
<script src="../node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js"></script>
<script src="../node_modules/jasmine-core/lib/jasmine-core/boot.js"></script>
</head>
<body>
<!-- Unit Testing Chapter #1: Proof of life. -->
<script>
it('true is true', function () {
expect(true).toEqual(true);
});
</script>
</body>
</html>
Lo primero que necesitamos es decirle a karma que use Webpack para leer nuestras pruebas,
bajo una configuración que configuramos para el motor del paquete web. Aquí, estoy usando
https://riptutorial.com/es/home 219
babel porque escribo mi código en ES6, puedes cambiarlo por otros sabores, como Typescript. O
uso plantillas Pug (anteriormente Jade), no tienes que hacerlo.
preprocessors: {
"./karma.shim.js":["webpack"]
https://riptutorial.com/es/home 220
},
webpack: packConfig,
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
browsers: ['PhantomJS'],
concurrency: Infinity,
autoWatch: false,
singleRun: true
});
};
Hasta ahora, le hemos dicho a Karma que use el paquete web, y le hemos dicho que comience
en un archivo llamado karma.shim.js . Este archivo tendrá el trabajo de actuar como punto de
partida para el paquete web. webpack leerá este archivo y utilizará las declaraciones de
importación y requerimiento para reunir todas nuestras dependencias y ejecutar nuestras
pruebas.
import "zone.js/dist/zone";
import "zone.js/dist/long-stack-trace-zone";
import "zone.js/dist/jasmine-patch";
import "zone.js/dist/async-test";
import "zone.js/dist/fake-async-test";
import "zone.js/dist/sync-test";
import "zone.js/dist/proxy-zone";
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/of';
Error.stackTraceLimit = Infinity;
TestBed.initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting());
https://riptutorial.com/es/home 221
En esencia, estamos importando TestBed desde las pruebas de núcleo angular e iniciando el
entorno, ya que debe iniciarse solo una vez para todas nuestras pruebas. Luego, vamos a través
del directorio src / app recursivamente y leemos cada archivo que termina con .spec.js y los
alimentamos a testContext, por lo que se ejecutarán.
Usualmente trato de poner mis exámenes en el mismo lugar que la clase. A gusto personal, me
facilita importar dependencias y refactorizar pruebas con clases. Pero si desea poner sus pruebas
en otro lugar, como en el directorio src / test , por ejemplo, aquí tiene la oportunidad. cambia la
línea antes del último en el archivo karma.shim.js.
Perfecto. ¿lo que queda? ah, la tarea truculenta que usa el archivo karma.config.js que hicimos
anteriormente:
gulp.task("karmaTests",function(done){
var Server = require("karma").Server;
new Server({
configFile : "./karma.config.js",
singleRun: true,
autoWatch: false
}, function(result){
return result ? done(new Error(`Karma failed with error code ${result}`)):done();
}).start();
});
Ahora estoy iniciando el servidor con el archivo de configuración que creamos, diciéndole que se
ejecute una vez y que no observe los cambios. Considero que esto se adapta mejor a mí, ya que
las pruebas solo se ejecutarán si estoy listo para que se ejecuten, pero, por supuesto, si quieres
algo diferente, sabes dónde cambiar.
Y como ejemplo de código final, aquí hay un conjunto de pruebas para el tutorial de Angular 2,
"Tour of Heroes".
import {
TestBed,
ComponentFixture,
async
} from "@angular/core/testing";
beforeEach(()=> {
TestBed.configureTestingModule({
imports: [AppModule]
});
this.fixture = TestBed.createComponent(AppComponent);
this.fixture.detectChanges();
});
https://riptutorial.com/es/home 222
expect(this.fixture.componentInstance.title).toEqual("Tour of Heros");
});
}));
spyOn(cmp,"onSelect").and.callThrough();
this.fixture.nativeElement.querySelectorAll("ul.heroes li")[5].click();
https://riptutorial.com/es/home 223
expect(cmp.onSelect)
.toHaveBeenCalledWith(cmp.heroes[5]);
expect(cmp.selectedHero)
.toEqual(cmp.heroes[5], "click on hero should change hero");
})
));
});
Cabe destacar cómo tenemos antes que cada () configurar un módulo de prueba y crear el
componente en prueba, y cómo llamamos detectChanges () para que el ángulo pase por el
enlace doble y todo.
Tenga en cuenta que cada prueba es una llamada a async () y siempre espera a que la promesa
de WhenStable se resuelva antes de examinar el dispositivo. Luego tiene acceso al componente
a través de componentInstance y al elemento a través de nativeElement .
Hay una prueba que está comprobando el estilo correcto. como parte del Tutorial, el equipo de
Angular demuestra el uso de estilos dentro de los componentes. En nuestra prueba, usamos
getComputedStyle () para verificar que los estilos provienen de donde especificamos, sin
embargo, necesitamos el objeto Window para eso, y lo obtenemos del elemento como se puede
ver en la prueba.
Por lo general, los servicios llaman a Api remoto para recuperar / enviar datos. Pero las pruebas
unitarias no deberían hacer llamadas de red. Angular utiliza XHRBackend clase XHRBackend para
hacer solicitudes http. El usuario puede anular esto para cambiar el comportamiento. El módulo
de prueba angular proporciona las clases MockBackend y MockConnection que se pueden usar para
probar y afirmar las solicitudes http.
posts.service.ts Este servicio llega a un punto final de API para recuperar la lista de
publicaciones.
import 'rxjs/add/operator/map';
@Injectable()
export class PostsService {
posts: IPost[];
https://riptutorial.com/es/home 224
constructor(private http: Http) {
}
get(): Observable<IPost[]> {
return this.http.get(this.postsUri)
.map((response) => response.json());
}
}
describe('PostsService', () => {
// Mock http response
const mockResponse = [
{
'userId': 1,
'id': 1,
'title': 'sunt aut facere repellat provident occaecati excepturi optio
reprehenderit',
'body': 'quia et suscipit\nsuscipit recusandae consequuntur expedita et
cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet
architecto'
},
{
'userId': 1,
'id': 2,
'title': 'qui est esse',
'body': 'est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea
dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui
aperiam non debitis possimus qui neque nisi nulla'
},
{
'userId': 1,
'id': 3,
'title': 'ea molestias quasi exercitationem repellat qui ipsa sit aut',
'body': 'et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut
ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et
velit aut'
},
{
'userId': 1,
'id': 4,
'title': 'eum et est occaecati',
'body': 'ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda
https://riptutorial.com/es/home 225
provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt
voluptatem rerum illo velit'
}
];
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [
{
provide: XHRBackend,
// This provides mocked XHR backend
useClass: MockBackend
},
PostsService
]
});
});
expect(connection.request.url).toBe('http://jsonplaceholder.typicode.com/posts');
// Send mock response
connection.mockRespond(new Response(new ResponseOptions({
body: mockResponse
})));
});
postsService.get()
.subscribe((posts) => {
expect(posts).toBe(mockResponse);
});
})));
});
@Component({
selector: 'my-app',
template: '<h1>{{title}}</h1>'
})
export class MyAppComponent{
title = 'welcome';
}
Para la prueba angular, angular proporciona sus utilidades de prueba junto con el marco de
prueba que ayuda a escribir el buen caso de prueba en angular. Las utilidades angulares se
https://riptutorial.com/es/home 226
pueden importar desde @angular/core/testing
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
MyAppComponent
]
});
});
beforeEach(() => {
fixture = TestBed.createComponent(MyAppComponent);
comp = fixture.componentInstance;
});
expect(comp).toBeTruthy();
});
});
En el ejemplo anterior, solo hay un caso de prueba que explica el caso de prueba para la
existencia de componentes. En el ejemplo anterior, se utilizan utilidades de prueba angular como
TestBed y ComponentFixture .
TestBed se utiliza para crear el módulo de prueba angular y configuramos este módulo con el
método configureTestingModule para producir el entorno de módulo para la clase que queremos
probar. El módulo de prueba debe configurarse antes de la ejecución de cada caso de prueba,
por eso configuramos el módulo de prueba en la función beforeEach .
https://riptutorial.com/es/home 227
Capítulo 62: redux angular
Examples
BASIC
app.module.ts
app.store.ts
app.reducer.ts
tienda.ts
https://riptutorial.com/es/home 228
export interface IAppState {
example?: string;
}
acciones.ts
@Injectable()
export class exampleService {
constructor(@Inject(AppStore) private store: Redux.Store<AppState>) {}
getExampleState(){
console.log(this.store.getState().example);
}
}
cambian de estado
@Injectable()
export class exampleService {
constructor(@Inject(AppStore) private store: Redux.Store<AppState>) {}
setExampleState(){
this.store.dispatch(updateExample("new value"));
}
}
acciones.ts
https://riptutorial.com/es/home 229
example?: string;
}
app.store.ts
https://riptutorial.com/es/home 230
Capítulo 63: Servicio EventEmitter
Examples
Resumen de la clase
Componente de clase
@Component({
selector: 'zippy',
template: `
<div class="zippy">
<div (click)="toggle()">Toggle</div>
<div [hidden]="!visible">
<ng-content></ng-content>
</div>
</div>`})
export class Zippy {
visible: boolean = true;
@Output() open: EventEmitter<any> = new EventEmitter();
@Output() close: EventEmitter<any> = new EventEmitter();
toggle() {
this.visible = !this.visible;
if (this.visible) {
this.open.emit(null);
} else {
this.close.emit(null);
}
}
}
Eventos emisores
Atrapando el evento
Crear un servicio-
https://riptutorial.com/es/home 231
}
getNavChangeEmitter() {
return this.navchange;
}
}
@Component({
selector: 'obs-comp',
template: `obs component, item: {{item}}`
})
export class ObservingComponent {
item: number = 0;
subscription: any;
constructor(private navService:NavService) {}
ngOnInit() {
this.subscription = this.navService.getNavChangeEmitter()
.subscribe(item => this.selectedNavItem(item));
}
selectedNavItem(item: number) {
this.item = item;
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
@Component({
selector: 'my-nav',
template:`
<div class="nav-item" (click)="selectedNavItem(1)">nav 1 (click me)</div>
<div class="nav-item" (click)="selectedNavItem(2)">nav 2 (click me)</div>
`,
})
export class Navigation {
item = 1;
constructor(private navService:NavService) {}
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this.navService.emitNavChangeEvent(item);
}
}
Ejemplo vivo
https://riptutorial.com/es/home 232
Capítulo 64: Sujetos y observables angulares
RXJS con solicitudes API
Observaciones
Hacer solicitudes de API con el servicio Angular 2 Http y RxJS es muy similar a trabajar con
promesas en Angular 1.x.
Usa la clase Http para hacer peticiones. La clase Http expone los métodos para emitir solicitudes
HTTP GET , POST , PUT , DELETE , PATCH , HEAD a través de los métodos correspondientes. También
expone un método de request genérico para emitir cualquier tipo de solicitud HTTP.
Todos los métodos de la clase Http devuelven un Observable<Response> , al que puede aplicar
operaciones RxJS . Se llama al método .subscribe() y se pasa una función a la que se llamará
cuando se devuelvan datos en el flujo observable.
El flujo observable para una solicitud contiene solo un valor: la Response , y se completa / resuelve
cuando la solicitud HTTP se completa con éxito, o errores / fallas si se produce un error.
Tenga en cuenta que los observables devueltos por el módulo Http son fríos , lo que significa que
si se suscribe al observable varias veces, la solicitud de origen se ejecutará una vez por cada
suscripción. Esto puede suceder si desea consumir el resultado en varios componentes de su
aplicación. Para solicitudes GET, esto podría causar algunas solicitudes adicionales, pero esto
puede crear resultados inesperados si se suscribe más de una vez a las solicitudes PUT o POST.
Examples
Solicitud basica
El siguiente ejemplo muestra una solicitud HTTP GET simple. http.get() devuelve un Observable
que tiene el método subscribe . Este anexa los datos devueltos a la matriz de posts .
var posts = []
getPosts(http: Http):void {
this.http.get(`https://jsonplaceholder.typicode.com/posts`)
.map(response => response.json())
.subscribe(post => posts.push(post));
}
Puede ser una buena idea encapsular la lógica de manejo de HTTP en su propia clase. La
siguiente clase expone un método para obtener publicaciones. Llama al método http.get() y
llama a .map en el Observable devuelto para convertir el objeto Response en un objeto Post .
https://riptutorial.com/es/home 233
import {Injectable} from "@angular/core";
import {Http, Response} from "@angular/http";
@Injectable()
export class BlogApi {
El ejemplo anterior utiliza una clase de Post para contener los datos devueltos, que podrían tener
el siguiente aspecto:
constructor(src: any) {
this.userId = src && src.userId;
this.id = src && src.id;
this.title = src && src.title;
this.body = src && src.body;
}
}
Un componente puede ahora utilizar el BlogApi clase para recuperar fácilmente Post de datos sin
preocuparse de los trabajos de la Http clase.
Un escenario común es esperar a que finalicen varias solicitudes antes de continuar. Esto se
puede lograr utilizando el método forkJoin .
En el siguiente ejemplo, forkJoin se usa para llamar a dos métodos que devuelven Observables .
La devolución de llamada especificada en el método .subscribe se llamará cuando ambos
Observables se hayan completado. Los parámetros proporcionados por .subscribe coinciden con
el orden dado en la llamada a .forkJoin . En este caso, primero posts luego tags .
loadData() : void {
Observable.forkJoin(
this.blogApi.getPosts(),
this.blogApi.getTags()
).subscribe((([posts, tags]: [Post[], Tag[]]) => {
this.posts = posts;
this.tags = tags;
https://riptutorial.com/es/home 234
}));
}
https://riptutorial.com/es/home 235
Capítulo 65: Título de la página
Introducción
¿Cómo se puede cambiar el título de la página?
Sintaxis
• setTitle(newTitle: string): void;
• getTitle(): string;
Examples
cambiando el título de la página
https://riptutorial.com/es/home 236
Capítulo 66: Trabajador del servicio
Introducción
Veremos cómo configurar un servicio que funciona en angular, para permitir que nuestra
aplicación web tenga capacidades fuera de línea.
Un trabajador del servicio es un script especial que se ejecuta en segundo plano en el navegador
y administra las solicitudes de red a un origen determinado. Se instala originalmente por una
aplicación y permanece residente en la máquina / dispositivo del usuario. El navegador lo activa
cuando se carga una página desde su origen y tiene la opción de responder a las solicitudes
HTTP durante la carga de la página.
Examples
Añadir Service Worker a nuestra aplicación
Así que para empezar, podemos crear un proyecto normal con cli angular.
ng new serviceWorking-example
cd serviceWorking-example
Ahora lo importante, para decir a Cli angular que queremos usar el trabajador de servicio que
tenemos que hacer:
https://riptutorial.com/es/home 237
Y compruebe dist / carpeta.
• worker-basic.min.js
• sw-register.HASH.bundle.js
• ngsw-manifest.json
Además, index.html ahora incluye esta secuencia de comandos sw-register, que registra un
Trabajador de Servicio Angular (ASW) para nosotros.
Ahora nuestra aplicación debería cargarse más rápido y deberíamos poder usar la aplicación sin
conexión.
Ahora, si habilita el modo sin conexión en la consola Chrome, debería ver que nuestra aplicación
en http: // localhost: 4200 / index.html funciona sin conexión a Internet.
Pero en http: // localhost: 4200 / tenemos un problema y no se carga, esto se debe a que el caché
de contenido estático solo sirve para los archivos listados en el manifiesto.
Por ejemplo, si el manifiesto declara una URL de /index.html, las solicitudes a /index.html serán
respondidas por el caché, pero una solicitud a / o / some / route irá a la red.
https://riptutorial.com/es/home 238
enrutamiento del manifiesto y redirige las rutas configuradas a una ruta de índice específica.
{
"routing": {
"routes": {
"/": {
"prefix": false
}
},
"index": "/index.html"
}
}
Y construimos de nuevo nuestra aplicación, ahora cuando vamos a http: // localhost: 4200 / ,
deberíamos ser redirigidos a http: // localhost: 4200 / index.html .
https://developers.google.com/web/fundamentals/getting-started/primers/service-workers
https://docs.google.com/document/d/19S5ozevWighny788nI99worpcIMDnwWVmaJDGf_RoDY/edit#
Y aquí puede ver una forma alternativa de implementar el servicio trabajando con la biblioteca de
precache SW:
https://coryrylan.com/blog/fast-offline-angular-apps-with-service-workers
https://riptutorial.com/es/home 239
Capítulo 67: Tubería
Introducción
El tubo | el carácter se utiliza para aplicar tuberías en Angular 2. Las tuberías son muy similares a
los filtros en AngularJS, ya que ambas ayudan a transformar los datos en un formato específico.
Parámetros
Función /
Explicación
Parámetro
transformar
La función que se llama a transformar los valores en la plantilla.
(valor, args []?)
Observaciones
Este tema trata sobre Angular2 Pipes , un mecanismo para transformar y formatear datos dentro
de plantillas HTML en una aplicación Angular2.
Examples
Tuberías de encadenamiento
Tubos personalizados
https://riptutorial.com/es/home 240
my.pipe.ts
@Pipe({name: 'myPipe'})
export class MyPipe implements PipeTransform {
my.component.ts
@Component({
selector: 'my-component',
template: `{{ value | myPipe }}`
})
export class MyComponent {
public value:any;
my.module.ts
@NgModule({
imports: [
BrowserModule,
],
declarations: [
MyComponent,
MyPipe
],
})
export class MyModule { }
Tubos incorporados
https://riptutorial.com/es/home 241
Tubo Uso Ejemplo
Ejemplo
hotel-booking.component.ts
@Component({
moduleId: module.id,
selector: 'hotel-reservation',
templateUrl: './hotel-reservation.template.html'
})
export class HotelReservationComponent {
public fName: string = 'Joe';
public lName: string = 'SCHMO';
public reservationMade: string = '2016-06-22T07:18-08:00'
public reservationFor: string = '2025-11-14';
public cost: number = 99.99;
}
hotel-reservation.template.html
<div>
<h1>Welcome back {{fName | uppercase}} {{lName | lowercase}}</h1>
<p>
On {reservationMade | date} at {reservationMade | date:'shortTime'} you
reserved room 205 for {reservationDate | date} for a total cost of
{cost | currency}.
</p>
</div>
Salida
https://riptutorial.com/es/home 242
Código
@Component({
selector: 'json-example',
template: `<div>
<p>Without JSON pipe:</p>
<pre>{{object}}</pre>
<p>With JSON pipe:</p>
<pre>{{object | json}}</pre>
</div>`
})
export class JsonPipeExample {
object: Object = {foo: 'bar', baz: 'qux', nested: {xyz: 3, numbers: [1, 2, 3, 4, 5]}};
}
Salida
Para hacer que una tubería personalizada esté disponible en toda la aplicación, Durante la
aplicación bootstrap, extienda PLATFORM_PIPES.
bootstrap(AppComponent, [
provide(PLATFORM_PIPES, {
useValue: [
MyPipe
],
multi: true
})
]);
app / pipes.pipe.ts
@Pipe({name: 'truthy'})
export class Truthy implements PipeTransform {
https://riptutorial.com/es/home 243
transform(value: any, truthy: string, falsey: string): any {
if (typeof value === 'boolean'){return value ? truthy : falsey;}
else return value
}
}
app / my-component.component.ts
@Component({
selector: 'my-component',
template: `
<p>{{value | truthy:'enabled':'disabled' }}</p>
`,
pipes: [Truthy]
})
export class MyComponent{ }
@Component({
selector: 'async-stuff',
template: `
<h1>Hello, {{ name | async }}</h1>
Your Friends are:
<ul>
<li *ngFor="let friend of friends | async">
{{friend}}
</li>
</ul>
`
})
class AsyncStuffComponent {
name = Promise.resolve('Misko');
friends = Observable.of(['Igor']);
}
Se convierte en
<h1>Hello, Misko</h1>
Your Friends are:
<ul>
<li>
Igor
</li>
</ul>
https://riptutorial.com/es/home 244
import { DatePipe } from '@angular/common'
@Pipe({name: 'ifDate'})
export class IfDate implements PipeTransform {
private datePipe: DatePipe = new DatePipe();
Tubos de estado
Angular 2 ofrece dos tipos diferentes de tuberías: sin estado y con estado. Las tuberías son sin
estado por defecto. Sin embargo, podemos implementar tuberías con estado estableciendo la
propiedad pure en false . Como puede ver en la sección de parámetros, puede especificar un name
y declarar si la tubería debe ser pura o no, es decir, sin estado o sin estado. Mientras que los
datos fluyen a través de una tubería sin estado (que es una función pura) que no recuerda nada,
los datos pueden ser gestionados y recordados por tuberías con estado. Un buen ejemplo de una
tubería con estado es el AsyncPipe proporcionado por Angular 2.
Importante
Observe que la mayoría de las tuberías deben caer en la categoría de tuberías sin estado. Esto
es importante por razones de rendimiento, ya que Angular puede optimizar tuberías sin estado
para el detector de cambios. Así que use las tuberías con estado con cautela. En general, la
optimización de tuberías en Angular 2 tiene una mayor mejora de rendimiento sobre los filtros en
Angular 1.x. En Angular 1, el ciclo de resumen siempre tuvo que volver a ejecutar todos los filtros
aunque los datos no hayan cambiado en absoluto. En Angular 2, una vez que se ha calculado el
valor de una tubería, el detector de cambios sabe que no debe volver a ejecutar esta tubería a
menos que cambie la entrada.
@Pipe({
name: 'countdown',
pure: false
})
export class CountdownPipe implements PipeTransform, OnDestroy {
private interval: any;
private remainingTime: number;
https://riptutorial.com/es/home 245
if (typeof this.remainingTime !== 'number') {
this.remainingTime = parseInt(value, 10);
}
if (!this.interval) {
this.interval = setInterval(() => {
this.remainingTime--;
if (this.remainingTime <= 0) {
this.remainingTime = 0;
clearInterval(this.interval);
delete this.interval;
}
}, interval);
}
return this.remainingTime;
}
ngOnDestroy(): void {
if (this.interval) {
clearInterval(this.interval);
}
}
}
{{ 1000 | countdown:50 }}
{{ 300 | countdown }}
Es importante que su tubería también implemente la interfaz OnDestroy para que pueda limpiar una
vez que se destruya su tubería. En el ejemplo anterior, es necesario borrar el intervalo para evitar
pérdidas de memoria.
Tubo dinámico
Escenario de caso de uso: una vista de tabla consta de diferentes columnas con diferentes
formatos de datos que deben transformarse con diferentes canalizaciones.
table.component.ts
...
import { DYNAMIC_PIPES } from '../pipes/dynamic.pipe.ts';
@Component({
...
pipes: [DYNAMIC_PIPES]
})
export class TableComponent {
...
https://riptutorial.com/es/home 246
table.rows = [
[ 1, 'Home', 'home', '2016-08-27T17:48:32', true ],
[ 2, 'About Us', 'about', '2016-08-28T08:42:09', true ],
[ 4, 'Contact Us', 'contact', '2016-08-28T13:28:18', false ],
...
]
...
dynamic.pipe.ts
import {
Pipe,
PipeTransform
} from '@angular/core';
// Library used to humanize a date in this example
import * as moment from 'moment';
@Pipe({name: 'dynamic'})
export class DynamicPipe implements PipeTransform {
transform(value:string, modifier:string) {
if (!modifier) return value;
// Evaluate pipe string
return eval('this.' + modifier + '(\'' + value + '\')')
}
// Returns a human friendly time format e.g: '14 minutes ago', 'yesterday'
humanizeDate(value:string):string {
// Humanize if date difference is within a week from now else returns 'December 20,
2016' format
if (moment().diff(moment(value), 'days') < 8) return moment(value).fromNow();
return moment(value).format('MMMM Do YYYY');
}
}
table.component.html
<table>
<thead>
<td *ngFor="let head of data.header">{{ head }}</td>
</thead>
<tr *ngFor="let row of table.rows; let i = index">
<td *ngFor="let column of row">{{ column | dynamic:table.pipes[i] }}</td>
</tr>
https://riptutorial.com/es/home 247
</table>
Resultado
Probando un tubo
describe('ReversePipe', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [ReversePipe],
});
});
https://riptutorial.com/es/home 248
Capítulo 68: Usa componentes web nativos
en Angular 2
Observaciones
Cuando utiliza un componente web en su plantilla de Angular 2, angular intentará encontrar un
componente con un selector que coincida con la etiqueta personalizada del componente web, que
por supuesto no puede y producirá un error.
Examples
Incluye esquema de elementos personalizados en tu módulo
@NgModule({
imports: [ CommonModule ],
declarations: [ AboutComponent ],
exports: [ AboutComponent ],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
@Component({
selector: 'myapp-about',
template: `<my-webcomponent></my-webcomponent>`
})
export class AboutComponent { }
https://riptutorial.com/es/home 249
Capítulo 69: Usando bibliotecas de terceros
como jQuery en Angular 2
Introducción
Al crear aplicaciones utilizando Angular 2.x, hay ocasiones en las que es necesario utilizar
bibliotecas de terceros como jQuery, Google Analytics, API de JavaScript de integración de chat y
etc.
Examples
Configuración mediante angular-cli
NPM
Si se instala una biblioteca externa como jQuery usando NPM
"scripts": [
"../node_modules/jquery/dist/jquery.js"
]
Carpeta de activos
También puede guardar el archivo de biblioteca en su directorio de assets/js e incluirlo en
angular-cli.json
"scripts": [
"assets/js/jquery.js"
]
Nota
Guarde su biblioteca principal jquery y sus dependencias, como jquery-cycle-plugin en el
directorio activos y añadir a ambos en angular-cli.json , asegúrese de que se mantiene el orden
de las dependencias.
Para usar jquery en sus componentes de Angular 2.x, declare una variable global en la parte
superior
https://riptutorial.com/es/home 250
Si usa $ para jQuery
https://riptutorial.com/es/home 251
Capítulo 70: Zone.js
Examples
Obtener referencia a NgZone
my.component.ts
@Component({...})
export class Mycomponent implements NgOnInit {
constructor(private _ngZone: NgZone) { }
ngOnInit() {
this._ngZone.runOutsideAngular(() => {
// Do something outside Angular so it won't get noticed
});
}
}
Uso de NgZone para realizar múltiples solicitudes HTTP antes de mostrar los
datos
runOutsideAngular se puede usar para ejecutar código fuera de Angular 2 para que no active la
detección de cambios innecesariamente. Esto se puede usar para, por ejemplo, ejecutar varias
solicitudes HTTP para obtener todos los datos antes de representarlos. Para ejecutar código de
nuevo en el interior angular 2, run el método de NgZone se puede utilizar.
my.component.ts
@Component({...})
export class Mycomponent implements OnInit {
private data: any[];
constructor(private http: Http, private _ngZone: NgZone) { }
ngOnInit() {
this._ngZone.runOutsideAngular(() => {
this.http.get('resource1').subscribe((data1:any) => {
// First response came back, so its data can be used in consecutive request
this.http.get(`resource2?id=${data1['id']}`).subscribe((data2:any) => {
this.http.get(`resource3?id1=${data1['id']}&id2=${data2}`).subscribe((data3:any) =>
{
this._ngZone.run(() => {
this.data = [data1, data2, data3];
});
});
});
});
https://riptutorial.com/es/home 252
});
}
}
https://riptutorial.com/es/home 253
Creditos
S.
Capítulos Contributors
No
Agregue componentes
amansoni211, daniellmb, Günter Zöchbauer,
3 dinámicamente usando
jupiter24, Khaled
ViewContainerRef.createComponent
https://riptutorial.com/es/home 254
Angular2 proporciona datos
13 externos a la aplicación antes de Ajey
bootstrap
Angular2 Validaciones
15 Arnold Wiersma, Norsk, Yoav Schniederman
personalizadas
18 Barril TechJhola
24 Componentes BrunoLM
Configuración de la aplicación
25 ASP.net Core para trabajar con Oleksii Aza, Sam
Angular 2 y TypeScript
Depuración de la aplicación
30 mecanografiada Angular2 utilizando PSabuwala
código de Visual Studio
Detectar eventos de
31 Eric Jimenez
redimensionamiento
https://riptutorial.com/es/home 255
BrunoLM, daniellmb, Everettss, lexith, Stian
Standahl, theblindprophet
Ejemplos de componentes
39 borislemke, smnbbrv
avanzados
https://riptutorial.com/es/home 256
Servicios. Matrim, Roope Hakulinen, Syam Pradeep,
theblindprophet
51 Módulos BrunoLM
53 ngrx Maxime
Optimización de la representación
55 daniellmb, Eric Jimenez, Everettss
mediante ChangeDetectionStrategy
https://riptutorial.com/es/home 257
Angular 2
https://riptutorial.com/es/home 258