Angular 2无法从模板访问HTTP get响应

时间:2017-07-23 15:52:44

标签: javascript angular angular-services

好的,所以我一直在努力解决这个问题。我正在使用名为“Contenful”的服务充当CMS并使用他们的api来获取JSON数据。

我有一个名为'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次,即使此刻,数组'block'中只有1个对象。但我不认为有一个对象是一个问题......(我可能错了)

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

任何建议都将不胜感激。感谢。

1 个答案:

答案 0 :(得分:0)

正如我所提到的,主要问题在于:

<?php // demo/temp_elo.php
/**
 * Working with substrings
 *
 * https://stackoverflow.com/questions/45267396/accessing-substrings-in-a-php-array
 */
error_reporting(E_ALL);
echo '<pre>';


$target = "Ninja blah Turtles";
$source = [ "jack and jil", "peter likes pan", "Ninja Turtles" ];

// SEPARATE THE TARGET INTO ITS SUBSTRINGS
$targets = explode(' ', $target);

// TEST EACH OF THE SOURCE STRINGS
foreach ($source as $string)
{
    echo PHP_EOL . $string;
    foreach ($targets as $tgt)
    {
        if (stripos($string, $tgt) !== FALSE)
        {
            echo " CONTAINS $tgt";
        }
    }
}

如果<h1 *ngFor="let block of blocksJSON; let i = index">{{block[i].fields.blockName}}</h1> 是一个数组,ngFor将负责为你迭代它的元素,这样你就不需要通过它们的索引来访问元素了。

blocksJSON

只要<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);
  };
}