Angular2 http observables - 如何使用undefined类型

Angular2 http observables - 如何使用undefined类型

问题描述:

我正在将一些代码从Angular1迁移到Angular2并且出现了一些问题。我可以打开json响应,填充模板并从模板ng函数访问数据,但无法直接从组件类访问数据。从我阅读的内容和看到的错误信息看,Angular2 http/observable似乎没有返回纯Json对象,所以我怀疑我需要重新映射它,但不知道如何。我相信也应该可以放弃使用onPromise的承诺,但还没有设法实现这一目标。我花了很多时间搜索解决方案,并试图实现其中的大部分,但没有运气。如果任何人可以建议如何重新映射可用格式的响应或直接访问响应中的数据,将不胜感激。从服务Angular2 http observables - 如何使用undefined类型

例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') ... 
+0

似乎我的console.log调试没有从ngOnInit工作,但我能够从函数访问完整的JSOn结构: - getTitle(){ console.log(this.exam.questions [1] .answers [ 1] .correct); } – Robert

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

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管直接设置组件上的可观察性而不是订阅:

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

并在关联的模板中

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

希望它可以帮助你, 蒂埃里

+0

谢谢,感谢回复。它似乎确实是ngOnInit是错误的地方进行调试。我将调试移出到一个函数,并能够通过点击成功调用它,所以能够访问完整的JSON树。 – Robert

+0

很高兴听到这个;-)事实上,这并没有链接到组件的生命周期(ngOnInit是一个生命周期钩子),但是对于可观察的... –

有了这个代码

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()尚未完成连接到服务器r并收到回复。

你需要留在事件链与最终返回的数据等的工作:

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

我不知道这样做是否解决您的问题,但你的问题没有提供足够的有关您的要求的更多详细解决方案的信息。

+1

这个版本的ngOnInit没有错误就完成了,但是console.log输出只显示“未定义”而不是返回对象的长度。 – Robert

+0

然后'getExam()'不返回一个值。你可以将'getExam()'的代码添加到你的问题中吗? –

+1

上面的“未定义”问题是因为长度属性仅存在于JSON数组上,并且在JSON对象上未定义。我能够返回this.exam.questions.length,但this.exam.length返回“undefined”。所以......基本上这是由于我误解了长度属性何时可以使用。我非常感谢你的帮助,因为它迫使我重新审视我的假设并测试更多的组合。 – Robert