Pradip
Pradip

Reputation: 33

Angular5: When angular finished page loading?

In my angular5 application, I am using a table. And data in the table comes from the backend. When the table is fully loaded for the first time, I want to change the scroll position inside the table. For that I am doing this:

ngAfterViewInit() {
    setTimeout(function () {
        const scroller = document.getElementById('list-container');
        scroller.scrollTop = amountTop; // amountTop is the calculated height, which represents the centre of the table 
    }, 500);
}

Is there any better way for DOM manipulation for this instead of using setTimeout() function?

Upvotes: 1

Views: 3407

Answers (2)

Glenn Van Schil
Glenn Van Schil

Reputation: 1099

If you want your page to display when data is loaded, I strongly advices using route resolves. The article shows how to build and implement this, but I'll try to explain this in short.

Instead of loading the data when accessing the component the route resolve will trigger when a certain URL is accessed. This will get the data from your service and add it to the route snapshot data. From your component you can access this data via the ActivatedRoute and your component will only be loaded when the route resolve was successfully.

One thing the article doesn't explain is how to handle exceptions but here's a code snippet so you don't have to show a blank page. I'd recommend looking at this after you've red the article though.

resolve(route: ActivatedRouteSnapshot): Observable<MyObject> {
    return this.myService.getMyObjectById(route.params['id'])
        .map(myObject => {
            return myObject;
        })
        .catch(e => {
            console.error(e);
            return Observable.of([]); // You could return an other object.
            this.router.navigate(['404']); // Or you could redirect to a different page using the @angular/router
        });
}

Update

What this means in your specific case is that you can just call

ngOnInit() {
    this.myList = this.route.snapshot.data['myList']
    const scroller = document.getElementById('list-container');
    scroller.scrollTop = amountTop;
}

Now you're sure your data is present when the ngOnInit method is called because the component is only loaded when the resolve was successfully

Update 2

If you want to load your data in a async way without the route resolves you can solve it like this

ngOnInit() {
    this.myService.getMyObjectByAParameter(myParameter).subscribe(
      myList => {
          this.myList = myList;
          const scroller = document.getElementById('list-container');
          scroller.scrollTop = amountTop;
      }, err => {
          // Handle your exception
      }
  );
}

If you do it like this your component will always be loaded but the scroll will only be set after the data is successfully loaded.

Upvotes: 1

Dhyey
Dhyey

Reputation: 4335

You need to execute the scroll top code on success of your API call in setTimeout with timeout being 0, so that the code is executed after a tick i.e after angular is done with data binding

this.marketService.getBuyOrder(marketId, start, limit)
.subscribe(data => { 
    const buyOrders = data; 
    if (buyOrders.length > 0) { 
        this.bids = this.bids.concat(buyOrders); 
    } else { 
        this.loadMore = false; 
    } 
    this.cd.markForCheck();

    // The timeout is set to 0 to allow angular to bind the array to view
    setTimeout(function () {
        const scroller = document.getElementById('list-container');
        scroller.scrollTop = amountTop;
    }, 0);
}, (err: HttpErrorResponse) => { Helper.handleError(err, this.alertService); });

Upvotes: 3

Related Questions