Single Page Application: Un viaje a las SPA a través de Angular y Javascript (II)

Nos introducimos en TypeScript y aprendemos los fundamentos de Angular

@davidjguru
23 min readFeb 10, 2019
Índice: en este artículo
0- Objetivos
1- Introducción
2- Solo un pequeño toque de TypeScript
2.1- Primer ejercicio con TypeScript: Hello World vía navegador
2.2- Segundo ejercicio con TypeScript: Hello World vía Node
2.3- Tercer ejercicio con TypeScript: Hello World con errores
2.4- Cuarto ejercicio con TypeScript: Transpilación automática
2.5- Quinto ejercicio con TypeScript: Imprimir Saludo
2.6- Sexto ejercicio con TypeScript: Comprobar tipado
2.7- Séptimo ejercicio con TypeScript: Clases e Interfaces
3- Conceptos básicos de Angular
3.1- Componentes
3.2- Decoradores
3.3- Directivas
3.4- Módulos
3.5- Servicios
3.6- Vistas
4- Segundo ejercicio con Angular: Hello World
4.1- Modificar el mensaje de Bienvenida
4.2- Añadir un nuevo componente Footer a Hello World
4.3- Modificar el title de página en Hello World
5- Referencias y lecturas recomendadas
Este artículo viene de:
Single Page Application: Un viaje a las SPA a través de Angular y Javascript(I)
Otros artículos no relacionados que podrían interesarte:
Composer y Drush en el contexto de Drupal 8
Form API(I): Comprender, crear y modificar formularios en Drupal 8
Form API(II): Modificando formularios en Drupal8 mediante form_alter
Form API(III): Caso práctico de modificación de formulario Drupal 8

0- Objetivos

En este artículo aprenderás:
1. Varias rutinas iniciales con TypeScript.
2. Gestionar la transpilación de TypeScript a JavaScript por consola.
3. Conceptos teóricos de Angular (Módulo, Componente, Directiva, Servicio).
4. Estructura de directorios y ficheros en una app Angular.
5. Realizar modificaciones y añadir componentes en una app Angular.

1- Introducción

¡Hola de nuevo! ¿Qué tal por aquí?

Vamos a seguir el camino iniciado en el artículo anterior. Tengo notas por aquí y por allá, ejemplos, tutoriales, código, snippets y demás que quería poner en orden de manera -relativamente- estructurada y articularlo todo en forma de tutorial por capítulos a la manera que creo que puede ser más interesante: combinando lo teórico y lo práctico, de manera progresiva y globalizando cada nuevo concepto.
En este segundo artículo sobre la construcción de aplicaciones con Angular, se hacía necesario pasar primero por TypeScript, el superset over JavaScript que sirve de base para poder construir funcionalidades y para ello, hay que detenerse un poco al menos en ofrecer un marco de este lenguaje y sus principales características: el concepto de transpilación, sus diferencias con JavaScript, como operar con él bajo línea de comandos y algunas curiosidades más.

Supongo que en cierta manera, obtener un buen nivel construyendo aplicaciones con Angular depende mucho de tener bien claro sus conceptos teóricos elementales, así que también los repasaremos en un apartado específico. En el siguiente apartado y para conectar este artículo tanto con su sentido último como con el artículo anterior, retomaremos el ejercicio Hello World creado con Angular y comenzaremos a realizarle modificaciones: siempre intentaremos aplicar el esquema de introducción teórica + práctica directa. Se aprende lo que se comprende y se practica a la vez.

Espero que puedan sacarle partido a este artículo.

2- Solo un pequeño toque de TypeScript

Conceptualmente hablando, TypeScript es algo así como un superset de Javascript, algo que viene a añadirle vitaminas a lo que ya existe, similar en espíritu a lo que less o sass hacían por CSS.
Un Javascript con funcionalidades extra pero que al 85–90% es un Javascript normal que lleva añadidas herramientas nuevas del estándar ECMAScript ¿Qué sentido tiene esto? bueno, al transpilar a un Javascript normalizado ( y por tanto, extendido), permite la ejecución de código en navegadores no-actualizados a la última versión disponible de la especificación ECMAScript.

Es un lenguaje de programación desarrollado por Microsoft (https://www.typescriptlang.org+) con implementación liberada como Software Libre con licencia Apache 2. Está compuesto en un 85% de Javascript normal y corriente -PERO- integra características de los nuevos estándares ECMAScript 6 y 7, usa tipado fuerte (las variables se mantienen estrictas con el tipo de dato que hayamos declarado inicialmente…string, integer, etc).

Es un lenguaje interpretado que se “transpila” (algo más horizontal que vertical) a Javascript normal y corriente. Esto quiere decir que programamos en TypeScript formando archivos de extensión .ts y luego usando un transpilador tendremos un fichero Javascript válido para cualquier navegador web moderno. Este es el lenguaje de programación en el que se basan los proyectos hechos con Angular.

Instalando y probando con TypeScript

Si seguiste los pasos del artículo anterior y ya tienes instalados npm y Node.js, será tan sencillo como ejecutar la instrucción npm install -g typescript (con especial atención a los permisos de escritura en /usr/lib/node_modules/).

También con Visual Studio Code tienes muchas opciones para trabajar con TypeScript:

2.1- Primer ejercicio con TypeScript: Hello World vía navegador

Vamos a crear el primer ejercicio con TypeScript: Hello World que lanzaremos desde navegador. El caso será extremadamente simple: solo necesitaremos dos ficheros:

1- Fichero de extensión .html para cargar desde el navegador: “basic-hello-world.html”.
2- Fichero de extensión .ts para cargar un mensaje Hello World: “basic-hello-world.ts”.

basic-hello-world.ts

console.log("Hello World from TypeScript");
alert("Hello World with TS");
console.warn("Warning: TypeScript is running");
console.error("Oh, well...welcome to TypeScript");

Y en el html cargaremos el futuro fichero Javascript ya transpilado(basic-hello-world.js):

basic-hello-world.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title> OOP And TypeScript</title>
<script src="basic-hello-world.js"></script>
</head>
<body>
<h1>Object-Oriented Programming (OOP) And TypeScript</h1>
<p>
Lorem fistrum tiene musho peligro sexuarl diodeno. Hasta luego Lucas ese que llega al ataquerl papaar papaar. Pupita se calle ustée de la pradera llevame al sircoo fistro apetecan ahorarr fistro. Me cago en tus muelas me cago en tus muelas sexuarl llevame al sircoo caballo blanco caballo negroorl.
</p>
</body>
</html>

La secuencia es la siguiente:

1- Lanzamos la instrucción de transpilado tsc basic-hello-world.ts desde la carpeta donde se encuentra el fichero .ts y eso creará el .js

2- Abrimos el fichero html donde cargamos el script .js desde el navegador y veremos la ejecución del mismo con ventana de alert y abriendo la consola de Javascript (Ctrl+Shift+J o Cmd+Opt+J -Mac- con Chrome):

Transpilación — Ejecución de archivo TypeScript para un Hola Mundo

Este es nuestro particular Hello World con TypeScript. :-)

2.2- Segundo ejercicio con TypeScript: Hello World vía Node

Como es costumbre, el primer ejercicio que realizaremos será un saludo Hola Mundo. Y ya lo hemos hecho, aunque ahora vamos a probar a ejecutarlo de otra manera. Para ello creamos con nuestro editor de texto phavorito un fichero de nombre hello-world.ts e incluimos estas sencillas instrucciones:

var a = 'Hello',
b = 'world';
console.log(`${a} ${b}!`);

Con un par de órdenes:
1- Creamos dos variables para almacenar dos cadenas de texto: Hello, world.
2- Sacamos por consola la proyección de ambas mediante interpolación.

A continuación transpilamos el fichero de extensión .ts a través del comando tsc en consola: tsc hello-world.ts y generamos así el fichero transpilado hello-world.js ahora para ejecutarlo no tenemos porqué cargarlo en un navegador. Al tener npm y Node.js instalados en nuestro sistema, podemos lanzarlo directamente desde consola: node hello-world.js

Y eso generará la salida de nuestro script: Hello World!

salida Hello World con node

Acabamos de realizar nuestro primer ejercicio con TypeScript y Node. Enhorabuena.

2.3- Tercer ejercicio con TypeScript: Hello World con errores

Aunque puede resultar presuntuoso marcarlo como “ejercicio”, me parecía que necesitábamos cerrar el Hello World como se merece y hacer un aparte para esta iteración con algunos matices sobre el mismo fichero . Veamos.

El objetivo es comprobar el funcionamiento de la mecánica de desarrollo con TypeScript — Transpilación — Javascript en ejecución cuando se producen errores de codificación. Para ello vamos a volver a editar el fichero hello-world-ts con nuestro editor de texto favorito y le añadimos algunos errores de síntaxis:

Al lanzar la orden de transpilación, obtendremos un set de errores por consola:

tsc con errores detectados en transpilación

Pero además, la transpilación termina con la generación del fichero .js a pesar de los errores encontrados respecto a las especificaciones de TypeScript (no de Javascript, por eso podría seguir funcionando al ejecutarse el .js final)

¿Es importante controlar los errores de TypeScript de cara a la ejecución del futuro Javascript? bien, entonces podemos hacer algo para controlarlo y no dejar pasar (por error u omisión) un posible fichero .js que no nos sirva.

Podemos decirle al transpilador que omita la creación de un fichero .js en caso de que encuentre errores en Typescript mediante la opción tsc hello-world.ts --noEmitOnError ya que con el uso de este flag no se generará el .js y no arrastraremos los posibles errores. Veamos:

tsc para transpilar con flag — noEmitOnError

Mejor así, ¿no? más controlado :-)

2.4- Cuarto ejercicio con TypeScript: Transpilación automática

Como podemos apreciar, programar en TypeScript supone estar constantemente lanzando el transpilador para ir componiendo los ficheros .js que necesitemos. Ok. ¿Hay alguna manera de automatizar esto? Sí, la hay. Podemos usar el flag -w en la instrucción tsc del transpilador para activar el modo “watching” y que este se coloque activamente observando cambios en los ficheros que queramos indicar.
En cuanto grabemos nuestros cambios, el transpilador los detecta, lanza el proceso y devuelve los resultados sin necesidad de que interactuemos con él.

Veamos un ejemplo a partir del caso basic-hello-world.html:

1. En la primera parte, lanzamos la instrucción tsc -w *.ts (para observar cambios en todos los ficheros de extensión .ts de la carpeta actual.

2. En la segunda parte, realizamos un leve cambio en el texto del alert del fichero basic-hello-world.ts y observamos la primera pantalla para observar si se producen errores en la transpilación.

3. Por último, recargamos el navegador y ya podemos ver directamente los cambios realizados a nivel de TypeScript.

2.5- Quinto ejercicio con TypeScript: Imprimir Saludo

Para empezar, vamos a realizar el pequeño ejercicio inicial propuesto en la zona de ejemplos de TypeScript+ usando simplemente el transpilador que nos hemos instalado anteriormente y nuestro editor de texto habitual. Vamos a probar algunos aspectos básicos de TypeScript que hemos comentado anteriormente y como se relaciona con JavaScript.

1- Creamos un fichero llamado greeter.ts, en mi caso vim greeter.ts y añadimos el siguiente código:

function greeter(person){
return "Hello, " + person;
}

let user = "Jane User"; // Usamos let para limitar scope de vble.
document.body.innerHTML = greeter(user);

2- A continuación transpilamos el fichero mediante la instrucción tsc greeter.ts , lo que generará justo al lado el nuevo fichero transpilado de nombre greeter.js que tiene como principal diferencia con el original el cambio de definición de la variable “user” de let (alcance limitado a bloque) a var:

greeter.js transpilado

3- Creamos un fichero greeter.html a modo de index para las pruebas, le incluimos el siguiente código con la llamada al fichero greeter.js:

<!DOCTYPE html> 
<html>
<head>
<title>TypeScript Greeter</title>
</head>
<body>
<script src="greeter.js"></script>
</body>
</html>

4- Abrimos el fichero greeter.html desde navegador web y comprobamos que se carga el script greeter.js y se ejecuta la función que lanza el saludo.
He aquí nuestra primera aplicación en TypeScript:

https://www.typescriptlang.org/play/index.html

2.6- Sexto ejercicio con TypeScript: Comprobar tipado

La segunda iteración sobre el “saludador” es solo para comprobar una de las piezas claves de la definición de este superset para Javascript que es TypeScript: ampliar el lenguaje base con un tipado fuerte.

Vamos a tomar el fichero anterior greeter.ts y le modificaremos el tipo de entrada del parámetro person a la función greeter y la asignación de la variable user por un array de valores:

function greeter(person: string){
return "Hello, " + person;
}

let user = [0,1,2];
document.body.innerHTML = greeter(user);

A continuación, volvemos a transpilar el fichero mediante tsc greeter.ts y obtenemos un error por consola:

TypeScript error TS2345: Argumento no asignable

Obtenemos un error durante el proceso de transpilación que nos informa de que la asignación no es válida ya que estamos esperando un parámetro de tipo String. Sin embargo, si volvemos a mirar dentro de nuestro directorio, vemos que hemos obtenido la versión .js transpilada:

Fichero js transpilado obtenido tras el error TS2345

Y en dicha versión transpilada se encuentra el código Javascript que por no tener tipado fuerte de variables no tipifica la entrada del parámetro person como string:

Transpilación js de greeter_bad.ts

Y como podemos comprobar mediante el navegador web, a nivel de ejecución de Javascript no se produce ningún problema relacionado con el tipado:

Así que el tránsito del tipado fuerte con TypeScript no repercute en errores posteriores sobre el tipado débil de JavaScript. ¿Necesitas controlarlo? piensa en el ejercicio 2.2, usa el flag --noEmitOnError

2.7- Séptimo ejercicio con TypeScript: Clases e Interfaces

Bien, ahora introduciremos un poco a TypeScript en el contexto de la Programación Orientada a Objetos (POO), ya que la soporta bastante bien y es el contexto más natural en el que se suele usar.

Para ello, vamos a empezar con el concepto de “Interfaz” que como sabemos, en el contexto de la POO es la especificación de un contrato para declarar unos métodos que la clase que implementa dicha Interfaz se compromete a definir. Este es un mecanismo clásico para sortear las limitaciones de la herencia no-mutiple que la POO no nos permite hacer (que una clase extienda a más de una clase). Y en este contexto, sigue siendo lo mismo, con el matiz que dado que TypeScript viene a aportar tipado fuerte a JavaScript, también podemos definir propiedades además de métodos. Definamos una Interfaz:

interface Person{
name: string;
surname: string;
age: number;
getName(): string;
throwGreeting(): void;
setGreetingConsole(): void;
}

En este ejemplo de Interfaz definimos tres propiedades que servirán para definir a un usuario, así como tres métodos básicos: uno para cargar un saludo por pantalla a través del HTML y otro para cargarlo en Console del navegador. A continuación definiremos la clase que la usará:

class User implements Person{
name: string;
surname: string;
age: number;

constructor(name: string, surname: string, age: number){
this.name = name;
this.surname = surname;
this.age = age;
}

buildGreeting(){
return "Hello "+this.name;
}
getName(){
return this.name;
}

throwGreeting(){
document.body.innerHTML = this.buildGreeting();
}

setGreetingConsole(){
console.log(this.buildGreeting());
}

}

Como vemos, nos hemos encargado de cumplir el contrato con la Interfaz, así como de añadir algún método más como el constructor de la clase para iniciar un Objeto de este tipo o el getName() por hacer un clásico método getter de una propiedad.

Ahora le añadimos una función que instancie la clase y lo unificamos todo en un único fichero class_and_interface.ts para poder transpilarlo a Javascript y luego cargarlo desde un fichero .html para comprobar su funcionamiento:

function greetingHTML(name: string, surname: string, age: number){                        let person = new User(name, surname, age);
person.throwGreeting();
}

greetingHTML("John", "Smith", 21);

Como vemos, aquí tenemos la función que creará instancias de la clase y una llamada final a esta con tres parámetros. En este caso, usamos los métodos de la clase a través de la función y en este primer paso, solo llamamos al método que incrustará un saludo en el HTML que veremos por el navegador.

Aquí tienes la carpeta con los tres ficheros del ejemplo (.ts, .js y .html)+

Bien. Ahora si cargamos en el navegador un html básico que llame a nuestro fichero resultante classes_and_interfaces.js, veremos ejecutada los resultados de la secuencia de definición de Interfaz, implementación de esta desde la clase, los métodos definidos y los resultados generados por esto a través de la llamada de una función. Un pequeño resultado en pantalla que resume la integración de conceptos que hemos definido:

Aquí tienes el fichero para hacer pruebas:

3- Conceptos básicos de Angular

En base al enfoque de estos artículos, ahora toca cambiar (un poco) de contexto. Dado que la curva de aprendizaje implica un trabajo curioso, quizá mejor intentar un abordaje lateral y complementario. Estábamos hablando del lenguaje TypeScript y ahora volvemos a la plataforma. Es tiempo de conectar con la segunda parte de estos artículos: vamos por Angular.

En la aproximación a Angular que realizamos en este episodio de la serie, vamos a definir algunos conceptos y términos elementales del universo propio de Angular, y lo haremos aprovechando la estructura de proyecto que ya tenemos generada en nuestro entorno. A partir del Hello World que hicimos en el artículo anterior de esta serie sobre SPA, Angular y Javascript, vamos a conocer la estructura interna de un proyecto basado en Angular y que claves contiene cada parte.

¿Qué directorios y ficheros principales contiene un proyecto Angular?

Estructura de carpetas y ficheros de un proyecto creado con Angular CLI

La estructura que Angular CLI genera para un proyecto tiende a ser todo lo posiblemente plana, suficiente (en teoría) como para poder encontrar un archivo en menos de cinco segundos, siguiendo el principio LIFT:

  • Locating our code easy (Localización fácil del código).
  • Identify code at a glance (Identificación del código de un vistazo).
  • Flat structure as long as we can (Estructurar todo lo plano que podamos).
  • Try to stay D.R.Y — Don’t Repeat Yourself (Intenta no repetirte).

Veamos los sucesivos niveles de ficheros y directorios:

Y en la ruta /src/app/ se encuentran los ficheros que más nos importan ahora:

Vamos a tomar este set de ficheros como referencia para repasar la anatomía elemental de una aplicación basada en Angular, con lo que comentaremos los conceptos más interesantes y los veremos bajo la lupa en estos mismos ficheros del listado anterior.

Comenzaremos exponiendo los que podrían ser los seis elementos básicos de Angular: Componentes, Decoradores, Directivas, Módulos, Servicios y Vistas. Veamos.

3.1- Componentes

Es una clase que controla (¿Se podría aproximar a un “Controlador” tal y como lo conocemos en el contexto de PHP?) como se muestra una sección específica de nuestra aplicación, lo que podríamos llamar intuitivamente una vista. Para transformar una clase cualquiera en un Componente usamos el decorador “Component” donde declaramos -entre otros elementos- que plantilla o template visual usaremos para mostrar la vista del componente.

Declaraciones en el decorador “Component”

En nuestra pequeña aplicación hecha como ejemplo en el artículo anterior, el componente se encuentra articulado en el fichero app.component.ts del listado anterior de ficheros presente en la ruta /src/app/. Como vemos, la última instrucción es la de exportar la clase declarada como “AppComponent” que luego será usada desde la inicialización del módulo central de la aplicación.
Ojo a la propiedad “selector” (‘app-root’), que luego veremos en otro contexto (pulsa aquí si quieres saberlo ya, elige tu propia aventura).

3.2- Decoradores

Transforman las clases TypeScript en tipos especiales que pueden ser usados para otras cosas…lo cual resulta algo abstracto, así que intentaremos concretar. Básicamente, los decoradores en Angular son funciones que alteran clases Javascript de manera externa. Se usan para añadirle metadatos a las clases que serán registrados de manera más exhaustiva, de manera que informen sobre como funcionan y que comportamiento tienen.

Uso de decorador para ampliar una clase básica

Esencialmente consiste en un corpus informativo de registro para ofrecer el contexto de ese componente. ¿Recuerdas la creación de Plugins mediante Annotations en Drupal — PHP ? pues aunque no sea exactamente lo mismo, de momento podríamos decir que esto tiene un espíritu parecido.

3.3- Directivas

Intentaremos acotar un poco este concepto: lo primero que debemos asumir es que en el contexto de Angular, los templates son cambiantes sobre la marcha, es decir, son dinámicos. Admiten modificaciones en tiempo de “compilación”. Mientras Angular los va montando y renderizando, puede introducir cambios en el DOM según la lectura que vaya haciendo de unas reglas de manejo que podemos insertarle. Estas pautas son las llamadas “directivas”. En la práctica, serán clases de TypeScript asociadas a un decorador @Directive (salvo en un caso que veremos a continuación).

Existen tres tipos de directivas en Angular:

  • Componentes: Son en si mismos un tipo de directiva muy específica, con la suficiente entidad como para aprenderlos de manera independiente (por eso los tratamos por separado), pero en sí, no son más que directivas ligadas a una plantilla (un template, una vista).
    Son las directivas más comunes y tiene derecho a usar su propio decorador, @Component.
  • Directivas estructurales: Modifican la estructura de una vista, incorporando, retirando o reemplazando nuevos elementos sobre el DOM.
  • Directivas de atributos: Alteran el aspecto o el comportamiento de un elemento HTML, un componente u otra directiva. Suelen usarse como atributos HTML de elementos.

Podríamos diferenciarlas de manera intuitiva en dos grupos: por un lado las directivas que afectan a la lógica de negocio (Componentes) y por otro lado aquellas directivas que afectan a la estructura de vistas (Estructurales y Atributos).

3.4- Módulos

Sirven para organizar una aplicación en bloques funcionales. Cada app hecha en Angular debe tener, al menos, un módulo disponible, normalmente llamado “root module”. Lo normal en una app de poco tamaño es que sea el único módulo.
Lo normal suele ser mapear una funcionalidad clave o muy importante = 1 módulo, es decir; si tu aplicación tiene cinco features principales, seguramente tendrás 5 + 1 (root) módulos, y cada módulo decorado con @NgModule.

Veamos la construcción del fichero app.module.ts de nuestro ejemplo Hello World con Angular:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component'; // <-Importa compon.
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent] // <-Arranca con el componente declarado
})
export class AppModule { } // <-Declara finalmente una clase (vacía)

3.5- Servicios

Al igual que en el contexto actual de frameworks basados en PHP, en este caso un Servicio también es una clase que realiza una función muy específica y puede ser reutilizable desde otros lugares de la aplicación. Simplemente resuelve una funcionalidad concreta y está normalmente disponible para ser usada.

3.6- Vistas

En el apartado anterior sobre Componentes, dijimos que uno de ellos se encargaba de la responsabilidad de controlar una sección específica del renderizado de la página o sección, a lo que llamaremos una vista.
Veamos el contenido de una vista de ejemplo, el fichero app.component.html de nuestro primer ejercicio “Hello World” del artículo anterior:

<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<img width="300" alt="Angular Logo" src="path/to/image">
</div>
<h2>Here are some links to help you start: </h2>
<ul>
<li>
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://angular.io/cli">CLI Documentation</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
</li>

Como vemos, es una estructura HTML estándar que incorpora un caso de interpolación de variables en el caso de “title” y que vuelva el valor en la expresión. Este fichero de vista se complementa con una hoja de estilo asociada, en un fichero llamado app.component.css.

Esquema de app en Angular 2+, estructura conceptual

4- Segundo ejercicio con Angular: Hello World

Vamos a retomar los ejercicios con Angular justo donde lo dejamos en el artículo anterior. En el apartado final, habíamos creado nuestro propio “Hello World” con Angular, en el sentido que habíamos instalado las herramientas necesarias (Nodejs, npm, AngularCLI) y posteriormente habíamos creado mediante comandos de Angular CLI un nuevo proyecto y lo habíamos lanzado a través de navegador. ¿Lo recordáis? lo hicimos aquí+.

Bien, pues vamos a comenzar por ahí. Lo primero que vamos a hacer es convertir propiamente el ejemplo en un “Hello World” en toda regla, ya que el mensaje de bienvenida se mostraba en base al nombre de proyecto, “project-testing”.

4.1- Modificar mensaje de Bienvenida

Modificaciones que vamos a realizar sobre la pantalla de nuestro ejercicio de Angular:

1- Cambiar el mensaje de bienvenida por “Hello World”.

2- Retirar el menú lateral de opciones que Angular monta por defecto en la interfaz.

Para modificar el texto de bienvenida, vamos a modificar la clase del Componente: app.component.ts en la ruta /project-testing/src/app/ y allí al abrir el fichero a edición vemos la única propiedad que tiene la clase, una variable de nombre “title” que almacenará el nuevo título:

export class AppComponent {
title = 'Hello World'; // <- Título
}

Ya hemos modificado el contenido de la variable asociada al título y al actualizar la ventana del navegador ya veremos la sustitución de valor, pero aún nos queda el punto dos de las modificaciones (Retirar el menú lateral izquierdo) y ya de paso retirar eso de “Welcome to” y dejarlo a secas en “Hello World”. Para ello, recurriremos a editar la vista del proyecto, que si has leído las partes anteriores de este artículo, sabrás que estamos hablando del fichero app.component.html , presente como los principales ficheros del proyecto, en la ruta /project-testing/src/app/ . Ok, pues abrimos este y vemos la estructura de la vista tal y como la anótabamos en el apartado anterior donde comentábamos las vistas:

Estructura básica de la vista en el fichero app.component.html

Bien, pues intervenimos sobre el fichero de la vista (y aprovechamos para retirar el logotipo de Angular) y lo transformamos en…

<div style="text-align:center">
<h1>{{ title }}!</h1>
<img width="300" alt="Vulcanian Salute" src="http://icons.iconarchive.com/icons/google/noto-emoji-people-bodyparts/256/11974-vulcan-salute-medium-skin-tone-icon.png">
</div>

A continuación guardamos todo, se recompila de nuevo y al cargar la vista en el navegador ya podremos ver los resultados. Ahora la vista principal de nuestro Hello World queda modificada. De hecho, si levantamos la inspección del código de la página recién creada con las devtools del navegador, veremos el código HTML de nuestro HelloWorld:

Vista HTML de la landing page Hello World con Angular

¿Dónde hemos visto esto antes?

Lo teníamos disponible en el archivo app.component.ts de la ruta /src/app/

import { Component } from '@angular/core';@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Hello World';
}

Y ahora lo vemos a nivel de código HTML…¿Qué ocurre? bien, hemos encontrado una de las esencias del trabajo con Angular: En nuestros proyectos, estamos creando nuevas etiquetas HTML totalmente INVENT que sirven para inyectar componentes TypeScript — JavaScript que se terminarán renderizando en el navegador cliente. A eso vamos, demos un siguiente paso.

4.2- Añadir un nuevo componente Footer a Hello World

Hemos visto que nuestra landing page de bienvenida queda algo sosa así tal cual está y queremos mejorarla añadiéndole un footer que tenga alguna información personal de contacto.

Para ello, lo primero que haremos será crear una carpeta

footer”que almacene los ficheros del nuevo componente en la ruta src/app/ y dentro un fichero básico (de momento):
* footer.component.ts para la clase TypeScript del elemento.

Será en este fichero TypeScript en el que declaremos nuestro nuevo componente. Para ello, a pesar de que podemos hacerlo de manera automática mediante el scaffolding que nos brinda AngularCLI, lo haremos de manera artesanal para practicar un poco.

1- Importamos la clase Component del core de Angular
2- Creamos el decorador del Componente Footer
3- Incluimos el nombre del selector que usará este nuevo Componente (esas etiquetas HTML totalmente INVENT que inyectamos).
4- Para el template, podemos usar un fichero externo del tipo footer.component.html o código interno. Inicialmente, incluiremos el HTML del componente dentro directamente.
5- Creamos una clase FooterComponent como “core” funcional del nuevo Componente.

import { Component } from '@angular/core';@Component({
selector: 'footer-custom',
template: `
<h2>Footer</h2>
<ul>
<li>Author: davidjguru</li>
<li>Contact: davidjguru@gmail.com</li>
</ul> `
})
export class FooterComponent {constructor(){
console.log("Footer Component Loaded");
}
}
~

Por último, hemos añadido una llamada a console.log en el constructor de la clase para informar de cuando se ha cargado el componente, por si se producen problemas a nivel de vista y no lo vemos. Pero ahora ¿Cómo lo cargamos? NEXT: tenemos que incluir el nuevo componente en el módulo de la aplicación.

Editamos el fichero app.module.ts que centraliza la funcionalidad actual de esta aplicación “Hello World” y le añadimos las declaraciones necesarias:
1- Import de la nueva clase FooterComponent.
2- Declaración del Componente en el decorador de Módulo @NgModule.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FooterComponent } from './footer/footer.component';
@NgModule({
declarations: [
AppComponent,
FooterComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

¿Qué más?
Bien, hasta ahora, hemos creado un nuevo componente y le hemos pedido al módulo principal que lo incorpore a su funcionamiento. Ok. pero ¿Y dónde lo veremos? ese nuevo selector INVENT llamado “footer-custom¿Dónde lo inyectamos? Vamos al fichero app.component.html e incorporamos el nuevo selector:

Bien, y al ir guardando ficheros el proyecto se va transpilando solo en modo watching y ya solo queda recargar la página en navegador para ver si hemos cargado el nuevo Componente footer:

Eh, un momento. Justo al publicar este último cambio que añade el componente footer al proyecto, acabo de caer en la cuenta de que el título que aparece en la pestaña del navegador mantiene el nombrado del proyecto “ProjectTesting” ummmmm…

¡Creo que debemos cambiarlo también!
Ok, vamos.

4.3- Modificar el title de página en “Hello World”

Lo primero que debemos tener claro, es que sentido tiene esto en el contexto de una SPA: prácticamente, tenemos dos formas de resolverlo.

  1. En primer lugar, podemos afrontarlo como un simple cambio HTML habitual.
  2. En segundo lugar, podemos asumir la filosofía detrás de una modificación de este tipo en el contexto dinámico que puede tener una SPA: cambios sobre las rutas y las páginas que se muestran pueden generar cambios en el title de página de manera también dinámica.

Para el primer enfoque, simplemente editaremos el fichero central index.html en la ruta /src/ y cambiaremos el valor de la etiqueta <title> dentro del <head> del fichero:

Atributo <title> dentro de <head> en index.html

Luego guardamos y veremos el cambio en el navegador.

En cambio si seleccionamos el punto dos, entramos en un aspecto verdaderamente interesante dentro de Angular: la capacidad de modificar un atributo del proyecto mediante la inyección de dependencias, usando un servicio. Y esa experiencia a este pequeño nivel sí que es interesante. Veamos.

En primer lugar, vamos a asumir que algo como el title de una página puede ser dinámicamente cambiado en base a la actividad del usuario, los clicks que realice y las “páginas internas” (simuladas) que visite. Para ello, Angular nos provee de una clase Title dentro del paquete platform-browser que nos permitirá modificar el valor de este atributo: https://angular.io/api/platform-browser/Title+, como vemos, tiene dos métodos muy sencillos para obtener el Title: getTitle() y cargar uno nuevo: setTitle(newTitle: string)

Vamos a editar el fichero app.module.ts para solicitar la importación de la clase Title a partir de dicho paquete y luego la registraremos como proveedora de servicios desde la sección “providers”:

import { BrowserModule, Title } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FooterComponent } from './footer/footer.component';
@NgModule({
declarations: [
AppComponent,
FooterComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [Title],
bootstrap: [AppComponent]
})
export class AppModule { }

Si ahora guardamos el fichero, el proyecto volverá a transpilarse automáticamente y sin errores. Ya tenemos declarada la clase Title como un proveedor de servicios a nivel de proyecto (podríamos usarla en cualquier componente que diseñemos). Así que ahora vamos a usarla en nuestro componente.

Editamos el fichero app.component.ts y realizamos la importación de la clase. Luego a continuación modificaremos la clase de nuestro componente.

En concreto, para no equivocarnos con la cadena de texto que mostramos mediante interpolación en la vista diciendo “Hello World”, llamaremos a esta variable “titleBody”, para evitar confundirla.

Luego añadiremos un constructor de la clase del componente para que una vez que se cree una instancia de este componente, automaticamente se carguen los valores para estas dos variables que vamos a tener como atributos de la clase: el titleBody con el mensaje del <body> a mostrar y el title con el mensaje que mostraremos en el <head> ¿La diferencia? Que la carga del valor en el segundo caso la hacemos mediante el método setTitle()de la clase Title:

import { Component } from '@angular/core';
import { Title } from '@angular/platform-browser';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})

export class AppComponent {
private titleBody = '';
constructor(private titleService: Title){
this.titleBody = 'Hi, Hello World';
this.titleService.setTitle('Hello World');
}
}

Ahora si guardamos este fichero, solo nos queda un último cambio. Como hemos modificado el nombre de la variable que almacena el saludo en el <body>, vamos a la template del componente y sustituimos la variable cuyo valor estamos solicitando mediante interpolación. De manera que abrimos el fichero app.component.html y así :

<h1>
{{ titleBody }}!
</h1>

Al guardar y transpilar todo, ahora al refrescar en el navegador ya tenemos cambiado el title de la página:

¡Tenemos nuestro nuevo Componente footer integrado y el Title modificado! bueno, queda darle un poco de lustre CSS al footer y una mejor ubicación…así que ya tenemos tareas para mejorar esta vista: crear los ficheros complementarios de vista .html y .css.

Queda pendiente, ¿no?

5- Referencias y lecturas recomendadas

--

--

@davidjguru
@davidjguru

Written by @davidjguru

I’m @davidjguru this is my off-broadway channel, speaking about Drupal like in https://www.therussianlullaby.com or https://davidjguru.github.io but in spanish.