You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过API访问嵌套对象数据?(TMDB API+Angular场景)

解决Angular遍历TMDB API嵌套对象的问题

错误原因分析

  1. 初始值未定义:watchProviders初始为undefined,模板直接访问watchProviders.CA会触发"Cannot read properties of undefined"错误。
  2. 对象无法直接遍历:TMDB返回的watchProviders.CA是对象(包含flatrate/buy/rent等数组属性),而*ngFor仅支持遍历可迭代对象(如数组)。
  3. 冗余的延迟逻辑:组件中setTimeout完全没必要,会导致不必要的延迟,还可能错过路由参数变化。

分步解决方案

1. 修复异步加载与初始值问题

先给watchProviders设置初始空对象,同时移除无效的setTimeout,确保路由参数变化时立即触发API请求:

组件代码修改:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { MoviesService } from './path-to-your-service';

@Component({
  selector: 'app-movie-providers',
  templateUrl: './movie-providers.component.html'
})
export class MovieProvidersComponent implements OnInit {
  // 初始化为空对象,避免undefined报错
  watchProviders: any = {};

  constructor(private route: ActivatedRoute, private moviesService: MoviesService) {}

  ngOnInit(): void {
    // 直接订阅路由参数,无需延迟
    this.route.params.subscribe(params => {
      const movieId = +params["id"]; // 转换为数字类型,确保参数有效性
      if (movieId) {
        this.listProviders(movieId);
      }
    });
  }

  listProviders(movieId: number){
    this.moviesService.listProviders(movieId).subscribe((res) => {
      this.watchProviders = res['results'];
      // 打印数据确认结构,方便调试
      console.log('Providers data:', this.watchProviders);
    });
  }
}

2. 处理对象转数组的遍历需求

TMDB返回的CA结构示例:

{
  "flatrate": [{ "link": "xxx", ... }, ...], // 流媒体订阅提供商
  "buy": [{ "link": "xxx", ... }, ...],      // 购买提供商
  "rent": [{ "link": "xxx", ... }, ...]      // 租赁提供商
}

根据需求选择以下方案:

方案A:展示所有类型的提供商

合并flatrate/buy/rent数组,统一遍历:

模板代码:

<!-- 先判断CA是否存在,避免空值报错 -->
<div *ngIf="watchProviders?.CA">
  <span *ngFor="let provider of getAllProviders()">
    {{ provider.link }}
  </span>
</div>

组件添加方法:

getAllProviders(): any[] {
  if (!this.watchProviders?.CA) return [];
  // 合并所有类型的提供商数组,空数组兜底避免报错
  return [
    ...(this.watchProviders.CA.flatrate || []),
    ...(this.watchProviders.CA.buy || []),
    ...(this.watchProviders.CA.rent || [])
  ];
}
方案B:仅展示特定类型的提供商(如流媒体)

直接访问对应数组,用安全导航操作符(?.)和空数组兜底:

模板代码:

<!-- 安全导航确保CA和flatrate存在,空数组兜底避免*ngFor报错 -->
<span *ngFor="let provider of watchProviders?.CA?.flatrate || []">
  {{ provider.link }}
</span>

3. 可选:添加类型定义提升代码严谨性

避免any类型带来的不确定性,定义接口规范数据结构:

// 定义提供商对象结构
interface Provider {
  display_priority: number;
  logo_path: string;
  provider_id: number;
  provider_name: string;
  link: string;
}

// 定义国家对应的提供商分组
interface CountryProviders {
  flatrate?: Provider[];
  buy?: Provider[];
  rent?: Provider[];
}

// 定义API返回结构
interface WatchProvidersResponse {
  results: Record<string, CountryProviders>; // key为国家代码(如CA、US)
}

修改服务和组件的类型声明:

// 服务代码
listProviders(movieId: number): Observable<WatchProvidersResponse> {
  return this.coreApi.get<WatchProvidersResponse>(`${endpoints.listMovies}/${movieId}/watch/providers`);
}

// 组件代码
watchProviders: Record<string, CountryProviders> = {};

listProviders(movieId: number){
  this.moviesService.listProviders(movieId).subscribe((res) => {
    this.watchProviders = res.results;
  });
}

内容的提问来源于stack exchange,提问作者KimiH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 02:30:44