Angular中@Input setter无法捕获值,直接@Input却可行的问题
Angular @Input Setter 异常问题解答
问题场景
父组件通过异步请求初始化数据:
protected loadSelectedSource(source: TableSource) { if (isPresent(source)) { this.tableWidgetSettingsService.getTableColumns(source).subscribe((tableColumns) => { this.tableColumns = tableColumns; this.availableObjectColumnIdentifiers = this.mapColumnsToSortableItems(tableColumns); if (this.selectedObjectColumnIdentifiers.length === 0) { this.availableObjectColumnIdentifiers.forEach((column) => { if (column.position > 0) { if (!this.isDuplicateSelectedColumn(column)) { this.selectedObjectColumnIdentifiers.push(column); if (!isPresent(this.lastInit)) { this.formGroupOptions.tableColumns.setErrors(null); } } } }); this.selectedObjectColumnIdentifiers = this.sortByPosition( this.selectedObjectColumnIdentifiers, ); } }); } }
子组件模板绑定数据:
<multi-sortable-selection [formatter]="formatColumn" [availableItems]="availableObjectColumnIdentifiers" (selectedItemsChange)="selectColumns($event, isObjectColumns)" [selectedItems]="selectedObjectColumnIdentifiers" ></multi-sortable-selection>
子组件出现两个异常现象:
- 使用
@Input() set selectedItems(items: SortableItem[])时,参数items始终为null,无法捕获值;但直接使用@Input selectedItems却能正常获取值。 - 在
availableItems的 setter 中,this._selectedItems能被正确初始化,无需经过selectedItems的 setter。
问题1:为何@Input setter无法捕获值,而直接@Input可以?
- 初始化时序与空值拦截:父组件中
selectedObjectColumnIdentifiers是异步赋值的,初始值大概率为undefined或空数组。如果你的 setter 开头写了类似if (!items) return;的逻辑,第一次触发时传入空值会直接返回,后续父组件更新数据时,若只是用push修改数组(引用未变),Angular 变更检测会认为输入值未改变,不会再次触发 setter,导致有效值无法被捕获。而直接使用@Input selectedItems时,Angular 会在每次变更检测中直接更新属性值,不受引用不变的限制,因此能拿到最新数据。 - setter 实现的逻辑漏洞:如果 setter 内部有覆盖
_selectedItems的错误逻辑,或者没有正确处理数组引用更新的情况,也会导致无法捕获后续传入的有效值。
问题2:为何this._selectedItems能在不经过selectedItems setter的情况下完成初始化?
- Angular 输入属性的直接赋值机制:不管有没有 setter,Angular 在变更检测时都会直接把输入值赋值给组件对应的属性。如果你的子组件中同时定义了
@Input() selectedItems和私有变量_selectedItems,且存在直接引用(比如_selectedItems = this.selectedItems),那么当 Angular 直接更新selectedItems时,_selectedItems会同步拿到值,无需经过 setter。 - availableItems setter 的时序巧合:父组件中
availableObjectColumnIdentifiers和selectedObjectColumnIdentifiers是在同一个异步回调中赋值的,availableItems的 setter 触发时,selectedObjectColumnIdentifiers已经有有效值。此时如果在availableItems的 setter 中直接通过this.selectedItems(不带 setter 的输入属性)获取值并赋值给_selectedItems,就会出现无需经过selectedItemssetter 完成初始化的情况。
内容的提问来源于stack exchange,提问作者ugglybobby
相关产品推荐
相关产品推荐

