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
相关产品推荐
相关产品推荐

