Angular编辑selectedHero时为何同步修改英雄列表数据
Angular英雄列表与详情编辑数据联动异常问题
相关代码实现
Hero接口定义
export interface Hero { id: number, name: string }
英雄列表常量数据
import { Hero } from './model-interfaces/hero'; export const HEROS: Hero[] = [ { id: 12, name: 'Dr. Nice' }, { id: 13, name: 'Bombasto' }, { id: 14, name: 'Celeritas' }, { id: 15, name: 'Magneta' }, { id: 16, name: 'RubberMan' }, { id: 17, name: 'Dynama' }, { id: 18, name: 'Dr. IQ' }, { id: 19, name: 'Magma' }, { id: 20, name: 'Tornado' } ];
英雄列表组件逻辑
export class HerosComponent implements OnInit { heros = HEROS; selectedHero?: Test; constructor() { } ngOnInit(): void { } onSelect(hero: Test): void { this.selectedHero = hero; } }
注:此处存在类型笔误,selectedHero与onSelect参数标注的Test类型应改为Hero类型,避免TS类型校验报错
英雄列表组件模板
<h2>My Heroes</h2> <ul class="heroes"> <li *ngFor="let hero of heros"> <button [class.selected]="hero === selectedHero" type="button" (click)="onSelect(hero)"> <span class="badge">{{hero.id}}</span> <span class="name">{{hero.name}}</span> </button> </li> </ul> <app-hero-details [hero] = "selectedHero"></app-hero-details>
英雄详情组件逻辑
export class HeroDetailsComponent implements OnInit { @Input() hero?: Hero constructor() { } ngOnInit(): void { } }
英雄详情组件模板
<div *ngIf="hero"> <h2>{{hero.name | uppercase}} Details</h2> <div>ID: {{hero.id}}</div> <div> <label for="hero-name">Hero name: </label> <input id="hero-name" [(ngModel)]="hero.name" placeholder="name"> </div> </div>
问题现象
- 点击列表中任意英雄后,页面底部正常展示选中英雄的详情与名称编辑输入框
- 在输入框修改选中英雄的名称时,列表中对应英雄的名称会同步发生变更
原因说明
这个现象是JavaScript/TypeScript的引用类型特性导致的,和Angular框架本身无关:
- 基础类型(字符串、数字、布尔值等)赋值时是值拷贝,两个变量的修改操作互不影响
- 对象、数组属于引用类型,变量存储的是指向堆内存中实际数据的地址,而非数据本身。你在
onSelect方法中执行this.selectedHero = hero时,并没有生成一个独立的新英雄对象,只是让selectedHero变量指向了HEROS数组中对应原对象的内存地址 - 详情模板中通过
[(ngModel)]双向绑定修改hero.name时,本质是直接修改了内存地址上存储的原对象属性,列表渲染用的heros数组中存储的也是指向同一个对象的引用,自然会同步展示修改后的结果
调整方案
如果需要编辑详情时不直接改动列表原数据,只需要在选中英雄时生成一个原对象的副本,切断引用关联即可,修改onSelect方法:
onSelect(hero: Hero): void { // 通过对象展开运算符做浅拷贝,生成独立的新对象 this.selectedHero = {...hero}; }
如果后续需要把编辑后的结果同步回列表,可以新增保存逻辑,根据英雄id找到原数组中的对应项,再更新属性值即可。
内容的提问来源于stack exchange,提问作者g78
相关产品推荐
相关产品推荐

