In my Angular app I have included a child component. This has two fields of the Boolean type. In my parent app, I want to react as soon as the values have changed.
///////////////////////////////////////////////////////
// This ist the CHILD
///////////////////////////////////////////////////////
@Component({
selector: 'critical',
template: `<div ><h1>This is a critical component</h1></div>`,
styles: [`h1 { font-family: Lato; } .blueBorder {border: 1px solid blue;}`],
})
export class CriticalComponent {
error: boolean = false;
warning: boolean = false;
}
///////////////////////////////////////////////////////
// This ist the PARENT
///////////////////////////////////////////////////////
@Component({
selector: 'my-app',
template: '<critical #criticalCmp></critical>',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
@ViewChild('criticalCmp') criticalCmp: CriticalComponent;
one rrorsOrWarningsInCriticalComponent(): void {
// I want to run this method everytime the values in the critical-component changed to
// call services, print logs or do other things here
}
}
How can I achieve this?
To illustrate, I've prepared a StackBlitz here: https://stackblitz.com/edit/angular-ivy-hpn8qy?file=src/app/app.component.ts
CodePudding user response:
You can use a setter, together with an Output I guess.
Parent:
import { Component, ViewChild } from '@angular/core';
import { CriticalComponent } from './critical.component';
@Component({
selector: 'my-app',
template: '<critical #criticalCmp (errorChanged)="errorChanged($event)"></critical>',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
@ViewChild('criticalCmp') criticalCmp: CriticalComponent;
one rrorsOrWarningsInCriticalComponent(): void {
// I want to run this method everytime the values in the critical-component changed to
// call services, print logs or do other things here
}
errorChanged(isError: boolean) {
if(isError){
this.onErrorsOrWarningsInCriticalComponent();
}
}
}
Child:
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'critical',
template: `<div ><h1>This is a critical component</h1></div>`,
styles: [`h1 { font-family: Lato; } .blueBorder {border: 1px solid blue;}`],
})
export class CriticalComponent {
@Output()
errorChanged = new EventEmitter();
set error(val: boolean) {
this._error = val;
this.errorChanged.next(val);
};
get error() {
return this._error;
}
warning: boolean = false;
private _error: boolean = false;
}
Component communication can take place in many ways, you can find good reading from the docs: https://angular.io/guide/component-interaction
CodePudding user response:
If you are interested in a reactive (Observable) approach, I would recommend the following.
Make error
and warning
BehaviorSubject
s, give them the initial value you want:
error = new BehaviorSubject(false);
warning = new BehaviorSubject(false);
Use combineLatest
together with @Output()
to emit whenever values change:
@Output() myBooleans = combineLatest({
error: this.error.asObservable(),
warning: this.warning.asObservable(),
}).pipe(skip(1));
I'm using skip(1)
to disregard the first change (if that is what you want, to not emit the initial values).
The parent listens to this output:
<critical (myBooleans)="onErrorsOrWarningsInCriticalComponent($event)"></critical>
and fires your function when something changes.
And in child, when you want to change either value you can call: this.error.next()
and this.warning.next()
.
I also created an interface for this object, which I always would recommend, to type your data :)
Here is your forked STACKBLITZ with the above solution.