Comunicación de Eventos entre Componentes en Angular
Resumen
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.
Comunicación hijo a padre
A partir de la emisión de un evento, el decorador @Output()permite enviar mensajes desde un componente hijo hacia el padre.
Envío del mensaje
Para esto, se hace uso de la clase EventEmitter importándola desde @angular/core, para crear en tu componente una propiedad emisora de eventos.
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
Tienes toda la razón, buen aporte.
Mmmm de ese modo funciona lo de cargar la imagen por defecto, pero en mis pruebas, hacerlo de esa forma hace que el evento de onloaded no se dispare correctamente dado que más adelante se busca indicarle al componente padre que la imagen se cargó correctamente. Si se hace de la manera que propones el evento onloaded se ejecutará siempre, incluso si hay un error y se carga la imagen por defecto, y este caso ese no es el comportamiento deseado
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 =newEventEmitter();
Si ademas queremos tipear este output para ser mas especificos con la información que vamos a enviar entonces declaramos:
@Output miOutput =newEventEmitter<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:
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
Excelente resumen, gracias.
no son necesarios los paréntesis después del output()?
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)
}
Tu explicación esta bien, pero estaría mejor si el código fuente lo ubicas en cajas usando el botón </>.
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 =newEventEmitter<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:
Hola ! Eso te puede estar sucediendo porque te falta colocar los paréntesis cuando llamas a la función
Ejemplo (de como lo tienes seguramente):
<img width="200px" (load)="imgLoaded" (error)="imgError()" [src]="img" alt="avatar" *ngIf="img; else elseImg" />
Ejemplo de cómo tendría que ser:
<img width="200px" (load)="imgLoaded()" (error)="imgError()" [src]="img" alt="avatar" *ngIf="img; else elseImg" />
La diferencia es que la función imgLoaded() lleva los paréntesis
donde se puede encontrar mas información sobre ese evento error, busque en internet y nada
Hola!
Cuál es el error que quieres encontrar?
Hola !! es un evento que nosotros creamos y después le dimos la funcionalidad que requerimos, que para este caso era activarlo cuando no se presentara la ruta de la imagen.
Uso de Outputs
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']})exportclassImgComponent{@Input() img:string='';//* se comunica con el hijo@Output() loaded =newEventEmitter<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}}
muy bueno el evento (error), me será muy útil de ahora en más 💪🏽
No logre pasar de (error), quizá se mi versión de angular y ya esta desactualizado el curso
¿qué error tienes?, muestra tu código
Se me ocurrió que una buena forma de utilizar el Output sería afectar a los estilos por fuera, pero me topé con que estilar componentes desde el padre es bastante raro.
Por alguna razón, Angular entiende que el componente es ese rectangulito, tuve que utilizar
display: inline-block;
para que tuviera el tamaño real de mi componente, y aún con eso, trata al componente como un elemento a parte de sus hijos, así que si cambio el color de fondo realmente es como una capa debajo del componente. Fue muy confuso para mí 😵💫.
Actualización
Para estilar tu componente en sí debes hacerlo en los estilos del componente en cuestión utilizando el selector :host. Por ejemplo:
el (load) no se ejecuta cuando el loading fue correcto como indica el profe ya que aunque sea una url valida o no igual se ejecuta, hay forma como condicionar que solo se ejecute cuando sea una imagen correcta?
De hecho, lo que dice el profe es verdad (loaded) solo funciona cuando img del componente hijo carga correctamente.
Lo que pasa es que como le asignamos a img la imagen default en caso de que ingreso el usuario no funciona, tecnicamente estamos cargando una imagen correctamente (aunque sea la default), así que por eso se dispara el evento jajaja.
Para evitar este pequeño bug, puedes camibiar el método imgLoaded de el componente hijo de la siguiente manera:
Donde basicamente decimos que la img cargada sea diferente de la default.
pensé que si la imagen era nula/no existiaen internet entonces mostraba la imagen del ng-template. No entiendo por qué el uso del evento (error)=" "
ng-template se ejecutará cuando la variable del if de false, es decir no haya imagen. Pero puede ser que se cargue una imagen que estaba en un servidor en internet y llegue un momento que la borren o no hay conexión con ella, o simplemente hay una errata en la url... es decir el if si que se cumple porque hay una cadena con la url de la imagen... lo que pasa que no es válida por los casos que te he indicado y no se va a cargar la imagen, se ejecutará en ese momento el evento error...
Bueno yo lo entendí así. Espero estar en lo cierto y haberte ayudado si no llegaste a quedarte claro el concepto.
que nombre es que recibe esto, el tipo string dentro de <string>
@Output() loaded = new EventEmitter<string>();
EventEmitter<T> es un módulo que ayuda a compartir datos entre componentes usando los métodos emit() y subscribe() (cabe mencionar que extiende de Subject)
un Output() siempre estará acompañado de un EventEmitter<T> donde <T> es el tipo que le darás (<string>, <number>, <model>). Mismo que debe ser el tipo de lo que se proporcionará a la función emit().
Básicamente. ¿que nombre es que recibe esto, el tipo string dentro de <string>?
-- Es el tipado que le estás dando al EventEmitter. Estás diciendo; éste output() emitirá un valor de tal tipo ( lo que está entre < >)
gracias, Daniel, su nombre es tipo Generic Type<T>
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.
@Output: Es un decorador que nos permite pasar datos entre componentes.
EventEmitter: Es un módulo que ayuda a compartir datos entre componentes usando los métodos emit() y subscribe(). EventEmitter está en la capa Observables, que observa cambios y valores y emite los datos a los componentes suscritos a esa instancia de 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.
cómo pasa el más de una event o variable?
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.