Introducción

Antes de empezar, a lo largo de estos artículos puede que use la palabra controller o controladores. Con este término me refiero al archivo .ts que se crea por cada componente, es decir, la propia lógica de dicho componente. Si no sabes cómo crear componentes en Angular te recomiendo que eches un vistazo a mi artículo anterior: Cómo crear componentes en Angular

Controllers (archivos .component.ts)

Bien, como hemos dicho, los controladores se encargan de manejar la vista y de crear toda la lógica de dicho componente. En los controladores es en el lugar en el que se crean todas las variables e información que necesite la vista para pintarse. Además se encarga de la interactividad del componente, es decir, de especificar qué se hace al renderizar el componente, al eliminar el componente de la vista, o al pulsar sobre un elemento del HTML.

La principal ventaja de Angular (y de otros frameworks) es que la vista está siempre actualizada con las variables que tengas definidas en el controlador. Por ejemplo si creas una variable de tipo string y al pulsar sobre un botón decides cambiar su valor, automáticamente en la vista se refleja el nuevo valor, sin que tengas que hacer nada. Esta reactividad permite que no te tengas que preocupar de refrescar la vista cuando cambias un valor o hacer una operación.

Recordemos la estructura básica que tienen los controladores.

Estructura de los controllers

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-item-list',
  templateUrl: './item-list.component.html',
  styleUrls: ['./item-list.component.css']
})
export class ItemListComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

Este código de arriba es el de un controlador, ya te debería de sonar. El único cambio es que esta vez lo he generado con el comando ng generate de Angular. Este comando añade en el export de la clase la implementación de OnInit.

Este OnInit si se implementa en la clase del controlador permite que dentro puedas llamar al método ngOnInit. La ventaja de este método es que el código que metas dentro se ejecutará cada vez que este componente se renderice por pantalla.

Por ejemplo, si recuerdas, en el artículo anterior creamos un par de rutas en la web. Si añades el código de abajo en un componente que tenga asignada una ruta y nevegas en el navegador hasta esa ruta, aparecerá por pantalla el console.log

ngOnInit() {
  console.log("ngOnInit del componente");
}

Pero esto no quiere decir que el OnInit tenga que estar en un componente con una ruta asignada. Puedes meterlo en cualquier componente y se ejecutará cuando se muestre por pantalla.

Pero también hay un método llamado constructor(), que también se ejecuta al cargar la página. El constructor también se utiliza para la inyección de dependencias.

Otro método que también tiene Angular y que ya has usado es el constructor. El método constructor también se ejecuta cuando se carga el componente, igual que el OnInit, pero entonces, ¿qué diferecia hay entre ambos?

Diferencias entre ngOnInit() y el constructor() en Angular

Como otros lenguajes, typescript también tiene un constructor de clase, en este caso el constructor se ejecuta antes que el ngOnInit().

Normalmente se usa el constructor para inicializar variables, y el ngOnInit para inicializar o ejecutar tareras que tienen que ver con Angular. Todo esto lo podemos poner directamente en el constructor y funcionaría de la misma manera, pero no está de más tener más separado el código para que sea más mantenible.

Es decir, mi recomendación es que en el constructor solo incialices variables y el ngOnInit el resto de cosas: llamadas a backend, preparación de los datos, filtrado, etc.

Visto esto de Angular vamos con lo importante de este artículo: cómo se programa con Typescript.

Sintaxis TypeScript

Logo de typescript

Typescript es un lenguaje que creó Microsoft. Su sintaxis es una especie de mezcla entre Javascript y Java. Todo el código que escribas en Typescript será compilado en código Javascript.

Typescript está pensado para añadir funcionalidad a Javascript, extenderlo, y por tanto puedes usar código Javascript dentro de métodos y clases de Typescript.

Veamos todo lo que añade Typescript respecto a Javascript:

Tipado estático

Typescript añade tipado estático a Javascript, puedes crear variables con un tipo fijado (string, números, etc). El tipado estático es opcional por lo que deja al desarrollador si quiere utilizarlos.

Los tipos que vienen con typescript son:

  • boolean: (true/false).
  • number: integers, floats, Infinito y not a number.
  • string: caractéres o lista de caracteres.
  • []: Arrays of other types, like number[] or boolean[].
  • {}: Objeto literal.
  • undefined.
  • any: Tipo especial que permite que una variable pueda tener cualquier tipo.

Para crear los tipos, al declarar las variables, tienes que indicar su tipo con dos puntos, por ejemplo:

let decimal: number = 6;

En el caso de arriba se crea una variable llamada decimal de tipo number inicializada a 6.

Lo bueno de este tipado estático es que al declarar los tipos consigues tener mayor control mientras estás desarrollando. Por ejemplo si creas una variable contador de tipo number, si más adelante haces que esa variable tenga un valor de tipo string, el compilador arrojará un error. Esto permite que el código sea menos propenso a fallos.

Por cierto, también puedes declarar los tipos para los parámetros de entrada de las funciones, incluso para el tipo de dato que devuelven:

function identity(arg: number): number {
  return arg;
}

Programación orientada a objetos con clases en Typescript

Typescript añade clases. Las versiones modernas de Javascript ya incorporan clases pero las de typescript son más cómodas de usar.

Para declarar las clases se utiliza la misma sintaxis que Javascript ES6, por ejemplo:

export class Rectangle() {
  private width:number:
  private height:number;
}

También he declarado dos atributos de clase (a diferencia de Javascript que no los puedes declarar directamente). Como pasa en otros lenguajes, aquí también se pueden declarar variables ‘private’, no se puede acceder a estas variables desde fuera de la clase en la que están declaradas.

Para crear funciones se hace igual que en ES6:

calcArea() {
  return this.height * this.width;
}

Para la herencia también se hace como en ES6:

class Dog extends Animal {
}

Interfaces

Igual que en Java, Typescript también tiene interfaces:

interface Person {
  firstName: string;
  lastName: string;
}

Las iterfaces sirven para que las clases puedan implementar dichas interfaces de forma que tengan una definición de métodos y características similar. Una vez una clase implementa la interfaz queda en su mano cómo va a querer la implementación de dichos métodos.

Para implementar una interfaz se usa la palabra reservada implements:

interface Animal {
  name: string;
  age: string;

  eat(): void;
}
class dog implements Animal {
  name = "Dog";
  age = 10;

  eat() {
    console.log('Dog eating');
  }
}

A mi las interfaces, personalmente, me sirven de gran ayuda para definir cómo van a ser los objetos que quiero en mi web. Por ejemplo puedo crear la interfaz User:

interface User {
  name: string;
  age: number;
}

Para que de esta forma todos los usuarios tengan los mismos parámetros.

El resto de características (arrays, objetos, arrow functions, etc ) son exactamente igual que en Javascript ES6.

Inyección de dependencias

Logo de typescript

Una de las ventajas que tiene Angular respecto a otros frameworks es la posibilidad de usar el patrón de diseño de inyección de dependencias. Este patrón sirve para proveer, suministrar, a las clases con las dependencias que se necesita. Esto permite que el código se pueda testear mejor ya que puedes pasar las dependencias desde fuera de la clase.

Imagina que inicializamos las dependencias de una clase de la manera tradiccional:

public Example() {
  object_test = Factory.getObject();
}

A la hora de testear esta clase es mucho más complicado porque si quieres comprobar la llamada a Factory (o quieres interceptarla no puedes). Para ello lo que se hace es inicializar la dependencia directamente desde el constructor, de esta forma lo que conseguimos es que al testear la aplicación, podamos crear el objeto Factory desde fuera:

constructor(Factory factory) {
  object_test = Factory.getObject();
}

Para que esté código funcione, tenemos que meter dentro del objeto Factory una anotación especial de Angular, @Injectable():

// factory.ts

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class Factory {

  constructor() { }

}

En este caso, se crea la anotación Injectable encima de la declaración de la clase. providedIn es un atributo especial de las anotaciones inyectables. providedIn: ‘root’ significa que Angular creará una sola instancia de esta clase para poder inyectarla de forma global en los componentes que la necesite. Esto permite ahorrar recursos y optimizar las webs de Angular al no tener que crear una instancia por dependencia aunque sea de la misma clase.

Conclusiones

Typescript suena muy diferente pero no deja de ser ES6 con unas cuantas cosas más. En mi opinión es un lenguaje en el que todo el mundo se siente cómodo porque es un poco una mezcla de Java y de Javascript.

Esto es una pequeña muestra de todo lo que Typescript puede ofrecer. Si te has quedado con las ganas de aprender más sobre Typescript visita su página oficial:

http://www.typescriptlang.org/index.html

En próximos artículos empezaremos a tocar cositas de las vistas, es decir, veremos cómo pasar datos desde los controladores a las vistas.