Component renders before NgOnInit finishes?

I've got a component which performs some calls to a service which calls an api. The component renders before these calls are finished, resulting in an empty page.

This is the code from the component:

import {Component, OnInit, OnDestroy} from '@angular/core';
import {AuthService} from '../services/auth.service';
import {AssignmentService} from '../services/assignment.service';
import {Assignment} from '../models/Assignment';
import {Request} from '../models/Request';
import {MeService} from '../services/me.service';
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
import {Router} from '@angular/router';
import {NavbarService} from '../services/navbar.service';

@Component({
  selector: 'app-newrequest',
  templateUrl: './newrequest.component.html',
  providers: [AssignmentService]
})
export class NewrequestComponent implements OnInit {
  me: MicrosoftGraph.User;
  assignments: Assignment[];
  requests: Request[] = [];
  ready = false;

  constructor(private meService: MeService,
              private authService: AuthService,
              private assignmentService: AssignmentService,
              private router: Router,
              public nav: NavbarService) {
  }

  ngOnInit() {
    this.nav.show();
    this.nav.element = 'newrequests';
    if (localStorage.getItem('loggedin') === 'yes') {
      this.meService.getMe().subscribe(data => {
          this.me = data;
        },
        error => {
          console.log(error);
        },
        () => this.assignmentService.getAssignments().subscribe(data => {
            this.assignments = data;
          },
          error => {
            console.log(error);
          },
          () => {
            this.setRequests();
          }));
    } else {
      this.router.navigate(['']);
    }
  }

  onLogout() {
    this.authService.logout();
  }

  onLogin() {
    this.authService.login();
  }

  private setRequests() {
    this.assignments.forEach(item => {
      if (this.me.mail.toLowerCase() === item.lecturer.toLowerCase()) {
        this.parseRequests(item.request, item.name);
      }
    });

    this.ready = true;
  }

  private parseRequests(toSplit, name) {
    const split = toSplit.split(',');

    split.forEach(item => {
      this.requests.push(new Request(item, name));
    });
  }
}

This is the code from the page:

<app-navbar-component></app-navbar-component>
<div *ngIf="ready">
  <div *ngFor="let request of requests">
    <p class="lead">{{request.user}}</p>
  </div>
</div>

This is the function in my service:

getAssignments() {
    return this.http.get(this.BASE_API_URL + '/assignments').catch(this.onError);
  }

I get no errors. The requests are loaded (checked via console.log). The only problem is that the page renders before the data has finished loading.

Any ideas?

Thanks in advance!

Upvotes: 1

Views: 2259

Answers (2)

John Velasquez
John Velasquez

Reputation: 3451

Have you tried using resolve?

create a resolver name it assignments-details.resolver.ts

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
import {MeService} from '../services/me.service';

@Injectable()
export class AssignmentsDetailsResolver implements Resolve<any> {

  constructor(api: MeService){}

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
   return this.api.getAssignments();
  }

}

Then on your route config do it like this

{
  path: 'your_path',
  component: NewrequestComponent,
  resolve: { AssignmentsDetails: AssignmentsDetailsResolver }
}

Then on your NewrequestComponent make sure you import ActivatedRoute

import { ActivatedRoute } from '@angular/router'

and in your contructor call it like this

 constructor(private meService: MeService,
              private authService: AuthService,
              private assignmentService: AssignmentService,
              private router: Router,
              public nav: NavbarService,
              private activateRoute: ActivatedRoute) {

   this.activateRoute.data.subscribe((response) => {
       //to get the response
       console.log(response.AssignmentsDetails);
     });
  }

And also make sure you register 'AssignmentsDetailsResolver' in the provider property of your module.

Hope this helps you.

Upvotes: 2

Sajeetharan
Sajeetharan

Reputation: 222682

Yes Since the service call is asynchronous, the data does not arrive immediately when the subscribe is called.

But in your code, you are not setting ready variable to be true once the data is arrived. So you don't see any data on page. Set it to true once you get the data

this.me = data;
this.ready =true;

or handle through the safe navigation operator.

Upvotes: 0

Related Questions