Con el evento de error ya no es necesario poner ng-template pues si detecta el evento del error se lanza el metodo de imgError() y se carga la imageDefault
Componentes
Todo lo que aprenderás sobre componentes y servicios en Angular
¿Qué son los componentes?
Uso de Inputs
Uso de Outputs
Componente para producto
Ciclo de vida de componentes
ngDestroy and SetInput
Lista de productos
Componentes y Header
Implementando el sideMenu
Comunicación padre e hijo
Servicios
Conociendo los servicios
¿Qué es la inyección de dependencias?
Obteniendo datos de una API
Pipes y Directives
Conociendo los pipes
Construyendo tu propio pipe
Conociendo las directivas
Best practices
Reactividad básica
Guia de estilos de Angular y linters
Despedida
Despedida
No tienes acceso a esta clase
¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera
Nicolas Molina
Así como el decorador @Input
permite el envío de información desde un componente padre hacia un componente hijo, el uso de @Outputs
permite lo contrario.
A partir de la emisión de un evento, el decorador @Output()
permite enviar mensajes desde un componente hijo hacia el padre.
Para esto, se hace uso de la clase EventEmitter
importándola desde @angular/core
, para crear en tu componente una propiedad emisora de eventos.
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-test-name',
templateUrl: './test-name.component.html',
styleUrls: ['./test-name.component.less']
})
export class TestNameComponent {
@Output() message = new EventEmitter<string>();
constructor() { }
}
Decorando la propiedad con el @Output()
y creando una instancia de EventEmitter
podrás emitir un evento de la siguiente manera:
...
emitirEvento() {
this.message.emit('Hola soy Platzi');
}
Llamando al método emit()
de la instancia EventEmitter
, se enviará el valor al componente padre que se encuentre escuchando el evento.
Desde el componente padre, inicializa el componente hijo de la siguiente manera:
<app-test-name>
(message)="recibirMensaje($event)"
</app-test-name>
Se “bindea” la propiedad emisora de eventos con ()
y se le pasa una función que se ejecutará cada vez que emita un evento.
Y en el componente padre:
import { Component } from '@angular/core';
@Component({
selector: 'app-father',
templateUrl: './father.component.html',
styleUrls: ['./father.component.less']
})
export class FatherComponent {
constructor() { }
recibirMensaje(event: Event) {
console.log(event);
}
}
La función recibirMensaje()
posee un parámetro del tipo Event
que contendrá el mensaje del componente hijo.
Contribución creada con los aportes de Kevin Fiorentino.
Aportes 23
Preguntas 13
Con el evento de error ya no es necesario poner ng-template pues si detecta el evento del error se lanza el metodo de imgError() y se carga la imageDefault
El decorador @Output nos permite enviar información desde el componente hijo en dirección al componente padre por medio de un Event Emitter, para declarar un output lo hacemos de la siguiente manera:
@Output miOutput = new EventEmitter();
Si ademas queremos tipear este output para ser mas especificos con la información que vamos a enviar entonces declaramos:
@Output miOutput = new EventEmitter<string>();
Lo siguiente es emitir esa información desde el componente hijo por medio de la función emit() de nuestro EventEmitter declarado, en este caso ‘miOutput’ por lo cual emitimos la información de la forma siguiente:
this.miOutput.emit('mi string proveniente desde componente hijo')
Para recibir esa información desde el componente padre utilizamos el event binding dentro del tag del componente hijo y hacemos referencia al nombre del event emitter del componente hijo, ejemplo:
<componente-hijo (miOutput)="funcionQueRecibeElOutput($event)" ></componente-hijo>
En el componente padre tendremos que recibir la información por medio de una función, en este caso es funcionQueRecibeElOutput($event) donde “$event” es la información que emite el componente hijo, y esta función se encargara de procesar la información que le llegue desde el event emitter
Aqui hay una imagen default
https://www.m2crowd.com/core/i/placeholder.png
La proxima vez, si tan solo pudieras llamar de la misma manera a los componenrtes no seria tan complejo. Me explico, en el 7:54 dices “nuestro componente” y se me explotó el cerebro, si solo dices el componente hijo sería genial. Puede que el aporte sea muy idiota, pero para los que estamos aprendiendo es muy valioso esos pequeños detalles entre tantas ventanas.
Estoy muy contento con el curso, usted explica muy bien.
Creo que lo explico de forma muy complicada sobre todo con eso de strings e imagenes, lo que hizo es esto:
Para pasar información al padre necesitamos dos modulos Output y EventEmitter, lo haremos a traves de un evento creado por nosotros imgLoaded:
import { Component, OnInit, Input, Output, EventEmitter } from ‘@angular/core’;
@Output() loaded = new EventEmitter<string>();
imgLoaded(){
console.log(‘log hijo’)
this.loaded.emit(‘ejemplo string del hijo a padre’);
}
Fijate como usa this.loaded.emit eso es lo que vamos a pasar del hijo al padre
Aqui lo usamos, loaded es un evento nativo de img:
<img width=“200” (load)=“imgLoaded()” (error)=“imgError()” [src]=“img” *ngIf=“img; else elseImg”>
En el componente padre lo recibimos:
<app-img (loaded)=“onLoaded($event)” [img]=“imgParent”></app-img>
Ese evento loaded tambien es nativo de img, por convencion se utiliza $ para eventos:
onLoaded(img: string){
console.log(‘log padre’, img)
}
esta es la ruta del avatar: https://www.w3schools.com/howto/img_avatar.png
– OUTPUTS –
//Importar
import { Output, EventEmitter } from ‘@angular/core’;
//Crear evento
@Output() loaded = new EventEmitter();
imgLoaded() {
console.log(‘loaded’);
//Activar evento
this.loaded.emit();
}
Pasar información del hijo al padre.
Un ejemplo sobre como funciona Output: https://desarrolloweb.com/articulos/emision-eventos-output-angular.html
Los outputs son para pasarle información del hijo al padre.
En el hijo, img.components.ts:
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-img',
templateUrl: './img.component.html',
styleUrls: ['./img.component.scss']
})
export class ImgComponent {
@Input() img: string = ''; //* se comunica con el hijo
@Output() loaded = new EventEmitter<string>(); //* se comunica con el padre
imageDefault = './assets/images/default.png'
imgError() {
this.img = this.imageDefault;
}
imgLoaded() {
console.log('log hijo!');
this.loaded.emit(this.img); //* notificando al padre
}
}
con su html img.component.html:
<img
[src]="img"
alt="imagen chida"
width="200"
*ngIf="img; else elseImg"
(error)="imgError()"
(load)="imgLoaded()"
>
<ng-template #elseImg>
<img [src]="imageDefault" alt="default">
</ng-template>
Recibimos la información y notificación en el padre, app.component.ts:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
imgParent = '';
onLoaded(img: string) {
console.log('log padre!', img); //* img viene del hijo
}
}
y su html, app.component.html:
<input type="text" [(ngModel)]="imgParent">
<app-img (loaded)="onLoaded($event)" [img]="imgParent"></app-img>
Tambien existe la forma de pasar informacion desde el componente hijo hacia el componente padre mediante el uso de el decorador @Output y el EventEmitter.
Para emitir un valor desde el componente hijo que pueda ser escuchado por el componente padre utilizamos el decorador @Output con un EventEmitter que nos va a permitir crear un evento personalizado el cual podremos escuchar desde nuestro componente padre.
para usar @Output = transmitir información del hijo al padre:
primero en el TS del hijo, se importa Output y EventEmitter,
se crea una variable de tipo EventEmmiter<TipoDato>() con decorador Output, en el componente HTML del hijo se adiciona la funcionalidad (load) haciendo referencia a la función que va a realizar el emit.
Por ultimo en el TS del componente hijo se crea la función que va por medio de la variable creada anteriormente a realizar un evento emit(dato a transmitir).
En el componente HTML del padre donde se esta mostrando el HTML del hijo <app-img (loaded)=“onLoaded($event)” [img]=“imgPadre”></app-img> se adiciona la funcionalidad (loaded) en el cual va a ejecutar una función que para obtener la información del componente hijo se realiza por medio de un $event.
En el componente TS del padre se hace la función en este caso onLoaded(img:string) en la cual recibe por parámetro la información y listo puede usarla.
De esta manera logre enviarle al padre las imágenes que se cargaron correctamente y información en caso de que la imagen no se haya cargado correctamente
@Input() src = '';
@Output() loaded = new EventEmitter<object | string>();
imageDefault =
'https://c8.alamy.com/compes/2h1ywt1/producto-defectuoso-resumen-concepto-vector-ilustracion-2h1ywt1.jpg';
imageError = {
isError: false,
src: this.src,
};
errorImage() {
this.imageError.isError = !this.imageError.isError;
this.imageError.src = this.src;
this.src = this.imageDefault;
}
imageLoaded() {
if (this.imageError.isError)
return this.loaded.emit({
message: 'there is an error uploading an image',
error: this.imageError.src,
});
this.loaded.emit(this.src);
}
me perdi con tanta vuelta en padre eh hijo deberia ser mas practico, no entiendo ayuda
Esto fue algo de lo que implementé en mi proyecto de tienda, espero que sea de ayuda para todos.
/*
En este caso, tenemos un componente que registra unos productos seleccionados en
un array de datos seleccionados, lo que se desea es que el componente emita el valor
total para todos los productos seleccionados al componente padre.
*/
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
import { Product } from 'app/shared/product-list/product.model';
import { ProductSelectionService } from 'app/shared/product-list/product-selection.service';
@Component({
selector: 'app-products-basket',
templateUrl: './products-basket.component.html',
styleUrls: ['./products-basket.component.scss']
})
export class ProductsBasketComponent implements OnInit {
selectedProducts: Product[] = [];
/*
Creamos la propiedad con la que se va a emitir el valor total de la canasta
*/
@Output() totalofBasket: EventEmitter<number> = new EventEmitter<number>();
constructor(private productSelectionService: ProductSelectionService) {}
ngOnInit() {
/*
Al iniciar el componente, se van a traer los productos seleccionados
a través del servicio.
*/
this.selectedProducts = this.productSelectionService.getSelectedProducts();
/*
Posteriormente emitir el valor total al iniciar el componente.
*/
this.emitTotalValue();
}
emitTotalValue() {
/*
Aquí se va a emitir el valor total después de ser calculado
*/
const totalValue = this.calculateTotalValue();
this.totalofBasket.emit(totalValue);
}
private calculateTotalValue(): number {
/*
Aquí se calcula el valor total de los productos seleccionados,
cabe mencionar que esta función es privada para este componente
y esta retornando un valor de tipo numero
*/
return this.selectedProducts.reduce((total, product) => total + product.price, 0);
/*
Se calcula seleccionado el precio en la información de cada producto y solamente}
se suman uno a uno
*/
}
}
<!--
En el componente padre al llamar <app-products-basket> o el componente hijo,
hacemos el llamado de la propiedad con valor de la función que va recibir
el evento como parametro a través de $event
-->
<section class="cart">
<app-products-basket (totalofBasket)="totalBasket($event)"></app-products-basket>
</section>
/*
En el .ts del componente padre simplemente se recibe este valor y se
manipula según las necesidades
*/
import { Component } from '@angular/core';
@Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.scss']
})
export class CartComponent {
totalPrice: number = 0;
totalBasket(value: number) {
console.log('El total es de', value);
this.totalPrice = value;
}
}
Quiero compartirles que los OutPut pueden tener un nombre personalizado para ser invocados con el EventBinding, de esta forma puedes usar un nombre distinto al nombre de la propiedad que tiene el decorador @Output. ejemplo:
@Output('loaded')
public imgLoaded: EventEmitter<string> = new EventEmitter<string>();
Dentro de los paréntesis y en comillas simples, se puede escribir el nombre con el que se estará escuchando el evento que emite el componente hijo. De esta forma aunque la propiedad se llame “imgLoaded” en el componente padre se va a escuchar por medio de “loaded”.
<app-img (loaded)="onLoaded()" [img]="imgParent"></app-img>
En Angular, los outputs son eventos que se emiten desde un componente hijo hacia su componente padre. Los outputs se utilizan para notificar al componente padre sobre cambios o acciones realizadas en el componente hijo. Los outputs se declaran en el decorador @Output() del componente hijo y se utilizan en conjunto con los eventos de la plantilla para emitir eventos hacia el componente padre. Los componentes padres pueden escuchar estos eventos y ejecutar acciones en respuesta a ellos, permitiendo una comunicación bidireccional entre los componentes.
En Angular, los @Output()
son una forma de comunicación unidireccional, donde el componente hijo emite un evento y el componente padre lo escucha y reacciona a él.
<aside>
<img src=“https://static.platzi.com/media/achievements/badge-angular-componentes-servicios-75f68ec3-48e0-430e-b7e2-889fad0d1984.png” alt=“https://static.platzi.com/media/achievements/badge-angular-componentes-servicios-75f68ec3-48e0-430e-b7e2-889fad0d1984.png” width=“40px” /> Esto se usa comúnmente para comunicarse desde un componente hijo a su componente padre.
</aside>
Para usar @Output()
, se debe declarar una propiedad de evento en el componente hijo con el decorador @Output()
.
import { Component, EventEmitter, Output } from '@angular/core';
@Component({
selector: 'app-componente-hijo',
template: `
<button (click)="eliminar()">Eliminar</button>
`
})
export class ComponenteHijoComponent {
@Output() eliminado = new EventEmitter();
eliminar() {
this.eliminado.emit();
}
}
En este ejemplo, se define una propiedad de evento eliminado
con el decorador @Output()
. Luego, dentro del método eliminar()
, se emite este evento llamando al método emit()
en la propiedad de evento.
<app-componente-hijo (eliminado)="onEliminar()"></app-componente-hijo>
En el componente padre, se utiliza la directiva (eliminado)="onEliminar()"
para escuchar el evento eliminado
emitido por el componente hijo. En este ejemplo, la función onEliminar()
se ejecutará cada vez que se haga clic en el botón “Eliminar” en el componente hijo.
import { Component } from '@angular/core';
@Component({
selector: 'app-componente-padre',
template: `
<app-componente-hijo (eliminado)="onEliminar()"></app-componente-hijo>
`
})
export class ComponentePadreComponent {
onEliminar() {
console.log('El componente hijo emitió el evento de eliminación');
}
}
Con tanto img por aquí y por allá me cuesta muchísimo seguir la clase, tanto nombrar que si componente padre/hijo y dar vueltas para un lado y para otro me pierdo todo el rato. Me da la sensación que estaría mucho mejor si solo se explicara de primeras qué hace Input y Output y nos explicaran con un ejemplo un poco más realista sin tanto rodeo.
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?