Angular2 http observables - how to work with undefined type

岁酱吖の 提交于 2019-12-22 13:09:42

问题


I am migrating some code from Angular1 to Angular2 and having a few issues. I can open a json response, populate a template, and access data from template ng functions but have not been able to access the data directly from the component class. From what I have read and the error messages seen Angular2 http / observable does not seem to return a pure json object, so I suspect I need to remap it, but not sure how. I believe it should also be possible to drop back to promises using onPromise but have not managed to get that working. I have spent a lot of time googling for solutions, and have tried to implement most of them, but no luck. If anyone can advise on how to remap the response to a usable format or directly access data in the response it would be greatly appreciated.

Example http call from the service :-

getExam() {
    return this._http.get('/json/exam.json')
      .map(data => data.json());
  }

Example subscribe :-

  ngOnInit() {
      this._examsService.getExam()
        .subscribe(response => this.exam = response);
    console.log(this.exam.length);  //this fails
  }

Example console log error :-

TypeError: Cannot read property 'length' of undefined in [null]

Example data structure (very simplified for testing) :-

{"title":"My Practice Exam",
  "questions":[
    {"question":"1+1 = ",
      "answers":[
        {"answer":"2","correct":"Y","selected":"N","iscorrect":""},
        {"answer":"5","correct":"N","selected":"N","iscorrect":""}]},
    {"question":"2+2 = ",
      "answers":[
        {"answer":"4","correct":"Y","selected":"N","iscorrect":""},
        {"answer":"7","correct":"N","selected":"N","iscorrect":""}]},
    {"question":"3+3 = ",
      "answers":[
        {"answer":"6","correct":"Y","selected":"N","iscorrect":""},
        {"answer":"8","correct":"N","selected":"N","iscorrect":""}]}]}

In Angular1 I was able to directly access data from functions - e.g as follows, and would like to do similar in Angular2

if ($scope.myExams[0].questions[q].answers[a].correct == 'y') ...

回答1:


With this code

ngOnInit() {
  this._examsService.getExam()
    .subscribe(response => this.exam = response);
  console.log(this.exam.length);  //this fails
}

the first line sends the request this._examsService.getExam() .subscribe(...) and registers interest in the response, then console.log(this.exam.length) is executed, but at this time respone => this.exam = response hasn't been execute yet, because getExam() is not yet done connecting to the server and receiving the response.

You need to stay in the chain of events to work with the data that is returned eventually, like:

ngOnInit() {
  this._examsService.getExam()
    .subscribe(response => {
      this.exam = response;
      console.log(this.exam.length);  //this shoudn't fail anymore
    });
}

I don't know if this solves your problem but your question doesn't provide enough information about your requirements for a more elaborate solution.




回答2:


I think that the following case is the normal behavior:

ngOnInit() {
  this._examsService.getExam()
    .subscribe(response => this.exam = response);
  console.log(this.exam.length);  //this fails
}

because you try to access the length property on the exam object that will set later and when the response will be there (in the subscribe method).

That said, when an error is thrown within the observable, the map operator isn't called. If you want to transform the error response, you can leverage the catch operator, as described below:

this._examsService.getExam()
    .subscribe(
      // Success
      response => this.exam = response,
      // Failure
      response => {
        // Do something
      });

and the corresponding service code:

getExam() {
  return this.http.get('http://...')
           .map(res = > res.json())
           .catch(res => {
             // If you want to extract the JSON error
             // message from the response
             return Observable.throw(res.json());
           });
}

Otherwise you can also leverage the async pipe to directly set the observable on the component and not do the subscribe:

this.exam = this._examsService.getExam();

and in the associated template

<ul>
  <li *ngFor="#e of exam | async">{{e.name}}</li>
</ul>

Hope it helps you, Thierry



来源:https://stackoverflow.com/questions/34925882/angular2-http-observables-how-to-work-with-undefined-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!