Herramientas de usuario

Herramientas del sitio


wiki2:angular:basics

¡Esta es una revisión vieja del documento!


Angular basics

Basics of basics

Glosario

  • Componente: Clase que interactua con la vista para mostrar datos. Gestiona la lógica de esta. Contiene una directiva y una template.
    • Directiva: La clase encargada de crear e interactuar con los elementos HTML. Cuando Angular encuentra una tag concreta de directiva en la template creará una instancia de esta (por ejemplo <my-directive>).
    • Template es el conjunto de HTML encargado de renderizar una vista.
  • Injector el objeto encargado de buscar la clase adecuada y crearla.
  • Módulo: creamos la aplicación a partir de módulos (nuestros o externos); un módulo es un bloque de código dedicado a algo concreto. Los módulos exportan “algo” y otros módulos lo importan.
  • Pipe es una función que prepara valores para ser mostrados.
  • Provider el encargado de crear una instancia de una dependencia.
  • Router el encargado de crear la navegación entre vistas.
  • Routing component es un componente enlazado a un router.
  • Vista es una porción de ventana para mostrar información e interactuar con el usuario. La vista se renderiza a partir una o varias directivas. El router es el encargado de indicar cuando mostrar una vista.

Aplicación básica

Necesitamos tener una versión de Node.js superior a v5 y de npm superior a v3; para conocer qué versión tenemos de cada uno haremos node -v y npm -v.

Necesitamos los siguientes ficheros:

  • package.json, que contiene una lista de paquetes necesarios para ejectuar la app.
  • tsconfig.json, contiene la configuración para el compilador de TypeScript.
  • typings.json, indica las definiciones de TypeScript.
  • systemjs.config.js, es la configuración de SystemJS que es un cargador de módulos (otra alternativa es webpack).

Para instalar los paquetes de package.json haremos:

  • $ npm install
  • $ npm run typings install (si la carpeta typings no aparece).

Los comandos de npm útiles son:

  • npm run script-name para ejecutar un comando/script. Los importantes no requieren de run.
  • npm start, inicia el compilador y el servidor a la vez.
  • npm run tsc, ejecuta el compilador de TypeScript.
  • npm run tsc:w, ejecuta el compilador de Typescript en watch mode.
  • npm run lite, ejecuta el servidor.
  • npm run typings, ejecuta la herramienta typings.
  • npm run postinstall, ejecuta la instalación de paquetes y definiciones de TypeScript.

Notes

Organization: All the files of the project are created inside a folder called app.

Para poder importar una clase, ésta primero se ha de expeortar.

TypeScript

Classes:

export class Hero {
  id: number;
  name: string;
}

Assigning an object to a property:

hero: Hero = {
  id: 1,
  name: 'Windstorm'
};

Una propiedad a la que se le asigna un array vacío:

missions: Mission[] = [];

Listas

Encontrar un elemento en una lista:

getHero(id: number) {
  return this.getHeroes()
             .then(heroes => heroes.find(hero => hero.id === id));
}

Recoger unos elementos concretos:

 this.heroService.getHeroes()
      .then(heroes => this.heroes = heroes.slice(1, 5));

Elements

Components

Toda aplicación Angular tiene al menos un componente, el root component, que por convención es llamado AppComponent. Un componente es un bloque de código que controla una parte de la vista. Esta es la estructura básica de uno de ellos:

import { Component } from '@angular/core';
@Component({
  selector: 'my-app',
  template: '<h1>My First Angular 2 App</h1>'
})
export class AppComponent { }

Contiene: (1) imports para hacer referencia a lo que necesita. (2) Decorador @Component para indicar plantillas y propiedades “externas” del componente (metadata que indica como crearlo y usarlo). (3) Su clase.

En el decorador nos encontramos con el selector y la template. El primero es la tag que corresponderá al componente en contreto. El segundo, la template, especifica el HTML que se incrustará cuando tenga que aparecer.

Clase con propiedades

export class AppComponent {
  title = 'Tour of Heroes';
  hero = 'Windstorm';
}

Leer contenido desde la template

Template de una sola línea que lee la propiedad title y la hero:

template: '<h1>{{title}}</h1><h2>{{hero}} details!</h2>'

Template de varias líneas (con el acento a la izquierda):

template:`
  <h1>{{title}}</h1>
  <h2>{{hero.name}} details!</h2>
  <div><label>id: </label>{{hero.id}}</div>
  <div><label>name: </label>{{hero.name}}</div>
  `

Añadir estilos en el componente

El decorador de componente también admite la propiedad styles:

styles: [`
  .selected {
    background-color: #CFD8DC !important;
    color: white;
  }
  .heroes {
    margin: 0 0 2em 0;
    list-style-type: none;
    padding: 0;
    width: 15em;
  }
  .heroes li {
    cursor: pointer;
    position: relative;
    left: 0;
    background-color: #EEE;
    margin: .5em;
    padding: .3em 0;
    height: 1.6em;
    border-radius: 4px;
  }
  .heroes li.selected:hover {
    background-color: #BBD8DC !important;
    color: white;
  }
  .heroes li:hover {
    color: #607D8B;
    background-color: #DDD;
    left: .1em;
  }
  .heroes .text {
    position: relative;
    top: -3px;
  }
  .heroes .badge {
    display: inline-block;
    font-size: small;
    color: white;
    padding: 0.8em 0.7em 0 0.7em;
    background-color: #607D8B;
    line-height: 1em;
    position: relative;
    left: -1px;
    top: -4px;
    height: 1.8em;
    margin-right: .8em;
    border-radius: 4px 0 0 4px;
  }
`]

Añadir propiedades de entrada

Para ello usamos el decorador @Input (que necesitamos importar) sobre la propiedad de la clase:

import { Component, Input } from '@angular/core';
import { Mission } from './mission';
 
@Component({
  selector: 'mission-detail',
  template: `
  <div *ngIf="mission">
  ...
  </div>
`
})
export class MissionDetailComponent {
    @Input()
    mission: Mission;
}

Luego, cuando la queramos usar en una template:

<mission-detail [mission]="selectedMission"></mission-detail>

:!: Recuerda que para que funcione has de incluir el nuevo selector como directiva en la lista de directivas de ese componente:

@Component({
  selector: 'newskid-app',
  template: `
  `,
  styles: [`
`],
 directives: [MissionDetailComponent]
})

Template en fichero

En vez de usar la propiedad template usaremos la propiedad templateUrl:

templateUrl: 'app/dashboard.component.html',

Templates for components

ngFor

Podemos indicar que cuando se haga click en un elemento…

<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
  <span class="badge">{{hero.id}}</span> {{hero.name}}
</li>

… se llame a un método concreto de la clase:

export class AppComponent {
  title = 'Newskid missions';
  missions = MISSIONS;
  selectedMission: Mission;
 
  onSelect(mission: Mission) { 
    this.selectedMission = mission; 
  }
}

ngIf

Si existe el elemento….

<div *ngIf="selectedMission">
  <h2>{{selectedMission.name}} Edition</h2>
  <div><label>id: </label>{{selectedMission.id}}</div>
  <div>
    <label>name: </label><input [(ngModel)]="selectedMission.name" placeholder="name"/>
  </div>
</div>

Bootstrapping

Es importante añadir un finchero main.ts que contenga el bootstrapping de la app:

import { bootstrap }    from '@angular/platform-browser-dynamic';
import { AppComponent } from './app.component';
bootstrap(AppComponent);

Se ha de importar los dos elementos necesarios para lanzar la app:

  1. La función bootstrap.
  2. El componente root de la aplicación.

La función bootstrap viene de platform-browser-dynamic debido a que hay muchas formas de lanzar la app. Una de ellas, por ejemplo, es hacerlo desde el server.

El fichero index.html

Es el fichero que define la página web y que contiene la app. Se declaran las librerías JavaScript necesarias, la configuración para el SystemJS y la tag de la aplicación (en este caso my-app).

<!DOCTYPE html>
<html>
  <head>
    <title>Angular 2 QuickStart</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="styles.css">
    <!-- 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>Loading...</my-app>
  </body>
</html>

Services

Para hacer un servicio, una clase que se pueda instanciar automáticamente en el constructor, añadimos @Injectable() a la clase:

import { Injectable } from '@angular/core';
import { MISSIONS } from './mock-missions';
 
@Injectable()
export class MissionService {
    getMissions () {
        return Promise.resolve(MISSIONS);
    }
}

A partir de ahora puede ser usado en la clase:

@Component({
  selector: 'newskid-app',
  ...
 providers: [MissionService]
})
export class AppComponent implements OnInit {
...
  constructor(private missionService: MissionService) { }

Esto agrega una propiedad a la clase denominada missionService. Fíjate que también hay que añadirlo en el array de providers.

Interfaces

ngOnInit

import { OnInit } from '@angular/core';
 
export class AppComponent implements OnInit {
  ngOnInit() {
  }
}

Promises

Devolver\declarar una promise (función que hace algo en algún momento, que tarda algún tiempo y que, cuando le sale, devuelve algo):

getHeroes() {
  return Promise.resolve(HEROES);
}

Usar lo que devuelve (HEROES es un array):

getHeroes() {
  this.heroService.getHeroes().then(heroes => this.heroes = heroes);
}

Routing

AppComponent únicamente debería manejar la navegación. El objeto router es el encargado de gestionarla y es una combinación del provideRouter, directivas y configuración.

Es necesario tener en el index.html:

<head>
  <base href="/">

Crearemos un fichero app.routes.ts donde añadiremos todas las rutas:

import { provideRouter, RouterConfig }  from '@angular/router';
import { HeroesComponent } from './heroes.component';
 
const routes: RouterConfig = [
  {
    path: 'heroes',
    component: HeroesComponent
  }
];
 
export const appRouterProviders = [
  provideRouter(routes)
];

La RouterConfig es un array de definiciones de ruta. Aquí únicamente tenemos una definición, pero podemos añadir más. Una difinición tiene un path (el path con el que hace match la URL, en este caso /heroes) y un componente (el componente que se crea en esa ruta).

El router ha de ser importado en el bootstrap:

import { bootstrap }    from '@angular/platform-browser-dynamic';
 
import { AppComponent } from './app.component';
import { appRouterProviders } from './app.routes';
 
bootstrap(AppComponent, [
  appRouterProviders
]);

Una de las directivas de router (ROUTER_DIRECTIVES) es <router-outlet>. Si lo añadimos en una template (ejemplo de app.component):

import { Component } from '@angular/core';
import { ROUTER_DIRECTIVES } from '@angular/router';
import { HeroService }     from './hero.service';
@Component({
  selector: 'my-app',
  template: `
    <h1>{{title}}</h1>
    <a [routerLink]="['/heroes']">Heroes</a>
    <router-outlet></router-outlet>
  `,
  directives: [ROUTER_DIRECTIVES],
  providers: [
    HeroService
  ]
})
export class AppComponent {
  title = 'Tour of Heroes';
}

También podemos crear una redirección:

const routes: RouterConfig = [
  {
    path: 'missions',
    component: MissionsComponent
  },
  {
    path: '',
    redirectTo:'/dashboard',
    pathMatch: 'full'
  },
  {
    path: 'dashboard',
    component: DashboardComponent
  }
];

O parametrizar una ruta (por ejemplo /detail/11):

{
  path: 'detail/:id',
  component: HeroDetailComponent
},

Entonces tendremos que recoger el id dentro del componente donde se vaya a leer, para ello leemos de la url en el navegador:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Hero } from './hero';
import { HeroService } from './hero.service';
 
@Component({
  selector: 'my-hero-detail',
  templateUrl: 'app/hero-detail.component.html',
})
export class HeroDetailComponent implements OnInit, OnDestroy {
  hero: Hero;
  sub: any;
 
  constructor(
    private heroService: HeroService,
    private route: ActivatedRoute) {
  }
 
  ngOnInit() {
    this.sub = this.route.params.subscribe(params => {
      let id = +params['id']; /* convert id to int */
      this.heroService.getHero(id)
        .then(hero => this.hero = hero);
    });
  }
 
  ngOnDestroy() {
    this.sub.unsubscribe();
  }
 
  goBack() {
    window.history.back();
  }
}
  1. Necesitamos un observer de la url, para ello accedemos a la ActivatedRoute
  2. Nos aseguramos que nos subscrivimos a la ActivatedRoute en el ngOnInit y que en el ngOnDestroy nos desubscribimos.
  3. Necesitamos agregarlo al constructor
  4. En el ngOnInit nos subscribimos a los params para obtener la id de la ruta actual (ActivateRoute); luego se usará el servicio para obtener ese id concreto.

Http

wiki2/angular/basics.1468577634.txt.gz · Última modificación: 2020/05/09 09:25 (editor externo)