Maksim Koronchik
Maksim Koronchik

Reputation: 107

Perform GET request before component initialization

I have template code like this:

 <li *ngIf="isRoot() || isSoftware()">

Also i have this functions in my components code:

isRoot() {
    return this.service.Level == 'Root';
}

isSoftwareOnly() {
    return this.service.ServiceType == 'Software';
}

this.service gets by HTTP request. How can I get request before template starts render? Now isRoot() and isSoftware() always return false, because this.service.Level and this.service.ServiceType are undefined

Upvotes: 3

Views: 1851

Answers (3)

Pierre Mallet
Pierre Mallet

Reputation: 7221

If you have to check before a component initialization, the best way to perform that is Guards mechanism (guide here). To create a guard just create a class implementing CanActivate interface. The canActivate method of your class should return an Observable that tells the router if it can load a route.

So your guard will ensure your GET XHR have returned before activating the route containing your component.

something like ( view doc here )

@Injectable()
class CanActivateCheckServiceState implements CanActivate {
  constructor(private myService: <YourService>) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean>|Promise<boolean>|boolean {
    return this.myService.<yourGetMethod>
         .map(() => return true)
         .catch(() => return false)
  }
}

Then use it in your routing config:

@NgModule({
  imports: [
    RouterModule.forRoot([
      {
        path: '<yourPath>',
        component: <yourComponent>,
        canActivate: [CanActivateCheckServiceState]
      }
    ])
  ],
  providers: [CanActivateCheckServiceState, <yourService>]
})
class YourModule {}

Upvotes: 1

Maciej Treder
Maciej Treder

Reputation: 12350

I see three ways:

First (quickest): Use constructor of your component (let's say that you have fetchData method in your service to make an http request:

 export class Component {
     constructor(private service: MyService) {
          this.service.fetchData();
     }
 }

Second (slower): Use ngOnInit hook - data will be fetched in the same moment when initialization of view starts.

Third: Use ngOnChanges lifecycle hook (in my opinion this is not best practice in your usecase) - according to documentation:

Respond when Angular (re)sets data-bound input properties. The method receives a SimpleChanges object of current and previous property values. Called before ngOnInit() and whenever one or more data-bound input properties change.

More about lifecycle hooks in Angular.

Upvotes: 1

Boris Lobanov
Boris Lobanov

Reputation: 2454

You can wrap you entire template in an ng-container and have a flag in your component that is set to true once the data has loaded:

export class MyComponent {
   dataHasLoaded: boolean = false;

   ngOnInit() {
       this.loadData();
   }

   loadData() {
   // send http-request
   this.httpService.getData().subscribe(() => {
       this.dataHasLoaded = true;
   })

In your template:

<ng-container *ngIf="dataHasLoaded">
    <!-- the rest of your HTML -->
</ng-container>

This way you html will only start rendering once you have your data.

Upvotes: 0

Related Questions