【问题标题】:Angular 12 - Using class as http observableAngular 12 - 使用类作为 http observable
【发布时间】:2021-11-08 02:38:18
【问题描述】:

使用 Angular 12

HTTP 服务从后端返回以下响应

Array<{
   id: string;
   title: string;
   created: string;
}>

// Service
public list(): Observable<Array<Item>> {
  return this.http.get<Array<Item>>(url);
}

// Component
this.service.list().subscribe(res => {
  this.item = res;
});

创建了一个模型类来对响应进行类型转换

export class Item {
  id: string;
  title: string;
  created: string;

  get parsedTitle() {
    const t = this.title;
    // do some parsing on title
    return t;
  }
}

在 HTML 中,想用parsedTitle 打印解析后的标题,但是什么也没打印。

尝试将 getter 更改为函数 public parsedTitle(){},然后它给出错误,parsedTitle is not a function

如何将返回的可观察对象类型转换为对象数组中的类实例?

【问题讨论】:

  • 您不能对它们进行“类型转换”——TypeScript 在运行时不存在,您需要使用 JSON 中的(香草对象)数据来实例化该类。使用接口来表示 JSON,它只有有数据(没有行为)。可能的欺骗集合:github.com/angular/angular/issues/25401.

标签: angular typescript angular-observable


【解决方案1】:

您需要将普通对象映射到真正的Item 类。试试这样的:

// class
class Item {
    constructor(item: Partial<Item>) {
        Object.assign(this, item);
    }

    id: string = '';
    title: string = '';
    created: string = '';

    get parsedTitle() {
        const t = this.title;
        // do some parsing on title
        return t;
    }
}

// Service
public list(): Observable<Array<Item>> {
  return this.http.get<Array<Item>>(url).pipe(
    map(items => items.map(item => new Item(item))),
  );
}

【讨论】:

    【解决方案2】:

    想想你应该如何在其他编程语言中使用类。通常,您需要使用类构造函数实例化该类型的对象,以便有一些东西可以调用您的方法(当然,除非方法是静态的)。

    将其外推到您的用例中,您不应该只是尝试告诉 typescript 将您刚从 API 获得的对象视为 Item 的实例,而是构建 @987654322 @ 实例。

    向您的项目类添加一个构造函数,该构造函数接收一个参数并将它在该对象中找到的所有属性复制到this(当前实例)。

    export class Item {
      id: string;
      title: string;
      created: string;
    
      constructor(item?: Item) {
        Object.assign(this, item ?? {});
      }
    
      get parsedTitle() {
        const t = this.title;
        // do some parsing on title
        return t;
      }
    }
    

    在您的服务类中,确保将从 API 获得的对象转换为 Item 类型的实际实例数组,如下所示:

    // Service
    public list(): Observable<Array<Item>> {
      return this.http.get<Array<Item>>(url).pipe(
        map(item => new Item(item))
      );
    }
    

    【讨论】:

      【解决方案3】:

      发生这种情况是因为来自后端的对象 (JSON) 被序列化为目标类型(在您的情况下为 Item),而没有使用其构造函数对其进行初始化。

      因此,如果您需要实现您想要做的事情,您必须使用new Item()Item 承包商初始化每个object

      所以你可以尝试以下方法:

      item.model.ts:

      export class Item {
        id: string;
        title: string;
        created: string;
      
        get parsedTitle() {
          const t = this.title;
          // do some parsing on title
          return t;
        }
      
        constructor(item: Partial<Item>) {
          Object.assign(this, item);
        }
      }
      

      items.service.ts:

      // Service
      public list(): Observable<Array<Item>> {
        return this.http
          .get<Array<Item>>(url)
          .pipe(map(items => items.map(item => new Item(item))));
      }
      

      【讨论】:

        【解决方案4】:

        这里的问题是,您没有实例化 Item 类并对其进行 API 响应。一旦 API 返回响应,从响应到 Item 类的转换不会自动发生。您只需要处理转换。 根据您的代码,代码尝试通过此访问 title,而 this 将永远不可用,因为您尚未实例化它。

        试试下面的代码(小改动):

        // 服务

        public list(): Observable<Array<Item>> {
          return this.http.get<Array<Item>>(url)
                 .pipe(map((items) => (items.map((item) => (new Item(item))))));
        }
        

        【讨论】:

          猜你喜欢
          • 2017-02-02
          • 2018-12-05
          • 2018-04-20
          • 2018-10-08
          • 2018-01-31
          • 2018-01-07
          • 1970-01-01
          • 1970-01-01
          • 2021-12-07
          相关资源
          最近更新 更多