How can be a function like onElChanged
be implemented, so that this functions gets executed each time properties of <div #plot id="plot-container"></div>
changed?
component.html
<div #plot id="plot-container"></div>
component.ts
@ViewChild('plot') el: ElementRef;
onElChanged(){
console.log(this.el.nativeElement.clientWidth);
}
The Angular @ViewChild decorator is one of the first decorators that you will run into while learning Angular, as it's also one of the most commonly used decorators. This decorator has a lot of features: some of them might not be very well known but they are extremely useful.
ViewChild is used to select an element from component's template while ContentChild is used to select projected content.
The ViewChild or ViewChildren decorators are used to Query and get the reference of the DOM element in the Component. ViewChild returns the first matching element and ViewChildren returns all the matching elements as a QueryList of items. We can use these references to manipulate element properties in the component.
The ViewChild decorator returns the first element that matches a given directive, component, or template reference selector.
Though not a solution that uses @ViewChild decorator, you can use the very similar @ViewChildren
decorator to subscribe to changes despite your particular observed subject being a non-list-like singular element.
You can use the first
(or last
) QueryList
member to obtain the ElementRef
value - ignoring most of the list-specific parts of the QueryList
interface - which is the quick and dirty approach I use below. However, it is probably recommended to handle a singular element iteratively as a list of length 1 to stick with the typical @ViewChildren
paradigm and create more generically useful methods and services.
@ViewChildren('plot', {read: ElementRef}) el: QueryList<ElementRef>;
/**
* Listen within this component
*/
private listenForPlotChanges() {
this.el.changes.subscribe(
(next: QueryList<ElementRef>) => {
console.log('listenForPlotChanges next:', next);
const plot = next.first.nativeElement;
console.log('listentForPlotChanges plot:', plot);
}
);
}
Or an example from a listener that exists outside a component (with special consideration for illustrating an update to the element via Renderer2
)...
import { ElementRef, Injectable, QueryList, Renderer2, RendererFactory2 } from '@angular/core';
import { ISubscription } from 'rxjs/Subscription';
/**
* Listen and update with renderer as a service outside a component
*
* Usage:
* @ViewChildren('yourElement', {read: ElementRef}) el: QueryList<ElementRef>;
*
* constructor(listener: ListenerService) {}
*
* ngAfterViewInit() {
* this.listener.listenForPlotChanges(this.el);
* }
*/
@Injectable()
export class ListenerService {
private renderer: Renderer2;
constructor(rendererFactory: RendererFactory2) {
this.renderer = rendererFactory.createRenderer(null, null);
}
listenForPlotChanges(elementQueryList: QueryList<ElementRef>): ISubscription {
const resolveNext = (next) => {
console.log('listenForPlotChanges next:', next);
const plot = next.first.nativeElement;
console.log('listentForPlotChanges plot:', plot);
this.renderer.addClass(plot, 'twist');
}
return elementQueryList.changes.subscribe(
(next: QueryList<ElementRef>) => {
resolveNext(next);
}
}
}
I've used my suggested approach in Angular version ^5.2.1
and have not verified for other versions of Angular including the latest.
You could create a directive that uses MutationObserver to listen to attribute changes in the DOM for your specific element.
dom-change.directive.ts
import { Directive, ElementRef, EventEmitter, OnDestroy, Output } from '@angular/core';
@Directive({
selector: '[domChange]'
})
export class DomChangeDirective implements OnDestroy {
private changes: MutationObserver;
@Output()
public domChange = new EventEmitter();
constructor(private elementRef: ElementRef) {
const element = this.elementRef.nativeElement;
this.changes = new MutationObserver((mutations: MutationRecord[]) => {
mutations.forEach((mutation: MutationRecord) => this.domChange.emit(mutation));
}
);
this.changes.observe(element, {
attributes: true
});
}
ngOnDestroy(): void {
this.changes.disconnect();
}
}
component.html
<div id="plot-container" (domChange)="onDomChange($event)"></div>
component.ts
onDomChange($event: Event): void {
console.log($event);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With