I am trying to get the DOM elements of an angular component through a querySelectorAll method, like this:
const widgetHTMLElements: NodeListOf<ChildNode> = document.querySelectorAll('medium-editor')[0].childNodes[0].childNodes
My first instinct was to put it in the ngAfterViewInit method, but I was soon to realize the DOM was not ready yet, I know so because I've displayed some console.log(s) and I got the following:
What's interesting here is that the NodeList returned has a length zero yet contains some elements, I thought at first it's a mere Chrome console inconsistency, but once I've tried to loop over the object, I'd notice it's not working, so I wonder what's up with angular with that regard...
Anyways, I though it might have to do lifecycle-hooks and went for the ngAfterViewChecked, the good news is that it works fine, I can loop through the returned NodeList and console.log shows something more interesting:
Clearly there's an iteration where the old state of DOM is prevalent, then the first change lets the querySelectorAll return the desired objects.
The thing is ngAfterViewChecked will execute indefinitely, so I thought I might establish some boolean flag which sets to true once the length of querySelectorAll changes or something; I just don't want to ngAfterViewChecked to continue eating resources while the page is mostly idle, but I don't want to miss significant changes either.
My question is about whether there exists some Design pattern to limit performance issues with ngAfterViewChecked, if so, what does it look like?
CodePudding user response:
Ideally, it should have DOM populated after ngAfterViewInit
method is called. I'm not sure, whether the DOM you're keeping eye on is populated based on async
API call.
The reason behind ngAfterViewChecked
is called after default change detector has completed checking a component's view for changes. Rather than using document.querySelectorAll
, I would recommend you to use ViewChildren
.
// I'm assuming below `menu-editor` is component selector
@ViewChildren('medium-editor') mediumEditors: QueryList<MenuEditorComponent>;
ngAfterViewInit() {
this.mediumEditors.changes.subscribe((mediumEditors) => {
console.log('mediumEditors', mediumEditors);
// use nativeElement property of each item to access DOM
mediumEditors.forEach(i => console.log(i.nativeElement));
});
}
Over here you can keep eye on menuEditors
DOM element, in an angular way. Any changes in menu-editor
's element addition/removal will be emitted inside change
subscription.