與.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