与.dirty的问题和.pristine booleans,就是一旦他们改变了,即使你撤销了你所介绍的所有改变,他们也不会回头。我设法找到解决这个问题的方法,创建一个监视整个表单变化的类,并用原始表单值检查更改后的值。这样,如果用户更改被撤销,表单可以返回到原始状态,或者可选地在您可以提供和订阅的可观察对象(ReplaySubject)上发布布尔值。
的使用将是这样的:
private _formIntactChecker:FormIntactChecker;
constructor(private _fb: FormBuilder) {
this._form = _fb.group({
...
});
// from now on, you can trust the .dirty and .pristine to reset
// if the user undoes his changes.
this._formIntactChecker = new FormIntactChecker(this._form);
}
可替换地,代替复位.pristine/.dirty布尔值的类可以被配置成发射一个布尔每当从完整形式变成了已修改和反之亦然。一个真正的布尔表示,表单回到完好无损,而假布尔意味着表单不再完整。
这里有一个关于你将如何使用它的一个例子:
private _formIntactChecker:FormIntactChecker;
constructor(private _fb: FormBuilder) {
this._form = _fb.group({
...
});
var rs = new ReplaySubject()
rs.subscribe((isIntact: boolean) => {
if (isIntact) {
// do something if form went back to intact
} else {
// do something if form went dirty
}
})
// When using the class with a ReplaySubject, the .pristine/.dirty
// will not change their behaviour, even if the user undoes his changes,
// but we can do whatever we want in the subject's subscription.
this._formChecker = new FormIntactChecker(this._form, rs);
}
最后,做类中的所有工作:
import { FormGroup } from '@angular/forms';
import { ReplaySubject } from 'rxjs';
export class FormIntactChecker {
private _originalValue:any;
private _lastNotify:boolean;
constructor(private _form: FormGroup, private _replaySubject?:ReplaySubject<boolean>) {
// When the form loads, changes are made for each control separately
// and it is hard to determine when it has actually finished initializing,
// To solve it, we keep updating the original value, until the form goes
// dirty. When it does, we no longer update the original value.
this._form.statusChanges.subscribe(change => {
if(!this._form.dirty) {
this._originalValue = JSON.stringify(this._form.value);
}
})
// Every time the form changes, we compare it with the original value.
// If it is different, we emit a value to the Subject (if one was provided)
// If it is the same, we emit a value to the Subject (if one was provided), or
// we mark the form as pristine again.
this._form.valueChanges.subscribe(changedValue => {
if(this._form.dirty) {
var current_value = JSON.stringify(this._form.value);
if (this._originalValue != current_value) {
if(this._replaySubject && (this._lastNotify == null || this._lastNotify == true)) {
this._replaySubject.next(false);
this._lastNotify = false;
}
} else {
if(this._replaySubject)
this._replaySubject.next(true);
else
this._form.markAsPristine();
this._lastNotify = true;
}
}
})
}
// This method can be call to make the current values of the
// form, the new "orginal" values. This method is useful when
// you save the contents of the form but keep it on screen. From
// now on, the new values are to be considered the original values
markIntact() {
this._originalValue = JSON.stringify(this._form.value);
if(this._replaySubject)
this._replaySubject.next(true);
else
this._form.markAsPristine();
this._lastNotify = true;
}
}
重要提示:小心与初始值
该类使用JSON.stringify()
快速比较整个formGroup值对象。但是,初始化控制值时要小心。
例如,对于复选框,您必须将绑定它的值设置为布尔值。如果您使用其他类型,如“已选中”,“0”,“1”等,则比较将无法正常工作。
<input type="checkbox" ... [(ngModel)]="variable"> <!-- variable must be a boolean -->
同去<select>
,你必须将其值绑定到一个字符串,而不是一个数字:
<select ... [(ngModel)]="variable"> <!-- variable must be a string -->
对于普通的文本输入控件,也可以使用一个字符串:
<input type="text" ... [(ngModel)]="variable"> <!-- variable must be a string -->
这是一个例子,为什么否则它不会工作。假设你有一个文本字段,并用一个整数初始化它。原始值的字符串化将是这样的:
{字段1:34,场2:“一些文本字段”}
但是,如果用户更新FIELD1为不同的值,并可以追溯到34,新的字符串化将是:
{场:“34”,场2:“一些文本字段”}
正如你所看到的,虽然形式并没有真正改变,原来和之间的字符串比较新的价值将导致错误的,由于引号数34左右。
可能的重复[如何观察Angular 2中的表单变化?](http://stackoverflow.com/questions/34615425/how-to-watch-for-form-changes-in-angular-2) – blo0p3r