【发布时间】:2017-09-16 00:07:25
【问题描述】:
前言:我意识到这可能是重复的,但是阅读了发现的错误的详细说明here 我仍然不明白我的代码将如何使更改中执行的脏检查无效检测。
我有一个包含 FormArray 的 FormGroup。我想将 FormArray 嵌套到一个子组件中,因为它包含很多它自己的特定业务逻辑。
当我在浏览器中加载组件并运行单元测试时,我收到以下异常:
ParentComponentA.html:2 ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.
at viewDebugError (core.es5.js:8426)
at expressionChangedAfterItHasBeenCheckedError (core.es5.js:8404)
at checkBindingNoChanges (core.es5.js:8568)
at checkNoChangesNodeInline (core.es5.js:12448)
at checkNoChangesNode (core.es5.js:12414)
at debugCheckNoChangesNode (core.es5.js:13191)
at debugCheckRenderNodeFn (core.es5.js:13131)
at Object.eval [as updateRenderer] (ParentComponentA.html:2)
at Object.debugUpdateRenderer [as updateRenderer] (core.es5.js:13113)
at checkNoChangesView (core.es5.js:1223
父组件 A:
@Component({
selector: 'app-parent-component-a',
templateUrl: './parent-component-a.component.html',
styleUrls: ['./parent-component-a.component.scss']
})
export class ParentComponentA implements OnInit, OnDestroy {
activeMediaViewport: string; // Should match a value of MaterialMediaQueries enum
mediaWatcher: Subscription;
parentForm: FormGroup;
childComponentDisplayMode: number; // Should match a value of ComponentDisplayModes enum
constructor(private formBuilder: FormBuilder, private mediaQueryService: ObservableMedia) {
const prepareComponentBFormControl = (): FormGroup => {
return formBuilder.group({
'code': '',
'weight': '',
'length': '',
'width': '',
'height': '',
});
};
const prepareParentForm = (): FormGroup => {
return formBuilder.group({
// ... omitted other properties
'childComponentList': formBuilder.array([prepareComponentBFormControl()])
});
};
}
ngOnInit() {
this.initializeWatchers();
}
ngOnDestroy() {
this.mediaWatcher.unsubscribe();
}
/**
* Sets intervals and watchers that span the entire lifecycle of the component and captures their results to be used for deregistration.
*/
private initializeWatchers(): void {
this.mediaWatcher = this.mediaQueryService
.subscribe(mediaChange => {
this.activeMediaViewport = mediaChange.mqAlias;
this.childComponentDisplayMode = this.calculateComponentDisplayMode(this.activeMediaViewport);
});
}
}
组件 A 的 HTML 标记属性
<child-component-b [displayMode]="childComponentDisplayMode"
[nestedFormList]="childComponentList">
</child-component-b>
子组件 B:
@Component({
selector: 'child-component-b',
templateUrl: './child-component-b.component.html',
styleUrls: ['./child-component-b.component.scss'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponentB implements OnInit {
@Input() displayMode: number; // Should match a value of ComponentDisplayModes enum
@Input() nestedFormList: FormArray;
mobileDisplays: Array<number>;
largeDisplays: Array<number>;
numberOfRowsToAdd: FormControl;
constructor(private formBuilder: FormBuilder) {
this.mobileDisplays = [ComponentDisplayModes.TABLET_PORTRAIT, ComponentDisplayModes.PHONE_LANDSCAPE, ComponentDisplayModes.PHONE_PORTRAIT];
this.largeDisplays = [ComponentDisplayModes.DESKTOP, ComponentDisplayModes.TABLET_LANDSCAPE];
}
ngOnInit() {
// including in this SO post since it references the @Input property
this.numberOfRowsToAdd = new FormControl(this.defaultRowsToAdd, this.addBuisnessLogicValidator(this.nestedFormList));
}
private addBuisnessLogicValidator(nestedFormListRef: FormArray): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => {
const rowsRemaining = maxLinesAllowed - nestedFormListRef.length;
const rowsToAdd = control.value;
const isInvalid = isNaN(parseInt(rowsToAdd, 10)) || rowsToAdd < 0 || rowsToAdd > rowsRemaining;
return isInvalid ? {'invalidRowCount': {value: control.value}} : null;
};
} }
组件 B HTML 标记属性
<div *ngFor="let listItem of nestedFormList.controls; index as index"
[formGroup]="listItem">
</div>
我认为在子组件中使用 *ngFor 可能会在更改检测期间“弄脏”视图的值?
【问题讨论】:
-
你能用你的问题创建一个 plunker 吗?
-
我已经阅读了那篇文章@AngularInDepth.com - 这就是我在我的 OP 中链接的内容。我仍然不明白在这种情况下我在做什么会更新任何导致异常的东西。 yurzi 等我有空的时候,我会试着把它放到一个 plunker 里,谢谢。
-
@rawkfist0215,是的,然后尝试创建一个 plunker
-
我找到了解决方案。创建 plunkr 帮助我隔离了潜在的问题点并缩小了原因。谢谢两位的建议。
标签: angular typescript angular-cli