1

I need to make template in loading state until the API response is received.

Template

<p>project: {{event.event_title}}
</p>

ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import {ServicesApiCustomerEventService} from "../../services/services-api/services-api-customer/services-api-customer-event.service";
import { Subscription } from 'rxjs/Subscription';

@Component({
  selector: 'app-customer-event',
  templateUrl: './customer-event.component.html',
  styleUrls: ['./customer-event.component.css']
})
export class CustomerEventComponent implements OnInit {

  id: any;
  event: any;
  subscription: Subscription;

  constructor(private route: ActivatedRoute,private eventService: ServicesApiCustomerEventService) {
    this.subscription = this.route.params.subscribe(params => {
      this.id = params['id'];
   });

   this.eventService.getEventById(this.id)
   .subscribe(
     data => {
       const a=data.json();
       this.event=a;
     }
   )
  }

  ngOnInit() {

  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

service

import { Injectable } from '@angular/core';
import {Http,Headers} from "@angular/http";
import 'rxjs/add/operator/map';
import {environment} from "../../../../environments/environment";

@Injectable()
export class ServicesApiCustomerEventService {
    url= `${environment.apiUrl}`;

    constructor(private http: Http) { }

    getEventById(id){
      let headers = new Headers();
      let currentUser = JSON.parse(localStorage.getItem('currentUser'));
      headers.append('Authorization',currentUser.token);
      headers.append("Content-Type", 'application/json')
      return this.http.post(this.url+'/customer/get_event_by_id',{"event_id": id}, {headers: headers})
    }  
}

error

ERROR TypeError: Cannot read property 'event.event_title' of undefined
    at Object.eval [as updateRenderer] (CustomerEventComponent.html:1)
    at Object.debugUpdateRenderer [as updateRenderer] (core.es5.js:13113)
    at checkAndUpdateView (core.es5.js:12260)
    at callViewAction (core.es5.js:12620)
    at execComponentViewsAction (core.es5.js:12552)
    at checkAndUpdateView (core.es5.js:12261)
    at callViewAction (core.es5.js:12620)
    at execEmbeddedViewsAction (core.es5.js:12578)
    at checkAndUpdateView (core.es5.js:12256)
    at callViewAction (core.es5.js:12620)

the issue is, since it takes some time to receive the API response and because of that i'm getting undefined error while loading the template. Can any one help me on this? what are the best practices to do this?

Achira Shamal
  • 527
  • 1
  • 5
  • 18
  • some options: easiest in this case is to initialize `event` as `event = {}` OR use safe navigation operator OR use ngIf OR use async pipe. some reading here: https://stackoverflow.com/questions/34734671/observable-type-error-cannot-read-property-of-undefined :) – AT82 Oct 25 '17 at 07:44
  • yes I get it. But still template may loaded without the data (takes some time) , So it's not good UX. is there any solution for that? – Achira Shamal Oct 25 '17 at 14:01
  • Then you would want a resolver: https://angular.io/guide/router#resolve-guard – AT82 Oct 25 '17 at 14:30

1 Answers1

0

You need to add a resolver to the component route. https://angular.io/api/router/Resolve In your routes it should look like

{ path: PATH.EVENTS_ID, component: CustomerEventComponent, resolve: {event: EventResolverService} }

In your resolver service, something like:

  resolve(route: ActivatedRouteSnapshot): Observable<IEvent> {
    return this.eventService.getEventById(route.params['id']).map((event: IEvent) => event);
  }

In your component: instead of subscribing, just get the data from the request

  ngOnInit() {
    this.event = this.route.snapshot.data['event'];
  }