映射/隐藏通过Angular的HttpClient检索的对象

时间:2018-01-17 18:27:39

标签: angular typescript ionic3

也许最好用一个例子来解释。

我有以下课程:

export class Foo {
    bar: string;

    doSomething() {
        // whatever
    }
}

以下提供者:

@Injectable()
export class FooProvider {

  constructor(private http: HttpClient) {

  }

  getFoos(): Observable<Foo[]> {
    return this.http.get<Foo[]>('/foos')
  }

}

我期望在订阅Observable时,数据将是Foo个对象的实际数组。但令我惊讶的是,数组中的对象是简单的javascript对象,只有数据,没有方法(实际上当试图在其中任何一个中执行doSomething()时会出现is not a function错误。

我能够做到的唯一方法是通过这样的方式映射observable:

@Injectable()
export class FooProvider {

  constructor(private http: HttpClient) {

  }

  getFoos(): Observable<Foo[]> {
    return this.http.get<Foo[]>('/foos')
        .map(foos => {
            foos.map(foo => {
                let f = new Foo();
                Object.assign(f, foo);
                return f;
            };
        });
  }

}

问题是,我不想在每个提供商的每个方法中都这样做。看到转换的代码很简单,我猜我错过了一些东西,但是我无法在文档中找到它。

有人可以帮我吗?

1 个答案:

答案 0 :(得分:1)

就像@toskv所说,你需要手动创建对象。虽然标记为重复的两个答案都可以解决OP问题,但我想添加这个答案,因为我通常会做一些不同的事情。

所有答案都使用Object.assign(f, foo);将属性从普通对象复制到类实例。没关系,但就我而言我希望能够更好地控制应用中使用的属性名称。为什么?因此,如果api返回一个属性username,但随后它被更改并且同一属性的名称为fullname,我不想更新该应用的所有页面,其中该属性为被使用。

因此我通常会创建一些静态方法,如下所示:

export class Foo {
    bar: string;

    doSomething() {
        // whatever
    }

    // Static method that creates the instance from 
    // a plain javascript object
    public static fromObject(object: any): Foo {
        let instance = new Foo();

        if(!object) return instance;

        // Here you can decide which name should each property have. 
        // If the API changes in the future, you would only need to 
        // modify a single line of code and that's it. You could also
        // modify each property and give it a specific format if you want
        instance.bar = object.bar;

        // more properties ...

        return instance;
    }

    // Static method that creates a list of instances from a list 
    // of plain javascript objects
    public static fromJsonList(objectList: Array<any>): Array<Foo> {
        let instances = new Array<Foo>();

        if (!objectList || (objectList && objectList.length === 0)) return Foo;

        objectList.forEach(object => instances.push(Foo.fromJson(object)));

        return instances;
    }
}

然后,我在服务中使用它:

getFoos(): Observable<Foo[]> {
    return this.http.get<Foo[]>('/foos').map(response => Foo.fromJsonList(response));
}

通过这样做:

  1. 如果任何属性的名称发生变化,您需要更改一行代码,并且每个页面仍然可以正常运行。
  2. 所有&#34;逻辑&#34;与创建每个实例的方式有关的是封装在模型中,而不是在服务中添加部分实例。