Angular
¿Qué es Angular?
Framework JS
UI reactivas
SPA: Single Page Applications
Data binding
Web components
TypeScript
Código fuente y código compilado
¿Angular 2? ¿4? ¿11? ¿AngularJS?
Microservicios / Jamstack
Entorno de desarrollo
Editor: Visual Studio Code
Configurar:
Format on Paste y Format on Save
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
Node.js y npm
Comandos básicos
Clonar un repositorio:
git clone URL
Descargar última versión del repositorio:
git pull origin master
Configuración proxy
git config --global http.proxy http://username:password@host:port
git config --global https.proxy http://username:password@host:port
npm
Instalar última versión después de instalar Node.js
(configurar proxy si es necesario): npm install -g npm
Repositorio de paquetes distribuibles
Paquetes globales y paquetes locales
La carpeta node_modules
El archivo package.json:
Registro de dependencias
Dependencias de desarrollo y de producción
Comandos npm
Instalar un paquete globalmente:
npm install -g paquete
Instalar un paquete de producción:
npm install paquete
Instalar un paquete de desarrollo:
npm install paquete --save-dev
Instalar todas las dependencias:
npm install
Instalar las dependencias de producción:
npm install --production
Listar paquetes instalados:
npm list --depth=0 (locales)Comandos npm
Lanzar el ejecutable de un paquete:
npx ejecutable
angular-cli
Instalación global:
npm install -g @angular/cli
Configuración proxy
npm config set proxy http://username:password@host:port
npm config set https-proxy http://username:password@host:port
JavaScript
Interpretado, compilado y ejecutado en el navegador
Cada navegador programa su propio motor de JS
Estandarización: ECMAScript
La versión ES6 o ES2015
Transpiladores: Babel, TypeScript
Organización del código JavaScript: módulos
Module loaders: ellos gestionan las dependencias y cargan los módulos (RequireJS, SystemJS)
Organización del código JavaScript: módulos
Module bundlers: además de lo anterior, generan un solo código encadenado y minificado (webpack, Parcel)
Organización del código JavaScript: módulos
Compatibilidad de los módulos ES6 en navegadores
¡Webpack!
Usaremos la sintaxis ES6
TS -> ES5 -> webpack -> bundle -> browser =
Angular CLI
ES6
let y const
let a = 3;
let a = 10; // Error
var a = 12; // Error
const b = 10;
b = 3; // Error
const obj = {
x: 10,
y: 12
}
obj.x = 15; // OK
obj = { // Error
x: 15,
y: 12
}
ES6
let y const
Template literals
let nombre = "Antonio";
let cuadrado = function(x) {
return x * x;
}
let n = Math.floor(Math.random() * 10);
let saludo1 = "Hola, " + nombre + ". El cuadrado de " + n + " es " + cuadrado(n) + ".";
let saludo2 = `Hola, ${nombre}. El cuadrado de ${n} es ${cuadrado(n)}.`;
ES6
let y const
Template literals
for ... of
let nombres = ["Patricia", "Zacarías", "Miguel", "Maite"];
for (let i in nombres) {
console.log(nombres[i]);
}
for (let nombre of nombres) {
console.log(nombre);
}
let obj = {
x: 3,
y: 4
}
for (let i in obj) {
console.log(obj[i]);
}
let nombre = "Antonio Jesús";
for (let c of nombre) {
console.log(c);
}
ES6
let y const
Template literals
for ... of
Funciones
Parámetros por defecto
function potencia(x, y = 2) {
return Math.pow(x, y);
}
console.log(`10 elevado a 8 es ${potencia(10, 8)}`);
console.log(`El cuadrado de 5 es ${potencia(5)}`);
ES6
let y const
Template literals
for ... of
Funciones
Parámetros por defecto
Función arrow:
(parámetros) => expresión_devuelta;const potencia = function (x, y = 2) {
return Math.pow(x, y);
}
const potencia = (x, y = 2) => Math.pow(x, y);
setTimeout(() => console.log("pausa"), 2000);
ES6
let y const
Template literals
for ... of
Funciones
Parámetros por defecto
Función arrow:
(parámetros) => expresión_devuelta;ES6
Operador spread
Meter un array dentro de otro
Número variable de argumentos en una función
Pasar varios valores a una función
Copiar un array en otro
Copiar un objeto en otro
Mergear objeto con defaults
// function(a, b, c)
function sumar(a, b, c) {
console.log(a + b + c);
}
let nums = [1, 3, 6];
sumar(...nums);
// function(n parámetros)
function sumar(...nums) {
let suma = 0;
for (n of nums) {
suma += n;
}
console.log("La suma es " + suma);
}
let a = 3;
let b = 7;
let c = 8;
sumar(a, b, c);
// push y unshift
let nums1 = [1, 3, 6];
let nums2 = [0, 52, 15, 9];
nums1.push(...nums2);
console.log(nums1);
nums1.unshift(...nums2);
console.log(nums1);
// meter un array en medio de otro
let nums1 = [1, 3, 6];
let nums2 = [0, 52, 15, 9];
nums1.splice(1, 0, ...nums2);
console.log(nums1);
// copiar un array
let nums1 = [1, 3, 6];
let nums2 = [...nums1];
// copiar un objeto
let o1 = {
x: 3,
y: 5
}
let o2 = { ...o1 };
// mergear un objeto con defaults (ES2018)
let defaults = {
ancho: 100,
alto: 200,
color: "rojo"
}
let o1 = {
ancho: 200,
grosor: 10000
}
o1 = { ...defaults, ...o1 };
Arrays
Métodos:
map
let nombres = ["juan", "luisa", "amparo", "arturo"];
let nombresMays = nombres.map(nombre => nombre.toUpperCase());
console.log(nombresMays);
Arrays
Métodos:
map
filter
let personas = [
{
nombre: "juan",
edad: 15
},
{
nombre: "luisa",
edad: 35
},
{
nombre: "amparo",
edad: 17
},
{
nombre: "arturo",
edad: 32
}
];
let mayoresEdad = personas.filter(persona => persona.edad >= 18);
console.log(mayoresEdad);
Arrays
Métodos:
map
filter
reduce
let nums = [2, 4, 10, 15, 12];
let suma = nums.reduce((x, y) => x + y);
let objs = [
{
x: 3,
y: 2
},
{
x: 8,
y: 10
},
{
x: 10,
y: 15
}
]
let sumaX = objs.reduce((acc, obj) => acc + obj.x, 0); // Método 1
let sumaX = objs.map(obj => obj.x).reduce((obj1, obj2) => obj1 + obj2); // Método 2
Arrays
Métodos:
map
filter
reduce
find
let notas = [
{
nombre: "juan",
nota: 6
},
{
nombre: "luisa",
nota: 8
},
{
nombre: "amparo",
nota: 4
},
{
nombre: "arturo",
nota: 3
}
];
let notaArturo = notas.find(n => n.nombre === "arturo");
Arrays
Métodos:
map
filter
reduce
find
Encadenamiento
let notas = [
{
nombre: "juan",
nota: 6
},
{
nombre: "luisa",
nota: 8
},
{
nombre: "amparo",
nota: 4
},
{
nombre: "arturo",
nota: 3
}
];
let notasAprobados = notas.filter(n => n.nota >= 5).map(n => n.nota);
console.log(notasAprobados);
Arrays
El operador spread
Destructuring
Asignar desde un array
Intercambiar variables
function medidasMueble() {
// ...
return [100, 70, 20];
}
let [ancho, alto, profundo] = medidasMueble();
console.log(ancho, alto, profundo);
// 100, 70, 20
let a = 10;
let b = 20;
[a, b] = [b, a];
console.log(a, b);
// 20, 10
Objetos
El operador spread
Destructuring
Asignar desde un objeto
Renombrar variables
Valores por defecto
Argumentos en las funciones
function getRGB(colorHex) {
// ...
return {
alias: 'deeppink',
red: 255,
green: 20,
blue: 147,
alpha: 0.8
}
}
let { red, green, blue } = getRGB("#ff1493");
console.log(red, green, blue);
// 255, 20, 147
let personas = [{
nombre: "Luis",
apellido: "Herrera",
edad: 23
},
{
nombre: "Marta",
apellido: "Nieto",
edad: 29
}];
for (let {nombre, edad} of personas) {
console.log(`Me llamo ${nombre} y tengo ${edad} años`);
}
// Me llamo Luis y tengo 23 años
// Me llamo Marta y tengo 29 años
let notas = {
mat: 8,
fis: 6,
dib: 5,
tec: 6
}
let { mat: matematicas, fis: fisica, dib: dibujo, tec: tecnologia } = notas;
console.log(matematicas, fisica, dibujo, tecnologia);
// 8, 6, 5, 6
let persona = {
nombre: "Luis",
edad: 23
}
let { nombre, edad, estado = "soltero" } = persona;
console.log(nombre, edad, estado);
// Luis, 23, soltero
function area({radio = 0, base = 0, altura = 0, tipo = 'circulo'} = {}) {
console.log(radio, base, altura, tipo);
}
area({ tipo: 'rectangulo', base: 10, altura: 20 });
// 0, 10, 20, "rectangulo"
area();
// 0, 0, 0, "circulo"
ES6
Clases
Propiedades y métodos
class A {
constructor(z) {
this.x = 3;
this.y = 10;
this.z = z;
}
suma() {
return this.x + this.y + this.z;
}
}
let a = new A(20);
console.log(a.suma());
class A {
x = 3;
y = 10;
z;
constructor(z) {
this.z = z;
}
suma() {
return this.x + this.y + this.z;
}
}
let a = new A(20);
console.log(a.suma());
ES6
Clases
Propiedades y métodos
Getters y setters
class A {
constructor(z) {
this.x = 3;
this.y = 10;
this.z = z;
}
suma() {
return this.x + this.y + this.z;
}
set zeta(z) {
this.z = z * 2;
}
get zeta() {
return this.z / 2;
}
}
let a = new A(20);
a.zeta = 15;
console.log(a.zeta);
ES6
Clases
Propiedades y métodos
Getters y setters
Métodos estáticos
class A {
constructor(z) {
this.x = 3;
this.y = 10;
this.z = z;
}
static getPI() {
return 3.14159;
}
suma() {
return this.x + this.y + this.z;
}
set zeta(z) {
this.z = z * 2;
}
get zeta() {
return this.z / 2;
}
}
let a = new A(20);
a.zeta = 15;
console.log(a.zeta);
console.log(A.getPI());
ES6
Clases
Propiedades y métodos
Getters y setters
Métodos estáticos
Herencia con extends y super()
class A {
constructor(z) {
this.x = 3;
this.y = 10;
this.z = z;
}
static getPI() {
return 3.14159;
}
suma() {
return this.x + this.y + this.z;
}
set zeta(z) {
this.z = z * 2;
}
get zeta() {
return this.z / 2;
}
}
class B extends A {
constructor() {
super(100);
this.x = 20;
}
suma() {
return this.x + this.z;
}
resta() {
return this.x - this.z;
}
}
let b = new B();
console.log(b.suma());
console.log(b.resta());
Timers
setTimeout(callback, delay);
setInterval(callback, delay);
clearTimeout(timer);
clearInterval(timer);
ES6
Módulos
import
import { literal } from 'ruta_modulo';ES6
Módulos
import dinámicos
import('ruta_modulo').then(
modulo => ...
);
TypeScript
Superconjunto de JavaScript
Transpila a ES5 (o a otra versión)
TypeScript
Superconjunto de JavaScript
Transpila a ES5 (o a otra versión)
Tipado
Errores en tiempo de compilación
TypeScript
Superconjunto de JavaScript
Transpila a ES5 (o a otra versión)
Tipado
Errores en tiempo de compilación
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"sourceMap": true,
"outDir": "./public/js/",
}
}
tsconfig.json
TypeScript - Tipos
Tipos básicos:
number
string
boolean
Array
any
void
let peso: number;
peso = 89.5;
let saludo: string;
saludo = 'Vais a petarlo con TypeScript';
let esVerano: boolean;
esVerano = false;
let nums: Array<number>;
nums = [10, 55, -3, 4.14];
let nombres: string[];
nombres = ['Juan', 'Paqui', 'Lorenzo', 'Alicia'];
let cosas: any[];
cosas = [10, 'Teruel', -5, true, [0, -10, 15], false];
function imprimeSaludo(s: string): void {
console.log(s);
}
imprimeSaludo('Buenas tardes');
TypeScript - Tipos
Tipos básicos:
number
string
boolean
Array
any
void
Enum
enum FormasPago {
TPV,
PayPal,
transferencia
}
let pago: FormasPago;
pago = FormasPago.PayPal;
procesarPago(pago);
function procesarPago(formaPago: FormasPago): void {
switch (formaPago) {
case FormasPago.TPV:
// ...
break;
case FormasPago.PayPal:
// ...
break;
case FormasPago.transferencia:
// ...
break;
}
}
TypeScript - Tipos
Tipos básicos:
number
string
boolean
Array
any
void
Enum
Union types
let numeros: Array<number | string>;
numeros = ['3', 6, '15.8', 0];
function procesar(a: string | number): void {
if (typeof a === 'string') {
console.log(a.toUpperCase());
} else {
console.log(a.toFixed(2));
}
}
TypeScript - Tipos
Tipos básicos:
number
string
boolean
Array
any
void
Enum
Union types
Genéricos
function verDoble<T>(elem: T): T[] {
let elemDoble: T[] = [elem, elem];
return elemDoble;
}
TypeScript - Tipos
Tipos básicos:
number
string
boolean
Array
any
void
Enum
Union types
Genéricos
Type assertion
const inputText = document.getElementById("nombre") as HTMLInputElement;
inputText.select();
TypeScript - Tipos
Tipos básicos:
number
string
boolean
Array
any
void
Enum
Union types
Genéricos
Type assertion
Alias
type Posicion = 1 | 2 | 3;
let p: Posicion;
p = 3; // OK
p = 5; // Error
TypeScript - Funciones
Sin flexibilidad en el número de parámetros
function sumar(a: number, b: number): number {
return a + b;
}
sumar(); // Error
sumar(3); // Error
sumar(10, 2); // OK
sumar(4, -3, 10, 8) // Error
TypeScript - Funciones
Sin flexibilidad en el número de parámetros
Parámetros opcionales
function sumar(a: number, b: number, c?: number): number {
if (c) {
return a + b + c;
} else {
return a + b;
}
}
sumar(10, 2);
sumar(10, 2, 15);
TypeScript - Funciones
Sin flexibilidad en el número de parámetros
Parámetros opcionales
Sobrecarga
function nChars(a: number): string;
function nChars(a: string): number;
function nChars(a: string | number): number | string {
if (typeof a === 'number') {
return '¡Es un número!';
} else if (typeof a === 'string') {
return a.length;
}
}
type RGB = [number, number, number];
function convierteColor(color: string): RGB;
function convierteColor(color: RGB): string;
function convierteColor(color: string | RGB): string | RGB {
if (typeof color === 'string') {
return [0, 128, 0];
} else {
return '#006600';
}
}
const colorRGB = convierteColor('#006600');
const colorHEX = convierteColor([0, 128, 0]);
TypeScript - Funciones
Sin flexibilidad en el número de parámetros
Parámetros opcionales
Sobrecarga
Function types
function transformaNumero(x: number, callback: (n: number) => void) {
callback(x);
}
let a = 10;
transformaNumero(a, m => console.log(m * 2));
TypeScript - Módulos
import { literal } from 'ruta_modulo';
import literal from 'ruta_modulo';TypeScript - Módulos
Módulos
import dinámicos
import('ruta_modulo').then(
modulo => ...
);
TypeScript - Módulos
TypeScript - Clases
class Factura {
numero: string;
base: number;
tipoIva: number;
constructor(numero: string, base: number, tipoIva: number = 21) {
this.numero = numero;
this.base = base;
this.tipoIva = tipoIva;
}
}
TypeScript - Clases
class Factura {
private static caracteresSerie = 2;
public num: string;
public serie: string;
public base: number;
private readonly intTipoIva: number;
constructor(base: number, tipoIva: number = 21) {
this.base = base;
this.intTipoIva = tipoIva;
}
get numero(): string {
return this.serie + this.num;
}
set numero(n: string) {
this.serie = n.slice(0, Factura.caracteresSerie - 1);
this.num = n.slice(Factura.caracteresSerie);
}
}
let f = new Factura(100);
f.numero = 'AB600';
console.log(f.numero);
TypeScript - Clases
abstract class Vehiculo {
public manual: boolean;
constructor(public ruedas: number, public motor: Motor) {
this.manual = this.motor === Motor.ninguno;
}
public abstract arrancar(): void;
}
class Bici extends Vehiculo {
public arrancar(): void {
console.log('Me pongo de pie y pedaleo');
}
}
TypeScript - Clases
interface Arrancable {
arrancar(): void;
apagar(): void;
}
class Vehiculo {
public manual: boolean;
constructor(public ruedas: number, public motor: Motor) {
this.manual = this.motor === Motor.ninguno;
}
}
class Bici extends Vehiculo implements Arrancable {
public arrancar(): void {
console.log('Me pongo de pie y pedaleo');
}
public apagar(): void {
console.log('Me bajo de la bici');
}
}
interface Cliente {
id: number;
login: string;
nombre: string;
tipo: TiposCliente;
fechaAlta: Date;
}
function getClientes(): Cliente[] {
let clientes: Cliente[] = conectaBD('clientes');
return clientes;
}
TypeScript - Decoradores
@
Asignar metadatos
Muy utilizados en Angular
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-factura',
templateUrl: './factura.component.html',
styleUrls: ['./factura.component.css']
})
export class FacturaComponent {
@Input()
facturaId: number;
}
Primeros pasos
Primeros pasos
Generar la app:
ng new <nombre-app> --prefix <prefijo> --skip-tests
El comando crea un nuevo directorio y lanza npm install dentro
Opciones de ng new:
--prefix: prefijo de la app
--skip-tests: no genera los archivos *.spec.ts
--skip-install: se salta el paso de npm install
Primeros pasos
Ejecutar la app y verla en el navegador:
ng serve -oEntornos dev y prod
Archivos de configuración
Módulos: contenedores lógicos
Componentes
Divisiones de la UI
Tienen clase y template (controlador y vista)
Estilos propios (:host para el propio componente)
Creando piezas:
ng generate <tipo-pieza> <nombre-pieza> [params]
Esqueleto de una pieza en Angular
clase =>
=> clase exportada =>
=> clase decorada =>
=> dependencias
Examinando un módulo
Metadata
declarations:
- componentes, directivas y pipes del módulo
imports:
- otros módulos cuyos componentes, directivas o pipes exportados queremos usar
exports:
- componentes, directivas o pipes que exponemos para que los usen otros módulos
providers:
- objetos inyectables que están disponibles para el inyector del módulo
bootstrap:
- componente(s) inicial de la app
Examinando un componente
Metadata
selector:
Selector CSS que se corresponde con una etiqueta HTML
template / templateUrl:
String con el HTML / fichero con el HTML
styles / styleUrls:
Strings con los estilos / ficheros con los estilos
ngOnInit
Componente inicializado (con su vista renderizada y sus valores cargados), se usa para los procesos iniciales (no usar el constructor).
ngOnDestroy
Examinando un template
Custom elements
Data binding
Interpolation
Property binding
Class & style binding
Event binding
Two-way binding
Examinando un template
Directivas de atributo
ngClass
ngStyle
Directivas estructurales
ngIf
ngFor
Pipes
Servicios
Dependency Injection:
Proveedores y jerarquía de inyectores
Injectable()
Singleton: tiene como ámbito su inyector y todos sus inyectores hijos.
Formularios
Template driven y Reactive forms
[(ngModel)]: Two-way binding
Importar el módulo FormsModule
Variables de template con #:
#formulario="ngForm"
#control="ngModel"
Validaciones: ng-invalid, ng-dirty y ng-touched
Capturar el envío: ngSubmit
Resetear los estados
Despliegue a producción
Pruebas con ng build
ng build:
--prod: código optimizado para producción
--base-href=: cambia el directorio base
--sourcemaps: genera los source maps
lite-server --baseDir="dist/project-name"
Entornos propios
Links