How to track tree DOM changes without reloading the page? Angular

54 Views Asked by At

I need your help. I have a small piece of code with which I am trying to implement the following logic - I have a menu list. If I have the root role, do not delete anything, but if the non-root role has changed, then delete the item of menu. Now my logic works, but only after reloading the page. Had the role of root, changed to another and the element is deleted only after reloading the page. ChangeDetectorRef, MutationObserver and applicationRef.tick() did not help me unfortunately. Please tell me how can I track it or do deletes and adds along with its result without rebooting? Thank you very much

@ViewChildren('menuItems') menuElements: QueryList<ElementRef>;

ngAfterViewInit() {
    let menuArrayElements = this.menuElements.toArray();
    let element = menuArrayElements.find((el) => el.nativeElement.innerText === 'Platform setup');
    if (this.role !== 'root') {
        element.nativeElement.parentNode.removeChild(element.nativeElement);
    }

    const observer = new MutationObserver(list => {
        console.log(list)
    })
    observer.observe(element.nativeElement, { childList: true, subtree: true });
}
1

There are 1 best solutions below

0
alexdefender93 On

I'd suggest using Angular tools except for calling the DOM API. I mean you're not supposed to use removeChild directly in the Angular app. Instead, I suggest using the binding. For example, you could write in component:

private role$ = new BehaviorSubject('root');  // should be updated when the role changes

private menuItems$ = [{
   name: 'first link',
   href: '/first',
   rootOnly: false
}, {
   name: 'second link',
   href: '/second',
   rootOnly: true
}];

// an observable that removes menu item when the role changes
menuItemsProtected$ = combineLatest([this.role$, this.menuItems$]).pipe(
  map(([role, items]) => {
    if (role === 'root') {
      return items;
    }
    return items.filter((e) => !e.rootOnly);
  })
);

Then in your template:

<ul *ngFor="let item of menuItemsProtected$ | async">
  <li>
    <a [routerLink]="item.href">
      {{item.name}}
    </a>
  </li>
</ul>

Now you just need to implement role$ as a BehaviorSubject (for example), see more details here https://www.learnrxjs.io/learn-rxjs/subjects/behaviorsubject