0

I have a service as UserService which gets data on its constructor function, it then populates its property of _userData through a promise, here is the service :

    @Injectable()
    export class UserService {
      private _userData: GrcUser = null;


      constructor(private logger: LogService, private http: Http, private noteService: NotificationsService) {
        logger.trace('UserService Created');
        this.getUserInfo() ;
    }
      public getUserInfo() {
        let userID: string = this.getCookieValue('grcUserId');
        let headers = new Headers({ 'X-West-session-token': this.getCookieValue("grcSessionToken") });
        if (userID) {
          this.http.get(AppConstants.USER_URL + "userInfo/" + userID, { headers: headers })
            .map((res: Response) => res.json())
            .toPromise()
            .then((data: GrcUser) => {
             this._userData = data;
            if (!data) {
            this.noteService.add(new Note('danger', 'Failed to load user 
           details'));
              }
            })
            .catch((err: any) => {
              this.logger.error(err);
              this.noteService.add(new Note('danger', 'Error while getting user details'));
              Promise.resolve();
            });
        } else {
          this.noteService.add(new Note('danger', 'You are not logged in. Please log in and try again'));
    }
  }

Now , I want to get userData in another component, this is how I tried :

export class WorkflowDisplayComponent implements OnInit {
  userData: GrcUser;

  constructor(private _userService: UserService,) {


  }
  ngOnInit(): void {
   this.userData = this._userService.userData;
  }
}

now I understand why this doesn't work as , I am not wating until the promise returns _userData in the user Service. I read some on Observable but I am not quite sure if I want to use them and how exactly I can use them in this scenario.

Seems like I would have to change my getUserInfo function in my userService if I want to use Observables

Is there a better way I can do this , without refactoring my code too much

4

1 回答 1

1

You shouldn't convert the http observable to toPromise(). In this scenario, you've to multicast your http observable and cache it in your service.

    @Injectable()
    export class UserService {
      private _userData: GrcUser = null;
      private httpObservable: Observable;

      constructor(private logger: LogService, private http: Http, private noteService: NotificationsService) {
        logger.trace('UserService Created');
        this.getUserInfo() ;
    }
      public getUserInfo() {
        let userID: string = this.getCookieValue('grcUserId');
        let headers = new Headers({ 'X-West-session-token': this.getCookieValue("grcSessionToken") });
        if (userID) {
         if(this.httpObservable){
             return this.httpObservable;
         } else if(this._userData){
            return Observable.of(this._userData);
         } else {
         this.httpObservable = this.http.get(AppConstants.USER_URL + "userInfo/" + userID, { headers: headers })
            .map((res: Response) => res.json())
            .do((data: GrcUser) => {
             this._userData = data;
            if (!data) {
            this.noteService.add(new Note('danger', 'Failed to load user 
           details'));
              }

            }).catch( (err: any) => {
              this.logger.error(err);
              this.noteService.add(new Note('danger', 'Error while getting user details'));
              return Observable.of(false);
            }).share();
            return this.httpObservable;
           }
        } else {
          this.noteService.add(new Note('danger', 'You are not logged in. Please log in and try again'));
          return return Observable.of(false);
    }
  }

Here in the code, please notice the .share() method. This will multicast your observable. In any of your other components:

export class WorkflowDisplayComponent implements OnInit {
  userData: GrcUser;

  constructor(private _userService: UserService,) {
  }
  ngOnInit(): void {
   this._userService.getUserInfo()
                   .subscribe((userData: any) => {
                       if(userData !== false) {
                          this.userData = userData;
                       }
                    });
  }
}

This way, you're only making one http call and caching it in the service and all the subsequent calls will be served from the stored variable of the service.

于 2017-10-10T17:17:12.233 回答