简体   繁体   中英

How do I access the scope of a constructor wraping an angular2 observable?

I have the following code:

import { Injectable }     from '@angular/core';
import { Http, Response, Headers, RequestOptions, URLSearchParams } from '@angular/http';
import { Observable } from "rxjs/Observable";
import { Document } from "../api-objects/document";
import { ErrorService } from "../error/error.service";

@Injectable()
export class QuestionsService {
  private questionsUrl = '/api/questions';  // URL to web API
  headers= new Headers({
    'Content-Type': 'application/vnd.api+json',
    'Accept': 'application/vnd.api+json' });
  public newQnsCount: Observable<number>;
  private time:Date;

  constructor (
    private http: Http,
    private errorService:ErrorService
  ) {
      var self = this;
      this.newQnsCount = new Observable(
        (observable) => {
          //configure parameters
          let params = new URLSearchParams();
          //add filter options to query
          params.set("filters", JSON.stringify([{
              name: "date",
              op: "gt",
              val: self.getTime().toISOString()
            }]));
          //add functions[query] to query
          params.set("functions", JSON.stringify([{
              name: "count",
              field: "id"
            }]));
          //to prevent returning from cache
          params.set("rand", Math.random()+"");
          //create options
          var options = new RequestOptions({
            headers:self.headers,
            search: params
          });
          //create the http observable
          var resp = self.http.get(self.questionsUrl, options)
            .map(self.extractData)
            .catch(self.handleError);
          //create an interval that monitors the number of new questions
          let interval = setInterval(() => {
            resp.subscribe(
              //return the count of new questions since the last get time
              data => {observable.next(data[0])},
              //handle errors
              (error) => {
                self.errorService.handle401(error);
                observable.onError(error);
              }
            )
          });
          //return the observable's destroyer function
          return () => {clearInterval(interval);}
        }
      );
  }

  getTime():Date{
    return this.time;
  }

  addQuestion(question:Document):Observable<Document>{
    let body = JSON.stringify(question);
    let options = new RequestOptions({headers:this.headers});

    var resp = this.http.post(this.questionsUrl, body, options)
      .map(this.extractData)
      .catch(this.handleError);
    resp.subscribe(()=>{}, error => this.errorService.handle401(error));
    return resp;
  }

  getQuestions():Observable<Document>{
    let params = new URLSearchParams();
    //to prevent returning from cache
    params.set("rand", Math.random()+"");
    //create options
    var options = new RequestOptions({
      headers: this.headers,
      search: params
    });
    this.time = new Date();
    return  this.http.get(this.questionsUrl, options)
      .map(this.extractData)
      .catch(this.handleError);
  }

  private extractData(res: Response):Document {
    let body = res.json();
    return body || { };
  }

  private handleError (error: any):Observable<Document>{
    // In a real world app, we might use a remote logging infrastructure
    // We'd also dig deeper into the error to get a better message
    let errMsg = (error.message) ? error.message :
      error.status ? `${error.status} - ${error.statusText}` : 'Server error';
    return Observable.throw(error.json());
  }
}

I can't seem to access the scope of the QuestionsService from within the observable creation function. This problem, however, seems to affect the the getTime() function as the resulting error message is:

EXCEPTION: Error: Uncaught (in promise): EXCEPTION: Error in :0:0
ORIGINAL EXCEPTION: TypeError: self.time is undefined
ORIGINAL STACKTRACE:
QuestionsService/this.newQnsCount<@http://localhost:5000/client-app/app/shared/questions/questions.service.js:31:21
Observable.prototype.subscribe@http://localhost:5000/client-app/node_modules/rxjs/Observable.js:52:57
DashboardComponent@http://localhost:5000/client-app/app/components/dashboard/dashboard.component.js:21:9
anonymous/_View_DashboardComponent_Host0.prototype.createInternal@DashboardComponent_Host.template.js:13:34
AppView.prototype.create@http://localhost:5000/client-app/node_modules/@angular/core/src/linker/view.js:66:16
DebugAppView.prototype.create@http://localhost:5000/client-app/node_modules/@angular/core/src/linker/view.js:259:20
ComponentFactory.prototype.create@http://localhost:5000/client-app/node_modules/@angular/core/src/linker/component_factory.js:143:27
ViewContainerRef_.prototype.createComponent@http://localhost:5000/client-app/node_modules/@angular/core/src/linker/view_container_ref.js:108:28
DynamicComponentLoader_.prototype.loadNextToLocation/<@http://localhost:5000/client-app/node_modules/@angular/core/src/linker/dynamic_component_loader.js:45:20
Zone</ZoneDelegate</ZoneDelegate.prototype.invoke@http://localhost:5000/client-app/node_modules/zone.js/dist/zone.js:323:20
NgZoneImpl/this.inner<.onInvoke@http://localhost:5000/client-app/node_modules/@angular/core/src/zone/ng_zone_impl.js:45:32
Zone</ZoneDelegate</ZoneDelegate.prototype.invoke@http://localhost:5000/client-app/node_modules/zone.js/dist/zone.js:322:20
Zone</Zone</Zone.prototype.run@http://localhost:5000/client-app/node_modules/zone.js/dist/zone.js:216:25
scheduleResolveOrReject/<@http://localhost:5000/client-app/node_modules/zone.js/dist/zone.js:571:53
Zone</ZoneDelegate</ZoneDelegate.prototype.invokeTask@http://localhost:5000/client-app/node_modules/zone.js/dist/zone.js:356:24
NgZoneImpl/this.inner<.onInvokeTask@http://localhost:5000/client-app/node_modules/@angular/core/src/zone/ng_zone_impl.js:36:32
Zone</ZoneDelegate</ZoneDelegate.prototype.invokeTask@http://localhost:5000/client-app/node_modules/zone.js/dist/zone.js:355:24
Zone</Zone</Zone.prototype.runTask@http://localhost:5000/client-app/node_modules/zone.js/dist/zone.js:256:29
drainMicroTaskQueue@http://localhost:5000/client-app/node_modules/zone.js/dist/zone.js:474:26
ZoneTask/this.invoke@http://localhost:5000/client-app/node_modules/zone.js/dist/zone.js:426:22

ERROR CONTEXT:
[object Object]

I included the self variable to try and fix the problem but I get the same error. Any help would be greatly appreciated.

Use arrow function => like

.map((data) => this.extractData(data))

instead of

.map(this.extractData)

otherwise the scope of this is not preserved.

No need for self .

Move let self = this; outside constructor

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM