【问题标题】:Angular2 unable to map a single JSON object?Angular2 无法映射单个 JSON 对象?
【发布时间】:2017-03-10 10:03:21
【问题描述】:

如何映射和使用作为单个对象而不是数组的 JSON 响应?

最近,我开始向我正在处理的项目中添加一个新功能,该功能应该从 API 获取 JSON 响应,并使用其中的数据填写一个简单的模板。应该不难吧?嗯,不……但是,是的……

JSON 响应的模拟版本:

{
    "id": 1,
    "name": "Acaeris",
}

profile.service.ts

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Profile } from './profile';

/**
 * This class provides the Profile service with methods to read profile data
 */
@Injectable()
export class ProfileService {
    /**
     * Creates a new ProfileService with the injected Http.
     * @param {Http} http - The injected Http.
     * @constructor
     */
    constructor(private http: Http) {}

    /**
     * Returns an Observable for the HTTP GET request for the JSON resource.
     * @return {Profile} The Observable for the HTTP request.
     */
    get(): Observable<Profile> {
        return this.http.get('assets/profile.json')
            .map(res => <Profile>res.json())
            .catch(this.handleError);
    }

    /**
     * Handle HTTP error
     */
    private handleError (error: any) {
        let errMsg = (error.message) ? error.message :
            error.status ? `${error.status} - ${error.statusText}` : 'Server error';
        console.error(errMsg);
        return Observable.throw(errMsg);
    }
}

profile.component.ts

import { Component, OnInit } from '@angular/core';
import { ProfileService } from '../services/profile/profile.service';
import { Profile } from '../services/profile/profile';

/**
 * This class represents the lazy loaded ProfileComponent
 */
@Component({
    moduleId: module.id,
    selector: 'sd-profile',
    templateUrl: 'profile.component.html',
    styleUrls: ['profile.component.css'],
})
export class ProfileComponent implements OnInit {

    errorMessage: string;
    profile: Profile;

    /**
     * Creates an instance of the ProfileComponent with the injected
     * ProfileService
     *
     * @param {ProfileService} profileService - The injected ProfileService
     */
    constructor(public profileService: ProfileService) {}

    /**
     * Get the profile data
     */
    ngOnInit() {
        this.getProfile();
    }

    /**
     * Handles the profileService observable
     */
    getProfile() {
        this.profileService.get()
            .subscribe(
                data => this.profile = data,
                error => this.errorMessage = <any>error
            );
    }
}

profile.ts

export interface Profile {
    id: number;
    name: string;
}

我只是尝试使用{{profile.name}} 输出它,但这最终导致控制台显示大量错误消息并且没有输出。如果我在加载后尝试检查profile 的内容,它会告诉我它是undefined

但是,这是令人困惑的部分。如果我将所有Profile 引用替换为Profile[],将JSON 包装在一个数组中,添加*ngFor="let p of profile" abd 使用{{p.name}} 一切正常。不幸的是,在实际完成的应用程序中,我无法控制 JSON 格式。那么,与作为对象数组处理相比,尝试将其作为单个对象处理时,我做错了什么?

【问题讨论】:

    标签: javascript json angular typescript


    【解决方案1】:

    看起来在表达式 {{profile.name}} 配置文件变量在页面呈现时刻未定义。您可以尝试添加一些像这样的吸气剂:

    get profileName(): string { return this.profile ? this.profile.name ? ''; }
    

    并在模板 {{profileName}} 处使用,或者您可以在模板中使用 ngIf,如下所示:

    <div *ngIf="profile">{{profile.name}}</div>
    

    或更短(如以下评论中的drawmoore建议):

    <div>{{profile?.name}}</div>
    

    当您使用数组时,情况相同 - 在第一次渲染时数组是未定义的。 ngFor 为你处理这个并且什么都不渲染。当获取“配置文件项目”的异步操作完成时 - 使用正确的值再次重新呈现 UI。

    【讨论】:

    • 正确的诊断,但仅供参考:the Elvis operator 作为语法糖存在,正是为此:&lt;div&gt;{{profile?.name}}&lt;/div&gt;
    • 这对我来说没有意义。如果一个对象在渲染时是未定义的,但如果是一个对象数组则定义?问题是我必须将 JSON 设置为 [{ "id": 1, "name": "Acaeris"}] 而不是提供的 { "id", "name": "Acaeris"} ,因此将其视为对象数组,以免引发错误。
    • Array 也是未定义的,但是 ngFor 处理这种情况并且一开始什么也不渲染。填充数组后 - UI 重新呈现
    • 一个小修正,问号语法在 Angular 2 模板上下文中称为 safe navigation operator
    • 非常感谢你现在说得通了。
    【解决方案2】:

    map函数返回 Observables,它们是元素的集合。它与数组的map 函数的工作方式基本相同。

    现在要解决此问题,您可以将 Profile 引用替换为 Profile[] 并使用 {{profile[0].name}}

    【讨论】:

    • 试过了,只是在包装 JSON 之前一直收到同样的错误:EXCEPTION: Uncaught (in promise): Error: comp.profile is undefined View_ProfileComponent_0@/ProfileModule/ProfileComponent/component.ngfactory.js:45:5 [angular] this._console.error('EXCEPTION: ' + this._extractMessage(error));
    • 'map' 函数返回 Observable,而不是 Observable 数组。查看文档:gist.github.com/btroncone/d6cf141d6f2c00dc6b35#map.
    • 我所说的 Observable 是元素的集合。对此我的回答很抱歉。
    • Observable 不是元素的集合。 Observable 对象表示发送通知的对象。观察者订阅了此通知。调用 subscribe 方法时您正在执行此操作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-06
    • 1970-01-01
    • 1970-01-01
    • 2019-05-27
    • 2017-05-12
    • 2017-04-09
    • 1970-01-01
    相关资源
    最近更新 更多