2017-07-23 216 views
-1

好的,所以我一直在为此挣扎了一段时间。我使用名为“Contenful”的服务来充当CMS,并使用它们的API来获取JSON数据。Angular 2无法从模板访问HTTP获得响应

我有一个叫做“editor.service.ts”服务如下(我已经隐藏了“SpaceID”和“访问令牌”隐私):

import { Injectable } from '@angular/core'; 
import { Http, Response } from '@angular/http'; 
import { Observable } from 'rxjs/Observable'; 
import 'rxjs/add/operator/map'; 

@Injectable() 
export class EditorService { 
    private baseURL = 'https://cdn.contentful.com'; 
    private spaceID = 'HIDDEN'; 
    private accessToken ='HIDDEN'; 
    private blocksURL = this.baseURL + '/spaces/' + this.spaceID + '/entries?access_token=' + this.accessToken + '&content_type=blocks'; 

    constructor(private http: Http) {} 

    getBlocks(): Observable<any> { 
     return this.http.get(this.blocksURL).map((res: Response) => res); 
    } 
} 

然后在我的组件调用'editor.component.ts' 我有这样的:

import { Component, OnInit } from '@angular/core'; 
import { EditorService } from './../editor.service'; 

@Component({ 
    selector: 'app-editor', 
    templateUrl: './editor.component.html', 
    styleUrls: ['./editor.component.css'], 
    providers: [EditorService] 
}) 

export class EditorComponent implements OnInit { 
    blocksJSON: any; 

    constructor(private editorService: EditorService) {} 

    ngOnInit() { 
     this.editorService.getBlocks().subscribe(res => { 
      this.blocksJSON = res.json().items; 
      console.log(this.blocksJSON); //THIS WORKS 
     }); 
    } 
} 

这里有一个是越来越我困惑的一点。该文件中的console.log()行正好打印出我想要的内容,所以我知道该API工作正常。令人困惑的是现在。

在我的模板文件,我有这样一行:

<h1 *ngFor="let block of blocksJSON; let i = index">{{block[i].fields.blockName}}</h1> 

在我看来,这应该只是工作。不过,我不断收到错误

ERROR TypeError: Cannot read property 'fields' of undefined 

它打印出此错误3次,即使在目前,有在数组“块”只有1对象。但我不认为有1个对象是一个问题...(我可能是错的,虽然)

我不知道这是为什么,因为console.log打印出我想要的数据,所以我知道它应该被定义。我唯一的想法是角度2 HTTP get是异步的,但我不知道这是否是问题。

任何意见将不胜感激。谢谢。

+1

[angular2的可能重复:错误:类型错误:无法读取undefi的属性'...' ned](https://stackoverflow.com/questions/41242793/angular2-error-typeerror-cannot-read-property-of-undefined) – Alex

+0

和更多的建议... https://stackoverflow.com/questions/34734671/ observable-type-error-can-read-property-of-undefined大量的问答环节;) – Alex

+0

@ AJT_82感谢您的回答并抱歉发布重复。根据2个答案,我认为我需要将h1包装在* ngIf中。我这样做如下:但我仍然得到相同的错误。你有什么想法,或者我应该继续寻找:) –

回答

0

正如我提到的,主要的问题是在这里:

<h1 *ngFor="let block of blocksJSON; let i = index">{{block[i].fields.blockName}}</h1> 

如果blocksJSON是一个数组,ngFor会照顾迭代它为你的元素,所以你不要这样需要访问借助于元素的指数。

<h1 *ngFor="let block of blocksJSON">{{block.fields.blockName}}</h1> 

这应该工作,只要blocksJSON数组中的每一个元素都有fields属性。

跟你一样的角度出发,我会用这个答案指向一些其他的东西,你可以改善:

型号:始终定义一个接口为你的后端的响应。在地方使用any可以避免击败类型脚本的最大目的之一脚本:强打字。

因此,例如,定义如下:

export interface BlockFields{ 
    blockName: string; 
    // more properties 
} 

export interface Block{ 
    fields: BlockFields; 
    .... //more properties 
} 

服务:

import { Response, Http} from '@angular/http'; 
import { Block } from '...' // the place where you saved the response interface 
import { _throw } from 'rxjs/observable/throw'; 
import { ErrorObservable } from 'rxjs/observable/ErrorObservable'; 

@Injectable() 
export class EditorService { 
    private baseURL = 'https://cdn.contentful.com'; 
    private spaceID = 'HIDDEN'; 
    private accessToken ='HIDDEN'; 
    private _blocksUrl = `${this.baseUrl}/spaces/${this.spaceID}/entries?access_token=${this.accessToken}&content_type=blocks`; //template strings makes concatenation of multiple static sections and parameters cleaner 

    constructor(private http: Http) {} 

    getBlocks(): Observable<Block[]> { 
     return this.http.get(this.blocksURL) 
     .map(this.extractData) 
     .catch(this.handleError); // always handle your http errors at service level first. 
    } 

    private extractData(response: Response){ 
     return response.json(); 
    } 

    private handleError(error: any): ErrorObservable { 
    let errMsg: string; 
    if (error instanceof Response) { 
     const body = error.json() || ''; 
     const err = JSON.stringify(body); 
     errMsg = `${error.status} - ${error.statusText || ''} Details: ${err}`; 
    } else { 
     errMsg = error.message ? error.message : error.toString(); 
    } 
    return _throw(errMsg); 
    }; 
} 

组件:

import { Block } from '...' // the place where you saved the response interface 

@Component({ 
    selector: 'app-editor', 
    templateUrl: './editor.component.html', 
    styleUrls: ['./editor.component.css'] 
    //providers: [EditorService] dont provide the service directly in the component decorator. Instead, add the service to the providers array of you app.module. If you provide it here, a new instance of the EditorSerice will be created every time a this component is created. You want services to be singletone. 
})  
export class EditorComponent implements OnInit { 
    blocks: Block[]; 

    constructor(private editorService: EditorService) {} 

    ngOnInit() { 
     this.editorService.getBlocks() 
     .subscribe(res => { 
      this.blocks= blocks; 
     }); 
    } 
} 
+0

感谢您的帮助,不仅是为了解决这个问题,还有一些其他方面的角度2。我现在可能会去添加这些东西。谢谢 :) –