Tabla de Contenidos

3. Creación de componentes

En este tema vamos a crear nuevo componentes de Angular

Crear tu nuevo componente botón

Vamos a crear nosotros un nuevo componente boton.

Para ello vamos a crear los 3 ficheros que necesitas todo componente:

Los 3 ficheros los crearás dentro de la carpeta src/app/components/ui

src/
 └─ minecraft/
     └─ components/            
         ├─ ui/
         │   ├─ boton/
         │   │   ├─ boton.ts
         │   │   ├─ boton.html
         │   │   └─ boton.scss
         │   └─ panel/
         └─ paginas/
             ├─ minecraft-main/
             │   ├─ minecraft-main.ts
             │   ├─ minecraft-main.html
             │   └─ minecraft-main.scss
             └─ productos/
                 ├─ productos.ts
                 ├─ productos.html
                 └─ productos.scss

El contenido de cada uno de ellos será:

import { Component  } from '@angular/core';
import {CommonModule} from '@angular/common';

@Component({
  selector: 'boton',
  imports: [CommonModule],
  templateUrl: './boton.html',
  styleUrl: './boton.scss'
})
export class Boton  {

}

La parte más importante es el objeto que se le pasa al decocador @Componente. Veamos sus propiedades:

<button class="boton">Aceptar</button>

.boton {
  font-family: sans-serif;
  font-size: 16px;
  padding: 6px;

  border-radius: 6px;
  border-width: 1px;
  border-style: solid;

  display: inline-block;
  cursor: pointer;
  text-decoration: none;


  border-color: #0056b8;
  background-color: #0056b8;
  color: #ffffff;
}

Usando un componente

Como ya hicimos en el tema anterior, hay que importarlo en el .ts donde quedamos usarlo y añadirlo al array de imports.

Primero lo importamos en el app.ts.

Primero lo importamos en el app.ts.

import { Component, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import {MatButtonModule} from '@angular/material/button';
import { Boton } from './shared/ui/boton/boton';
 
@Component({
  selector: 'app-root',
  imports: [RouterOutlet, MatButtonModule,Boton],
  templateUrl: './app.html',
  styleUrl: './app.scss'
})
export class App {
  protected readonly title = signal('EjemploComponentesAngular');
 
 
 
}

Y ahora ya podemos usar la etiquetya <boton></boton> en el app.html

<style>
</style>
  
<h1 >Hola mundo</h1>
  
<button matButton="filled">
  Aceptar
</button>

<br>
<br>

<boton></boton>
  
<router-outlet />

Contenido de la etiqueta

Nuestros botones es muy pobre porque no permite indicar el texto del botón. Para poder hacerlo simplemente hay que usar la etiqueta <ng-content></ng-content> en el boton.html

<button class="boton">
  <ng-content></ng-content>
</button>

Y ahora ya podremos cambiar el texto:

<style>
</style>
  
<h1 >Hola mundo</h1>
  
<button matButton="filled">
  Aceptar
</button>

<br>
<br>

<boton>Hola mundo</boton>
  
<router-outlet />

Personalizar del componente

Vamos ahora añadir atributos a nuestro componente para poder personalizarlo. Para ello vamos a añadir propiedades a la clase TypeScript del componente con el decorador Input()

Nuestro objetivo es poder hacer lo siguiente:

<boton [backgroundColor]="'#FF0000'" [color]="'#00FF00'">Hola mundo</boton>

Lo primero es añadir las propiedades backgroundColor y color a la clase Boton.

import { Component, Input } from '@angular/core';
import {CommonModule} from '@angular/common';

@Component({
  selector: 'boton',
  imports: [CommonModule],
  templateUrl: './boton.html',
  styleUrl: './boton.scss'
})
export class Boton  {
  @Input() backgroundColor: string = '#0B5CD5';
  @Input() color: string = '#F5F7FF';
}

Para usarlas en el boton.html hay 3 formas distintas:

<button class="boton" style="color:{{color}};background-color:{{backgroundColor}}">
  <ng-content></ng-content>
</button>

<button class="boton" [style.color]="color" [style.backgroundColor]="backgroundColor">
  <ng-content></ng-content>
</button>

<button class="boton" [ngStyle]="{'color': color, 'background-color': backgroundColor}">
  <ng-content></ng-content>
</button>

<button class="boton" [ngClass]="[colorClass, backgroundClass]">
  <ng-content></ng-content>
</button>

<button class="boton color--{{color}} background--{{backgroundColor}}">
  <ng-content></ng-content>
</button>

<button class="boton" [ngClass]="['color--'+color, 'background--'+backgroundColor]">
  <ng-content></ng-content>
</button>

Pero en ese caso hay que limitar los posibles valores, definir las clases, relacionarlas con las propiedades TypeScript. Esto lo veremos en el siguiente apartado.

Limitando los valores

En el apartado anterior hemos visto como definir los colores de los botones pero como vimos en el primer tema, realmente hay únicamente unos valores de colores que puede haber

Así que realmente lo que queremos es solo definir la función del botón.De forma que se use de la siguiente manera:

<boton [funcion]="'peligrosa'">Hola mundo</boton>

import {Component, Input} from '@angular/core';
import {CommonModule} from '@angular/common';

@Component({
  selector: 'boton',
  imports: [CommonModule],
  templateUrl: './boton.html',
  styleUrl: './boton.scss'
})
export class Boton  {
  @Input() funcion:'normal' | 'alternativa' | 'peligrosa'='normal';

}

.boton {
  font-family: sans-serif;
  font-size: 16px;
  padding: 6px;

  border-radius: 6px;
  border-width: 1px;
  border-style: solid;

  display: inline-block;
  cursor: pointer;
  text-decoration: none;


  border-color: #0056b8;
  background-color: #0056b8;
  color: #ffffff;
}

.funcion--normal {
  border-color: #0056b8;
  background-color: #0056b8;
  color: #ffffff;
}

.funcion--alternativa {
  border-color: #ed8936;
  background-color: #ed8936;
  color: #ffffff;
}

.funcion--peligrosa {
  border-color: #c53030;
  background-color: #c53030;
  color: #ffffff;
}


<button class="boton funcion--{{funcion}}">
  <ng-content></ng-content>
</button>

Notar el truco de class="funcion–{{funcion}}"

<button class="boton" [ngClass]="['funcion--'+funcion]">
  <ng-content></ng-content>
</button>

Acción de href

Por último vamos a añadir acciones al botón, como el onClick y el href

Para crear el atributo href hay que hacer 3 cambios:

import {Component, Input} from '@angular/core';
import {CommonModule} from '@angular/common';

@Component({
  selector: 'boton',
  imports: [CommonModule],
  templateUrl: './boton.html',
  styleUrl: './boton.scss'
})
export class Boton  {
  @Input() funcion:'normal' | 'alternativa' | 'peligrosa'='normal';
  @Input() href:string="";

}

  <a class="boton funcion--{{funcion}}" [attr.href]="href || null">
    <ng-content></ng-content>
  </a>

Hay que destacar que además de usar ahora href también hemos cambiado la etiqueta a <a>.

Hemos puesto

[attr.href]="href || null"

en vez de simplemente

href={{ href }}

porque si no hay nada en href, no se añadirá el atributo

Acción onClick

Queremos que se ejecute la función alerta() de nuestra aplicación al pulsar en el botón.

import { Component, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router';
 
 
@Component({
  selector: 'app-root',
  imports: [RouterOutlet],
  templateUrl: './app.html',
  styleUrl: './app.scss'
})
export class App {
  protected readonly title = signal('prueba');
 
  alerta() : void {
    alert('Hola mundo');
  }

}

En el HTML lo indicaremos así

<style>
</style>
   
<h1 >Hola mundo</h1>
   
<button matButton="filled">
  Aceptar
</button>
 
<br>
<br>
 
<boton [funcion]="'peligrosa'" (onClick)="alerta()"  >Hola mundo</boton>
   
<router-outlet />

Para ello tenemos que hacer 3 cosas en el botón:

import {Component, EventEmitter, Input, Output} from '@angular/core';
import {CommonModule} from '@angular/common';

@Component({
  selector: 'boton',
  imports: [CommonModule],
  templateUrl: './boton.html',
  styleUrl: './boton.scss'
})
export class Boton  {
  @Input() funcion:'normal' | 'alternativa' | 'peligrosa'='normal';
  @Input() href:string="";
  @Output() onClick = new EventEmitter<void>();

  handleOnClick(): void {
    this.onClick.emit();
  }

}


  <a class="boton funcion--{{funcion}}" [attr.href]="href || null" (click)="handleOnClick()">
    <ng-content></ng-content>
  </a>

Filtros

Angular permite modificar los datos cuando se interpolan en el html.

<p>{{precio | currency}}</p>

<p>{{fechaCompra | date:'shortDate'}}</p>

Los formatos predefinidos de fecha se pueden ver en Pre-defined format options

Ejercicios

Ejercicio 1

Usando el elemento HTML de <progress>.

<label for="file">File progress:</label>

<progress id="file" max="100" value="70">70%</progress>

Crea el componente <progreso>

<progreso  [title]="'File progress:'" [porcentajeRealizado]="70" />

<boton (onClick)="incrementar()">Incrementar 10</boton>

y que muestre:

Añade en la página un botón de forma que al pulsarlo se incremente en 10 el valor.

Para generar los id se usa la librería uuid

npm install uuid
npm install --save-dev @types/uuid

import { v4 as uuidv4 } from 'uuid';

class MiClase{
  uniqueId: string;

  constructor() {
    this.uniqueId =uuidv4();
  }
}

Ejercicio 2

Crea un componente llamado panel que permita hacer los siguientes paneles

Y crea una página HTML donde se vean los paneles.

Ejercicio 3

Crea ahora un componente para crear los siguientes botones:

Importancia
Función Primaria Secundaria Terciaria
Normal
Alternativa
Peligrosa