Home > Back-end >  Angular: Wait until all child components have rendered before running code
Angular: Wait until all child components have rendered before running code

Time:01-22

I have a directive that's at the top level of the app and queries elements via document.querySelector and hands them to fromEvent. The problem is, that when the code in the directive's ngAfterViewInit runs, the DOM isn't fully rendered yet so the element query returns null.

I could run the code in setTimeout with some arbitrary amount of time, but that doesn't seem like a sustainable, and flexible solution.

Any ideas for how this can be elegantly handled?

Right now, my code looks like some variation of this:

ngAfterViewInit() {
  const trackedEl = document.querySelector('#myInput');
  const input$ = fromEvent(trackedEl, 'input')
    .pipe(
      map((inputEvent: any) => inputEvent.target.value)
    )
    .subscribe((v) => {
      console.log(`Got to the observable:: ${v}`, count  );
    })
}

CodePudding user response:

I think your best approach here would be to use something like a ViewChild.

So assuming your querySelector targets an <input> tag your html would be like (note the #myInput decorator):

<input #myInput ....>

Your .ts file would be:

 @ViewChild('myInput', { static: true })
  input?: ElementRef<HTMLElement>;

Then because we only want to resolve the event when it is subscribed to:

const input$ = defer(() => fromEvent(this.input, 'input').pipe(
      map((inputEvent: any) => inputEvent.target.value)
    )
    .subscribe((v) => {
      console.log(`Got to the observable:: ${v}`, count  );
    });

Something to this affect, but certainly ViewChild being key here.

CodePudding user response:

ngAfterViewInit lifecycle hook that angular calls after it creates all the component's child views. So you have to implement it on the root AppComponent. Then keep an observable into a service or state and just subscribe to it anywhere you wanna check.

root AppComponent:

export class AppComponent implements AfterViewInit {
  title = "Angular App";
  constructor(private data: DataService){}
  ngAfterViewInit() {
    this.data.rendered.next(true);
  }
}

subscribing it anywhere:

export class HighlightDirective {
  constructor(private data: DataService) {
    this.data.rendered.subscribe(rendered => {
     // all components rendered here, write you code
    });
  }
}
  •  Tags:  
  • Related