Angular2 http observables - 如何使用未定义的类型

Posted

技术标签:

【中文标题】Angular2 http observables - 如何使用未定义的类型【英文标题】:Angular2 http observables - how to work with undefined type 【发布时间】:2016-04-27 19:46:46 【问题描述】:

我正在将一些代码从 Angular1 迁移到 Angular2 并遇到一些问题。我可以打开 json 响应、填充模板并从模板 ng 函数访问数据,但无法直接从组件类访问数据。从我读过的内容和看到的错误消息来看,Angular2 http / observable 似乎没有返回纯 json 对象,所以我怀疑我需要重新映射它,但不确定如何。我相信也应该可以使用 onPromise 退回到承诺,但还没有设法让它发挥作用。我花了很多时间在谷歌上搜索解决方案,并尝试实施其中的大部分,但没有运气。如果有人可以建议如何将响应重新映射为可用格式或直接访问响应中的数据,将不胜感激。

来自服务的 http 调用示例:-

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

订阅示例:-

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

控制台日志错误示例:-

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

示例数据结构(非常简化的测试):-

"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":""]]

在 Angular1 中,我能够直接从函数访问数据 - 例如如下,并且希望在 Angular2 中做类似的事情

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

【问题讨论】:

似乎我的 console.log 调试不能从 ngOnInit 工作,但我可以从一个函数访问完整的 JSOn 结构:- getTitle() console.log(this.exam.questions[1 ].answers[1].正确); 【参考方案1】:

使用此代码

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

第一行发送请求this._examsService.getExam().subscribe(...)并注册响应的兴趣,然后console.log(this.exam.length)被执行,但是此时respone => this.exam = response还没有被执行,因为getExam()还没有被执行完成连接到服务器并接收响应。

您需要留在事件链中以处理最终返回的数据,例如:

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

我不知道这是否能解决您的问题,但您的问题没有提供足够的信息来说明您对更详细的解决方案的要求。

【讨论】:

这个版本的ngOnInit确实完成没有错误,但是console.log输出只显示“未定义”而不是返回对象的长度。 那么getExam() 不返回值。你能把getExam()的代码添加到你的问题中吗? 上面的“未定义”问题是因为长度属性只存在于 JSON 数组上,而在 JSON 对象上未定义。我可以返回 this.exam.questions.length 但 this.exam.length 返回“未定义”。所以......基本上这是由于我对何时可以使用长度属性的误解。非常感谢您的帮助,因为它确实迫使我重新审视我的假设并测试更多组合。 我明白了,感谢您的反馈。我不知道这些细节,因为我自己不使用 TS/JS,我只使用 Dart。您可以使用此信息发布答案。【参考方案2】:

我认为以下情况是正常行为:

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

因为您尝试访问稍后将设置的exam 对象上的length 属性以及响应何时出现(在subscribe 方法中)。

也就是说,当在 observable 中抛出错误时,不会调用 map 运算符。如果要转换错误响应,可以利用catch 运算符,如下所述:

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

及对应的服务代码:

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());
           );

否则你也可以利用async管道直接在组件上设置observable而不做订阅:

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

在相关的模板中

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

希望对你有帮助 蒂埃里

【讨论】:

谢谢,感谢您的回复。似乎 ngOnInit 是错误的调试位置。我将调试移到一个函数中,并且能够通过单击成功调用它,因此能够访问完整的 JSON 树。 很高兴听到这个消息 ;-) 事实上,这与组件生命周期无关(ngOnInit 是一个生命周期钩子),而是与 observable...

以上是关于Angular2 http observables - 如何使用未定义的类型的主要内容,如果未能解决你的问题,请参考以下文章

Angular2 http.get() ,map(), subscribe() 和 observable 模式 - 基本理解

如何从angular2中的observable获取数据

Angular2中Http的Promise vs Observable? [复制]

Angular2 - 在另一个 Observable 中使用 Observable 返回方法的值

Rxjs 过滤器运算符不适用于 Angular2 Observable

Angular2 Observables - 创建我自己的 - 订阅者未定义