I need to listen to class name changes on a element being replaced by the <ng-content>
. I have tried many ways and the only way I found for this is by using setInterval
which I think is not a good practice. Suppose I will inject an input
element inside the <app-child>
component
@Component({
selector: 'app-parent',
template: `
<app-child>
<input type="text">
</app-child>
`
})
export class ParentComponent implements OnInit {
ngOnInit() { }
}
And that I want to do something inside child.component.ts
whenever the class
attribute of the input
change:
@Component({
selector: 'app-child',
template: `<ng-content select="input"></ng-content>`
})
export class ChildComponent implements OnInit {
@ContentChild(HTMLInputElement) input: any;
ngOnInit() {
setInterval(() => {
const { className } = this.input.nativeElement;
console.log(className);
}, 500);
}
}
This approach manages to detect the class change but the problem with setInterval
is that that callback will be running on background every 500
milliseconds, is there another way to detect the change?
Note: I've already tried the hook ngAfterContentChecked
which is ran automatically after any change detection but inside I don't have access to the latest change on this.input.nativeElement.className
as if this function was executed before the value was changed.
CodePudding user response:
You can use the MutationObserver Api
Something like this:
ngAfterContentInit(): void {
this.changes = new MutationObserver((mutations: MutationRecord[]) => {
mutations.forEach((mutation: MutationRecord) => {
// this is called twice because the old class is removed and the new added
console.log(
`${mutation.attributeName} changed to ${this.input.nativeElement.classList}`
);
});
});
this.changes.observe(this.input.nativeElement, {
attributeFilter: ['class'],
});
}
Here is a stackblitz with it running https://stackblitz.com/edit/angular-ivy-tz5q88?file=src/app/child.component.ts