- Angular: Un framework de JavaScript (TypeScript) de código abierto, mantenido por Google, para construir aplicaciones web single-page applications (SPAs) y aplicaciones móviles (con Ionic o NativeScript).
- Componentes (Components): Bloques de construcción fundamentales de una aplicación Angular. Un componente controla una parte de la pantalla (una vista). Están formados por:
- Plantilla (Template): HTML que define la vista.
- Clase (Class): Código TypeScript que define la lógica del componente (propiedades y métodos).
- Metadatos (Metadata): Información adicional sobre el componente (selector, templateUrl, styleUrls, etc.). Se definen con un decorador (
@Component).
- Módulos (Modules): Contenedores de componentes, directivas, pipes y servicios relacionados. Una aplicación Angular tiene al menos un módulo raíz (
AppModule). Los módulos ayudan a organizar la aplicación y a dividirla en funcionalidades. - Plantillas (Templates): HTML con sintaxis especial de Angular para data binding, directivas, etc.
- Data Binding: Mecanismo para sincronizar datos entre la clase del componente y la plantilla.
- Interpolación (
{{ }}): Muestra valores de propiedades del componente en la plantilla. - Property Binding (
[]): Vincula una propiedad de un elemento HTML a una propiedad del componente. - Event Binding (
()): Vincula un evento de un elemento HTML a un método del componente. - Two-way Binding (
[(ngModel)]): Vincula una propiedad del componente a un input de formulario (sincronización bidireccional).
- Interpolación (
- Directivas (Directives): Instrucciones en el DOM que extienden la funcionalidad de HTML.
- Componentes: Directivas con una plantilla.
- Directivas estructurales (
*ngIf,*ngFor,*ngSwitch): Modifican la estructura del DOM (añaden o eliminan elementos). - Directivas de atributo: Cambian la apariencia o el comportamiento de un elemento.
- Servicios (Services): Clases que proporcionan funcionalidades reutilizables en toda la aplicación (ej: acceso a datos, logging, etc.). Se inyectan en los componentes a través de inyección de dependencias.
- Inyección de Dependencias (Dependency Injection - DI): Patrón de diseño que permite a los componentes obtener las dependencias (servicios, etc.) que necesitan sin tener que crearlas ellos mismos. Angular tiene un sistema de DI integrado.
- Routing: Permite la navegación entre diferentes vistas (componentes) de la aplicación.
- Observables (RxJS): Biblioteca para programación reactiva con observables. Los observables son streams de datos asíncronos. Angular usa RxJS extensivamente (ej: para las peticiones HTTP).
- Formularios (Forms): Angular proporciona dos enfoques para crear formularios:
- Template-driven forms: La lógica del formulario se define principalmente en la plantilla.
- Reactive forms: La lógica del formulario se define principalmente en la clase del componente (más flexible y potente).
- Pipes: Transforman datos en la plantilla (formateo de fechas, números, etc.).
-
Instalar Angular CLI (globalmente):
npm install -g @angular/cli
-
Crear un nuevo proyecto:
ng new mi-app
-
Ejecutar la aplicación en modo de desarrollo:
cd mi-app ng serveLa aplicación estará disponible en
http://localhost:4200.
mi-app/
├── src/ # Código fuente de la aplicación
│ ├── app/ # Módulo principal de la aplicación
│ │ ├── app.component.html # Plantilla del componente principal
│ │ ├── app.component.scss # Estilos del componente principal
│ │ ├── app.component.spec.ts # Pruebas del componente principal
│ │ ├── app.component.ts # Clase del componente principal
│ │ └── app.module.ts # Módulo principal
│ ├── assets/ # Archivos estáticos (imágenes, etc.)
│ ├── environments/ # Archivos de entorno (desarrollo, producción, etc.)
│ ├── index.html # Página HTML principal
│ ├── main.ts # Punto de entrada principal
│ ├── styles.scss # Estilos globales
│ └── ...
├── node_modules/
├── angular.json # Configuración de Angular CLI
├── package.json
├── tsconfig.json # Configuración de TypeScript
└── ...
// mi-componente.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-mi-componente', // Selector CSS (cómo se usará el componente en otras plantillas)
templateUrl: './mi-componente.component.html', // Ruta a la plantilla
styleUrls: ['./mi-componente.component.scss'] // Rutas a los archivos de estilos (opcional)
// También se puede usar template y styles:
// template: `<h1>Hola, mundo!</h1>`,
// styles: [`h1 { color: blue; }`]
})
export class MiComponente {
// Propiedades
titulo: string = 'Mi Componente';
contador: number = 0;
// Métodos
incrementarContador() {
this.contador++;
}
}<!-- mi-componente.component.html -->
<h1>{{ titulo }}</h1> <!-- Interpolación -->
<p>Contador: {{ contador }}</p>
<button (click)="incrementarContador()">Incrementar</button> <!-- Event binding -->
<input type="text" [value]="titulo"> <!-- Property binding -->
<input type="text" [(ngModel)]="titulo"> <!-- Two-way binding (necesita FormsModule) -->@Input(): Decorador para definir propiedades que se pueden pasar desde un componente padre.@Output(): Decorador para definir eventos personalizados que el componente puede emitir. Se usan conEventEmitter.- Ciclo de vida de un componente (Lifecycle Hooks):
ngOnChanges(): Se llama cuando cambia el valor de una propiedad@Input().ngOnInit(): Se llama después de que Angular ha inicializado el componente (buen lugar para inicializar datos).ngDoCheck(): Se llama durante cada ciclo de detección de cambios.ngAfterContentInit(),ngAfterContentChecked(),ngAfterViewInit(),ngAfterViewChecked(): Hooks relacionados con el contenido y la vista del componente.ngOnDestroy(): Se llama justo antes de que Angular destruya el componente (buen lugar para limpiar recursos).
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; // Necesario para two-way binding (ngModel)
import { HttpClientModule } from '@angular/common/http'; // Para peticiones HTTP
import { AppComponent } from './app.component';
import { MiComponente } from './mi-componente/mi-componente.component';
// ... otros imports
@NgModule({
declarations: [ // Componentes, directivas y pipes que pertenecen a este módulo
AppComponent,
MiComponente,
// ...
],
imports: [ // Otros módulos que este módulo necesita
BrowserModule,
FormsModule,
HttpClientModule,
// ...
],
providers: [ // Servicios (providers) que estarán disponibles en este módulo
// ...
],
bootstrap: [AppComponent] // Componente raíz (solo en el módulo principal)
})
export class AppModule { }declarations: Componentes, directivas y pipes que pertenecen a este módulo.imports: Otros módulos que este módulo necesita.providers: Servicios (providers) que estarán disponibles en este módulo (y en sus componentes hijos).bootstrap: Componente raíz (solo en el módulo principal -AppModule).exports: Componentes, directivas y pipes que este módulo exporta para que puedan ser usados por otros módulos.- Feature Modules: Módulos que encapsulan una funcionalidad específica.
- Shared Modules: Módulos que contienen componentes, directivas y pipes que se usan en varios módulos.
-
Interpolación (
{{ }}):<p>Hola, {{ nombre }}!</p>
-
Property Binding (
[]):<img [src]="imagenUrl" [alt]="descripcion"> <button [disabled]="estaDeshabilitado">Haz clic</button>
-
Event Binding (
()):<button (click)="manejarClic($event)">Haz clic</button>
-
Two-way Binding (
[(ngModel)]): (RequiereFormsModule)<input type="text" [(ngModel)]="nombre"> <p>Hola, {{ nombre }}!</p>
-
*ngIf: Añade o elimina un elemento del DOM según una condición.<p *ngIf="mostrarMensaje">Este mensaje se mostrará si mostrarMensaje es true.</p>
-
*ngFor: Repite un elemento para cada elemento de una lista.<ul> <li *ngFor="let item of items; let i = index"> {{ i + 1 }} - {{ item.nombre }} </li> </ul>
-
*ngSwitch: Muestra un elemento u otro según el valor de una expresión.<div [ngSwitch]="color"> <p *ngSwitchCase="'red'" style="color: red;">Rojo</p> <p *ngSwitchCase="'green'" style="color: green;">Verde</p> <p *ngSwitchCase="'blue'" style="color: blue;">Azul</p> <p *ngSwitchDefault>Color desconocido</p> </div>
-
ngClass: Añade o elimina clases CSS condicionalmente.<div [ngClass]="{ 'clase-a': condicionA, 'clase-b': condicionB }"></div>
-
ngStyle: Aplica estilos CSS condicionalmente.<div [ngStyle]="{ 'color': color, 'font-size': fontSize + 'px' }"></div>
-
Crear directivas personalizadas:
@Directivedecorator:import { Directive, ElementRef, HostListener } from '@angular/core'; @Directive({ selector: '[appResaltar]' // Selector CSS (como un componente, pero sin plantilla) }) export class ResaltarDirective { constructor(private el: ElementRef) { } @HostListener('mouseenter') onMouseEnter() { this.resaltar('yellow'); } @HostListener('mouseleave') onMouseLeave() { this.resaltar(''); } private resaltar(color: string) { this.el.nativeElement.style.backgroundColor = color; } }
// mi-servicio.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root' // Disponible en toda la aplicación (inyectable a nivel raíz)
// También se puede proporcionar en un módulo específico:
// providedIn: MiModulo
})
export class MiServicio {
datos: string[] = [];
obtenerDatos(): string[] {
return this.datos;
}
agregarDato(dato: string) {
this.datos.push(dato);
}
}// mi-componente.component.ts
import { Component, OnInit } from '@angular/core';
import { MiServicio } from '../mi-servicio.service'; // Importa el servicio
@Component({ ... })
export class MiComponente implements OnInit {
datos: string[] = [];
constructor(private miServicio: MiServicio) { } // Inyecta el servicio
ngOnInit() {
this.datos = this.miServicio.obtenerDatos();
}
agregarDato(dato: string) {
this.miServicio.agregarDato(dato);
}
}@Injectable(): Decorador que indica que una clase puede ser inyectada.providedIn: Especifica dónde estará disponible el servicio ('root', un módulo específico, etc.).
- Inyección en el constructor: Los servicios se inyectan a través del constructor del componente. Angular se encarga de crear las instancias de los servicios y pasarlas al constructor.
-
Configurar las rutas:
// app-routing.module.ts (generalmente se crea automáticamente) import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { HomeComponent } from './home/home.component'; import { AboutComponent } from './about/about.component'; import { NotFoundComponent } from './not-found/not-found.component'; const routes: Routes = [ { path: '', component: HomeComponent }, // Ruta principal { path: 'about', component: AboutComponent }, { path: 'usuarios/:id', component: UserDetailComponent }, // Ruta con parámetro { path: '**', component: NotFoundComponent } // Ruta comodín (para 404) ]; @NgModule({ imports: [RouterModule.forRoot(routes)], // forRoot() para el módulo raíz exports: [RouterModule] }) export class AppRoutingModule { }
-
Importar
AppRoutingModuleenAppModule:// app.module.ts import { AppRoutingModule } from './app-routing.module'; @NgModule({ imports: [ // ... AppRoutingModule ], // ... }) export class AppModule { }
-
Usar
<router-outlet>: Directiva que indica dónde se mostrarán los componentes de las rutas.<!-- app.component.html --> <nav> <a routerLink="/">Inicio</a> <a routerLink="/about">Acerca de</a> </nav> <router-outlet></router-outlet> <!-- Aquí se cargarán los componentes -->
-
Navegación:
-
routerLinkdirective: Para crear enlaces.<a routerLink="/usuarios/123">Ver Usuario 123</a> <a [routerLink]="['/usuarios', userId]">Ver Usuario</a>
-
Routerservice: Para navegación programática.import { Router } from '@angular/router'; constructor(private router: Router) { } navegarAAbout() { this.router.navigate(['/about']); } navegarAUsuario(id: number) { this.router.navigate(['/usuarios', id]); }
-
ActivatedRoute: Para acceder a información sobre la ruta actual (parámetros, query parameters, etc.).
-
-
Importar
HttpClientModuleenAppModule(o en el módulo donde lo vayas a usar). -
Inyectar
HttpClienten tu servicio.// mi-servicio.service.ts import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class MiServicio { private apiUrl = 'https://api.example.com'; constructor(private http: HttpClient) { } obtenerDatos(): Observable<any> { return this.http.get(`${this.apiUrl}/datos`); } crearDato(dato: any): Observable<any> { return this.http.post(`${this.apiUrl}/datos`, dato); } // Otros métodos: put, delete, patch, etc. }
-
Suscribirse a los observables:
// mi-componente.component.ts import { Component, OnInit } from '@angular/core'; import { MiServicio } from '../mi-servicio.service'; @Component({ ... }) export class MiComponente implements OnInit { datos: any[] = []; constructor(private miServicio: MiServicio) { } ngOnInit() { this.miServicio.obtenerDatos().subscribe( (data) => { this.datos = data; }, (error) => { console.error("Error al obtener datos:", error); } ); } }
HttpClientmethods:get(),post(),put(),delete(),patch(),head(),options(). Devuelven observables.- Interceptors: Interceptan las peticiones HTTP y las respuestas (para logging, autenticación, manejo de errores, etc.).
-
Template-driven forms (Formularios basados en plantillas):
- Usa
ngModelpara el two-way binding. - Usa directivas como
ngForm,ngSubmit. - La validación se define principalmente en la plantilla.
<!-- app.component.html --> <form #miFormulario="ngForm" (ngSubmit)="onSubmit(miFormulario)"> <label for="nombre">Nombre:</label> <input type="text" id="nombre" name="nombre" [(ngModel)]="modelo.nombre" required> <div *ngIf="miFormulario.submitted && miFormulario.controls['nombre']?.invalid"> El nombre es obligatorio. </div> <label for="email">Email:</label> <input type="email" id="email" name="email" [(ngModel)]="modelo.email" required email> <div *ngIf="miFormulario.submitted && miFormulario.controls['email']?.invalid"> <div *ngIf="miFormulario.controls['email']?.errors?.['required']"> El email es obligatorio </div> <div *ngIf="miFormulario.controls['email']?.errors?.['email']"> Email inválido </div> </div> <button type="submit">Enviar</button> </form>
// app.component.ts import { Component } from '@angular/core'; import { NgForm } from '@angular/forms'; @Component({...}) export class AppComponent { modelo: any = {}; onSubmit(form: NgForm) { if (form.valid) { console.log("Formulario válido. Datos:", this.modelo); // Enviar datos al servidor... } } }
- Usa
-
Reactive forms (Formularios reactivos): (Recomendado para formularios complejos)
- Importar
ReactiveFormsModuleen tu módulo. - Usa
FormGroup,FormControl,FormArray,FormBuilder. - La validación se define en la clase del componente.
// app.component.ts import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators, FormControl, FormArray } from '@angular/forms'; @Component({...}) export class AppComponent implements OnInit { miFormulario: FormGroup; constructor(private fb: FormBuilder) { } // Inyecta FormBuilder ngOnInit() { this.miFormulario = this.fb.group({ nombre: ['', [Validators.required, Validators.minLength(3)]], // FormControl con validadores email: ['', [Validators.required, Validators.email]], hobbies: this.fb.array([]), // FormArray (para campos repetidos) }); //También se puede usar new FormControl, new FormGroup y new FormArray. } onSubmit() { if (this.miFormulario.valid) { console.log("Formulario válido. Datos:", this.miFormulario.value); // Enviar datos al servidor... } } get nombre() { return this.miFormulario.get('nombre'); } // Getter para acceder fácilmente al FormControl get email() { return this.miFormulario.get('email'); } get hobbies() { return this.miFormulario.get('hobbies') as FormArray; } agregarHobby() { this.hobbies.push(new FormControl('')); //Añade dinámicamente FormControls } }
<!-- app.component.html --> <form [formGroup]="miFormulario" (ngSubmit)="onSubmit()"> <label for="nombre">Nombre:</label> <input type="text" id="nombre" formControlName="nombre"> <div *ngIf="nombre?.invalid && (nombre?.dirty || nombre?.touched)"> <div *ngIf="nombre?.errors?.['required']">El nombre es obligatorio.</div> <div *ngIf="nombre?.errors?.['minlength']">El nombre debe tener al menos 3 caracteres.</div> </div> <label for="email">Email:</label> <input type="email" id="email" formControlName="email"> <div formArrayName="hobbies"> <div *ngFor="let hobby of hobbies.controls; let i=index"> <input type="text" [formControlName]="i"> </div> </div> <button type="button" (click)="agregarHobby()">Añadir hobby</button> <button type="submit">Enviar</button> </form>
- Importar
TestBed: Utilidad principal para configurar el entorno de pruebas de Angular.ComponentFixture: Wrapper para un componente, que proporciona acceso a la instancia del componente, al DOM, etc.jasmine: Framework de testing BDD (Behavior-Driven Development) usado por defecto en Angular.karma: Test runner usado por defecto en Angular.ng test: Comando de Angular CLI para ejecutar las pruebas.async/fakeAsync/tick: Para pruebas asíncronas.- Spies: Para simular el comportamiento de dependencias.
-
Transforman datos en la plantilla.
<p>Fecha: {{ fecha | date:'dd/MM/yyyy' }}</p> <p>Precio: {{ precio | currency:'EUR' }}</p> <p>{{ mensaje | uppercase }}</p>
-
Pipes incorporados:
date,currency,uppercase,lowercase,number,percent,json,slice,async, etc. -
Crear pipes personalizados:
-
@Pipedecorator. -
transform()method.import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'miPipePersonalizado' }) export class MiPipePersonalizado implements PipeTransform { transform(valor: string, arg1: string, arg2: number): string { // ... lógica de transformación return valor.toUpperCase() + arg1 + arg2; } }
-
- RxJS (Observables): Programación reactiva con observables. Muy importante en Angular.
- Change Detection: Mecanismo de Angular para detectar cambios en los datos y actualizar la UI.
ChangeDetectorRef: Para controlar manualmente la detección de cambios.OnPush: Estrategia de detección de cambios que mejora el rendimiento (detecta cambios solo cuando cambian las referencias de las propiedades@Input()).
- Content Projection (
<ng-content>): Proyecta contenido desde un componente padre a un componente hijo. - ViewChild y ContentChild: Acceden a elementos del DOM o a componentes hijos.
- Lazy Loading: Carga módulos de forma diferida (solo cuando se necesitan), mejorando el tiempo de carga inicial.
- Internacionalización (i18n): Adapta la aplicación a diferentes idiomas y regiones.
- Angular Universal: Server-side rendering (SSR) para Angular.
- Web Workers: Ejecuta código JavaScript en segundo plano (en un hilo separado).
- Service Workers: Permiten crear aplicaciones web progresivas (PWAs) que funcionan offline.
- Animaciones:
@angular/animations. - Esquemas (Schematics): Angular CLI tiene generadores de código.