Angular 2 模态弹出错误“检查后表达式已更改”
Posted
技术标签:
【中文标题】Angular 2 模态弹出错误“检查后表达式已更改”【英文标题】:Angular 2 Modal Popup Error "Expression has changed after it was checked" 【发布时间】:2017-07-08 11:37:20 【问题描述】:Youtube video demonstrating the problem
Github repository for the demo app
我有一个非常简单的应用程序,它有一个应用程序组件、一个子组件(帐户)、处理消息对话框组件(弹出模式)的警报服务。
为了演示目的,我有两个相同的表单,一个在 app.component.ts 中,一个在 account.component.ts 中。它们每个都有一个按钮,用于调用警报服务以显示消息对话框模式。
问题是当我单击子组件(account.component.ts)的表单输入字段并“在我的键盘上按回车键”时,我收到此错误
例外:./AccountComponent 类 AccountComponent 中的错误 - 内联模板:2:2 原因:检查后表达式已更改。以前的值:“真”。当前值:“假”。 请注意,此错误不会在以下提到的任何其他情况下发生
如果我单击按钮而不是按键盘上的 Enter 键
来自 app.componen.ts 的表单似乎没有任何问题,即使我按 Enter 键。它似乎只是子组件(account.component.ts)。
如果我点击account.component的输入,输入一些东西,点击按钮,没有错误显示,删除输入,回车,现在相比之前没有错误显示
我研究了 SO 和 google,似乎人们遇到了同样的问题,并通过调用更改检测来解决它。但是,我已经尝试过,并将其放在模态显示之后的地方,但它不起作用。此外,如果这样可以解决它,那么它不能解释为什么 app.component.ts 中的表单不会导致我出现这个错误。
下面是一些sn-ps的代码,完整的demo项目可以在上面的github链接上找到。这个问题困扰了我好几天。非常感谢您的帮助。
app.component.html
<label>This form is from app.component.html</label>
<form name="form" [formGroup]="changePasswordForm" (ngSubmit)="onUpdatePassword()">
<input placeholder="Old Password" formControlName="oldPassword">
<button class="btn btn-success">Update Password</button>
</form>
<br><br><br><br>
<label>This form is from account.component.html</label>
<router-outlet> </router-outlet>
<template ngbModalContainer></template>
app.component.ts
export class AppComponent implements OnInit
private changePasswordForm: FormGroup;
constructor(
private formBuilder: FormBuilder,
private alertService: AlertService,
)
ngOnInit()
this.changePasswordForm = this.formBuilder.group(
oldPassword: [''],
)
onUpdatePassword()
this.alertService.alertPopup('test2', 'asfafa')
account.component.html
<form name="form" [formGroup]="changePasswordForm" (ngSubmit)="onUpdatePassword()">
<input placeholder="Old Password" formControlName="oldPassword">
<button class="btn btn-success">Update Password</button>
</form>
account.component.ts
导出类 AccountComponent 实现 OnInit
private changePasswordForm: FormGroup;
constructor(
private formBuilder: FormBuilder,
private alertService: AlertService,
)
ngOnInit()
this.changePasswordForm = this.formBuilder.group(
oldPassword: [''],
)
onUpdatePassword()
this.alertService.alertPopup('test2', 'asfafa')
alert.service.ts
@Injectable()
export class AlertService
private subject = new Subject<any>();
private keepAfterNavigationChange = false;
constructor(
private router: Router,
private modalService: NgbModal,
)
alertPopup(title: string, content: string)
// open modal to check if worked over night
const modalRef = this.modalService.open(MessageDialogComponent);
modalRef.componentInstance.titleText = title
modalRef.componentInstance.bodyText = content
modalRef.result
.then(response =>
)
.catch(() =>
return
)
message-dialog.component.html
<div class="modal-header">
<h4 class="modal-title">titleText</h4>
</div>
<div class="modal-body">
<p>bodyText</p>
</div>
message-dialog.component.ts
export class MessageDialogComponent implements OnInit
@Input() titleText: string;
@Input() bodyText: string;
constructor(
public activeModal: NgbActiveModal,
)
ngOnInit()
【问题讨论】:
【参考方案1】:执行以下代码后似乎您的错误发生了:
ngAfterViewInit()
if (!this._elRef.nativeElement.contains(document.activeElement))
this._renderer.invokeElementMethod(this._elRef.nativeElement, 'focus', []);
https://github.com/ng-bootstrap/ng-bootstrap/blob/1.0.0-alpha.20/src/modal/modal-window.ts#L65
在input
上触发blur
事件,将您的控件标记为touched
。
它不适用于AccountComponent
,因为AccountComponent
中的检测更改发生在ngbModalContainer
之前,而app.component.html
中的FormGroup
获得正确的值。
可能的解决方案:
1) 在打开模式之前将控件标记为已触摸
account.component.ts
onUpdatePassword()
Object.keys(this.changePasswordForm.controls).forEach(key =>
this.changePasswordForm.controls[key].markAsTouched();
);
this.alertService.alertPopup('test2', 'asfafa')
2) 更改订单标签
app.component.html
<template ngbModalContainer></template>
<router-outlet> </router-outlet>
【讨论】:
非常感谢!使用选项 2 轻松修复!请问您确实发现了问题所在,因为错误代码对于问题出在哪里没有太大意义? 老实说,调试此类错误非常困难。你需要知道变化检测是如何工作的以及angular2是如何为每个组件生成factory
但是你做的这么快?我已经被困了好几天了。谢谢!
有没有办法单步调试代码以找出导致问题的函数?好像你找到了原因的确切位置。我坐在那里想这真假是从哪里来的【参考方案2】:
我什至遇到过同样的错误,
在你的 appComponent 中使用 ngAfterViewInit()
而不是 ngOnInit。
如果还是不行就试试
setTimeOut(function()
//Your Code
,1)
【讨论】:
我的 app.component.ts ngOnInit 中唯一的代码是 this.changePasswordForm = this.formBuilder.group.... 将其放入 ngAfterViewInit 将导致 formGroup 需要一个 FormGroup 实例错误。 setTimeout 函数也是如此。 如果你的代码放在 plnkr 上会更好,好的,我会从 github 获取并检查。 非常感谢伙计。我一直在努力解决这个问题。我不知道如何在 plunker 中设置它,因为它涉及到 angular material 2 和 bootstrap 类以使模态正常工作。 嘿,伙计。非常感谢您调查它。另一个解决方案有效,所以现在一切都很好。我只是将模板更改为 router-outlet 之前以上是关于Angular 2 模态弹出错误“检查后表达式已更改”的主要内容,如果未能解决你的问题,请参考以下文章
Angular UI Bootstrap - 模态不会在第一次点击时弹出