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

Angular中API GET请求结果无法赋值给myCharactere变量的问题

Angular API数据赋值失败排查与修复

问题描述

尝试通过表达式{{myCharactere && myCharactere.statistics && myCharactere.statistics[stat.key] || ''}}展示API GET请求返回的角色数据,但无法将请求结果赋值给本地变量myCharactere,相关代码如下:

组件TypeScript代码

export class StatsComponent implements OnInit {
  
  myCharactere: any;
  statLookup = [
    // Pourquoi est-ce un mauvais choix???
    { key: 'str', prefix: $localize`str`, suffix: $localize`enght`, couleur: 'bg-danger' },
    { key: 'dex', prefix: $localize`dex`, suffix: $localize`terity`, couleur: 'bg-primary' },
    { key: 'con', prefix: $localize`con`, suffix: $localize`stitution`, couleur: 'bg-warning' },
    { key: 'int', prefix: $localize`int`, suffix: $localize`elligence`, couleur: 'bg-success' },
    { key: 'sag', prefix: $localize`wis`, suffix: $localize`dom`, couleur: 'bg-info' },
    { key: 'cha', prefix: $localize`cha`, suffix: $localize`risma`, couleur: 'bg-dark' }
  ];
  constructor(public myService: ServeurService) { }

  ngOnInit(): void {
    this.myService.getAllInfosById(this.myService.getPersonnageIdByName("Xefoul Snaromers")).subscribe(result => {
      this.myCharactere = result
      console.log(this.myCharactere);
    });
    
    getModifier(stat: number): string {
      const mod = Math.floor((stat-10)/2)
      return (mod<0)?'-':'+'+ mod.toString();
    }
  }
}

服务TypeScript代码

export class ServeurService {
  
  personnages: any[] = [];
  persoName = '';

  constructor(private http_client: HttpClient) { }

  getPersonnage(): Observable<ICharactere[]> {
    return this.http_client.get<ICharactere[]>(this.serverCharacter).pipe(retry(4));
  }

  getAllInfosById(id: string) {
    const myUrl = 'https://cegep.fdtt.space/v1/character/' + id;
    return this.http_client.get<ICharactere>(myUrl).pipe();
  }

  setPersonnageName(name: string) {
    this.persoName = name;
  }

  getPersonnageName():string {
    return this.persoName;
  }

  getPersonnages() {
    this.http_client.get<any>('https://cegep.fdtt.space/v1/characters').subscribe({
      next: (val) => {
        val.data.forEach((element: { data: any; }) => {
          this.personnages.push(element);
        });
      }
    });
    return this.personnages;
  }

  getPersonnageById(id: string) {
    const persoSelectionne = this.getPersonnages().find((x: { id: string; }) => x.id === id);
    return persoSelectionne;
  }

  getPersonnageIdByName(name: string) {
    const persoSelectionne = this.getPersonnages().find((n: {name: string; }) => n.name === name);
    console.log("perso name service", persoSelectionne)
    return persoSelectionne.id; 
  }
}

展示用HTML代码

<div class="row text-center text-light bg-secondary mt-2  bg-transparent">
    <div class="row mt-5">
        <div class="col-2" *ngFor="let stat of statLookup">
            <div class="{{stat.couleur}} mx-xxl-4 mx-2 mx-md-1 rounded-4">
                <div class="fw-bold">{{stat.prefix}}<span class="d-none d-lg-inline">{{stat.suffix}}</span>
                </div>
                <div class="h2">
                    {{myCharactere && myCharactere.statistics && myCharactere.statistics[stat.key] ? getModifier(myCharactere.statistics[stat.key]) : ''}}
                </div>
                <div class="">
                    {{myCharactere && myCharactere.statistics && myCharactere.statistics[stat.key] || ''}}
                </div>
            </div>
    </div>
</div>

数据模型代码

export interface ICharactere {
    error: string;
    id: string;
    name: string;
    statistics: { [ key : string ]: number }
    race: string;
    player: string;
    classe : string;
    sousclasses: string;
    level: number;
    background: string;
    synopsis: string;
    image: string;
    health: number;
    currentHealth: number;
    traits: {
        trait: string;
        description: string;
    }[];
    armorClass: number;
    initiative: number;
    speed: number;
}

问题排查与修复

1. 异步请求同步返回导致ID获取失败

ServeurService中的getPersonnages发起异步HTTP请求,但直接返回空数组,此时getPersonnageIdByName调用getPersonnages().find()时,数组还未被API数据填充,导致persoSelectionne为undefined,调用persoSelectionne.id会抛出错误,进而getAllInfosById请求URL无效,myCharactere无法赋值。

修复方案:将getPersonnages改为返回Observable,确保数据加载完成后再获取ID:

// 修改服务中的getPersonnages方法
getPersonnages(): Observable<any[]> {
  return this.http_client.get<any>('https://cegep.fdtt.space/v1/characters').pipe(
    map(val => val.data),
    tap(data => {
      this.personnages = data; // 缓存数据
    })
  );
}

// 修改getPersonnageIdByName为异步获取
getPersonnageIdByName(name: string): Observable<string> {
  return this.getPersonnages().pipe(
    map(personnages => {
      const persoSelectionne = personnages.find((n: {name: string; }) => n.name === name);
      console.log("perso name service", persoSelectionne);
      return persoSelectionne?.id || '';
    })
  );
}

组件中调整调用逻辑:

ngOnInit(): void {
  this.myService.getPersonnageIdByName("Xefoul Snaromers").subscribe(id => {
    if (id) {
      this.myService.getAllInfosById(id).subscribe(result => {
        this.myCharactere = result;
        console.log(this.myCharactere);
      });
    }
  });
}

2. 方法定义位置错误

组件中getModifier定义在ngOnInit内部,属于语法错误,需移到组件类顶层:

export class StatsComponent implements OnInit {
  
  myCharactere: any;
  statLookup = [...]; // 原有数组保持不变

  constructor(public myService: ServeurService) { }

  ngOnInit(): void {
    // 修正后的异步调用逻辑
    this.myService.getPersonnageIdByName("Xefoul Snaromers").subscribe(id => {
      if (id) {
        this.myService.getAllInfosById(id).subscribe(result => {
          this.myCharactere = result;
          console.log(this.myCharactere);
        });
      }
    });
  }

  getModifier(stat: number): string {
    const mod = Math.floor((stat - 10) / 2);
    return mod < 0 ? `${mod}` : `+${mod}`;
  }
}

3. 模板空值检查优化

使用Angular可选链操作符?.简化空值判断:

<div class="row text-center text-light bg-secondary mt-2  bg-transparent">
    <div class="row mt-5">
        <div class="col-2" *ngFor="let stat of statLookup">
            <div class="{{stat.couleur}} mx-xxl-4 mx-2 mx-md-1 rounded-4">
                <div class="fw-bold">{{stat.prefix}}<span class="d-none d-lg-inline">{{stat.suffix}}</span>
                </div>
                <div class="h2">
                    {{myCharactere?.statistics?.[stat.key] ? getModifier(myCharactere.statistics[stat.key]) : ''}}
                </div>
                <div class="">
                    {{myCharactere?.statistics?.[stat.key] || ''}}
                </div>
            </div>
    </div>
</div>

额外优化建议

  • 用switchMap简化嵌套订阅:
// 组件ngOnInit优化版,记得导入switchMap
import { switchMap } from 'rxjs/operators';

ngOnInit(): void {
  this.myService.getPersonnageIdByName("Xefoul Snaromers").pipe(
    switchMap(id => this.myService.getAllInfosById(id))
  ).subscribe(result => {
    this.myCharactere = result;
    console.log(this.myCharactere);
  });
}
  • 给myCharactere指定类型获得类型提示:
myCharactere: ICharactere | undefined;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 00:30:42