Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting an observable variable in angular 2

What we want to do is call an endpoint from a url which returns 2 variables which can be used on multiple sections on the site. Although we are using the http call and subscribing to it, in order to speed up the site we only want to make the api call once. In order to do this we have created an Observable on the a service. Service calls a function in the constructor which sets the values of the Observable, however sometimes when visiting a link directly a cannot subscribe to method of undefined is returned. This is using the Microsoft ADAL library example code is below:

Firstly we are setting the variable as an Observable in the service:

@Injectable()
export class MicrosoftGraphService {
  public details: Observable<any>;

Then we are setting the observable values in the constructor:

constructor(
private _http:Http,
private _adalService: AdalService,
private _sanitizer:DomSanitizer
) {

this.getToken().subscribe(token => {
  /**
   * Get me data from graph to determine school_id and mis_id
   */
  this.get('me', token, true).subscribe(me => {
    this.details = new Observable(observer => {
        observer.next({
          me: me
        });
        observer.complete();
    });
  });
});

The getToken function is:

getToken(): Observable<any> {
    return this._adalService
      .acquireToken( this._adalService.config.endpoints.graph );
}

The get function is:

get( endpoint, token, beta = false ): Observable<any>  {
  return this._http.get( this._adalService.config.endpoints.graph + 
    this.getVersion( beta ) + endpoint, {
      headers: new Headers({ "Authorization": "Bearer " + token })
    })
    .map(res => {
      return res.json();
    });
}

This is then called in the constructor of the component as follows:

this._microsoftGraph.details.subscribe(details => {
    console.log(details);
});

This should add a console log of the return of the me endpoint, however on certain pages it does and others it returns a cannot subscribe to undefined. The MicrosoftGraphService is called and set in the constructor on both pages correctly.

I am wondering if this happens because of the way it's called and when it's set e.g. the visiting the base url would call the parent component, as the MicrosoftGraphService is called in that constructor it is initialised first, so is available when visiting the second component through navigation. However going directly to the URL location for the child component might mean it's called first before the parent, even though both load the MicrosoftGraphService.

Example of the routes if it helps:

const routes: Routes = [
{
    path: '',
    component: SiteComponent,
canActivate: [LoggedInGuard],
children: [
    { path: 'dashboard', component: DashboardComponent },
    { path: 'tasks', component: TasksComponent },
    {
      path: '',
      redirectTo: '/dashboard'
      , pathMatch: 'full'
      // , terminal: true
    }
  ]
},
like image 309
user1468867 Avatar asked Apr 20 '17 10:04

user1468867


1 Answers

The problem is that your public details: Observable<any>; is not initialized in the beginning and in the subscription you pass to the getToken() you set it to a new Observable every time by using

this.details = new Observable(observer => {
    observer.next({
      me: me
    });
    observer.complete();
});

Due to this, your components will get different objects when they access the details, depending on the point in time when they access it.

I would suggest to do something like the following in your service:

detailsSubject = new Subject<any>();
public details = this.detailsSubject.asObservable();

// --- in your subscription where you set your Observable before
this.detailsSubject.next(/* here comes your token */);

For further information take a look at this example

like image 127
alex kucksdorf Avatar answered Nov 14 '22 15:11

alex kucksdorf