2017-04-21 32 views
11

具有角(4.x的)我用ReactiveForms,我已經訂閱valueChanges我FormControl( 「輸入」),像這樣:ValueChanges觸發時Form.enable,即使emitEvent:假

export class App { 
    version:string; 
    formControl = new FormControl('default', []); 
    form = this.fb.group({ 
     input: this.formControl, 
     input2: ('',[]) 
    }); 

    constructor(private fb: FormBuilder) { 
    this.version = `Angular v${VERSION.full}` 
    } 

    ngOnInit() { 
    this.formControl.valueChanges.subscribe(value => doSomething(value)); 
    } 

所以現在我可以對我的FormControl的值的變化作出反應,但我當然從某處開始填充表單的值,所以我使用form.patchValue(data)來做到這一點。

由於這不是用戶更改,我不想對此作出反應,因此請添加標記emitEvent: false,如:this.form.patchValue(data, {emitEvent: false})

按預期工作。

現在我有一些邏輯,當窗體加載,我把整個窗體爲禁用,this.form.disable({ emitEvent: false }),並完成加載時,它會將整個形式再次啓用:this.form.disable({ emitEvent: false })

但我也有邏輯根據不同的標誌設置FormControl來啓用/禁用:this.formControl.enable({emitEvent: false});


現在我看到的問題是,當Form,狀態改變時,會觸發FormControl.valueChanges,即使我提供emitEvent: false標誌。

這是預期的行爲還是錯誤? 我希望提供國旗時根本不會觸發任何事件?

我做了一個普拉克這個地方可以在這​​裏進行測試: https://plnkr.co/edit/RgyDItYtEfzlLVB6P5f3?p=preview

+1

看來,這確實是一個錯誤: https://github.com/angular/angular/issues/12366 – Bulan

+0

根據同一來源,修復程序已被推送並且github問題已關閉。 – Pac0

回答

7

兩個disable()enable()功能(code source):

/** 
* Disables the control. This means the control will be exempt from validation checks and 
* excluded from the aggregate value of any parent. Its status is `DISABLED`. 
* 
* If the control has children, all children will be disabled to maintain the model. 
* @param {?=} opts 
* @return {?} 
*/ 
AbstractControl.prototype.disable = function (opts) { 
    if (opts === void 0) { opts = {}; } 
    this._status = DISABLED; 
    this._errors = null; 
    this._forEachChild(function (control) { control.disable({ onlySelf: true }); }); 
    this._updateValue(); 
    if (opts.emitEvent !== false) { 
     this._valueChanges.emit(this._value); 
     this._statusChanges.emit(this._status); 
    } 
    this._updateAncestors(!!opts.onlySelf); 
    this._onDisabledChange.forEach(function (changeFn) { return changeFn(true); }); 
}; 
/** 
* Enables the control. This means the control will be included in validation checks and 
* the aggregate value of its parent. Its status is re-calculated based on its value and 
* its validators. 
* 
* If the control has children, all children will be enabled. 
* @param {?=} opts 
* @return {?} 
*/ 
AbstractControl.prototype.enable = function (opts) { 
    if (opts === void 0) { opts = {}; } 
    this._status = VALID; 
    this._forEachChild(function (control) { control.enable({ onlySelf: true }); }); 
    this.updateValueAndValidity({ onlySelf: true, emitEvent: opts.emitEvent }); 
    this._updateAncestors(!!opts.onlySelf); 
    this._onDisabledChange.forEach(function (changeFn) { return changeFn(false); }); 
}; 

已經打電話:

this._updateAncestors(!!opts.onlySelf); 

其中調用其父母的updateValueAndValidity()函數沒有emitEvent標誌,然後調用

this._valueChanges.emit(this._value); 

這會觸發valueChanges發射器的形式,你在控制檯中看到:

Form.valueChanges: Object { input2: null } 

這是由表格,而不是由default輸入域控制器的觸發。 爲了阻止祖先更新,我們只需要提供附加標誌 - onlySelf: true,它告訴只更新其自身而不更新祖先。 因此,在每次調用disable()enable()功能,在您不希望更新的祖先添加此標誌:

disable(){ 
    this.form.disable({ 
    onlySelf: true, 
    emitEvent: false 
    }); 
} 

disableWEvent(){ 
    this.form.disable({ 
    onlySelf: true 
    }); 
} 

enable(){ 
    this.form.enable({ 
    onlySelf: true, 
    emitEvent: false 
    }); 
} 

enableWEvent(){ 
    this.form.enable({ 
    onlySelf: true 
    }); 
} 

disableCtrl(){ 
    this.formControl.disable({ 
    onlySelf: true, 
    emitEvent: false 
    }); 
} 

disableCtrlWEvent(){ 
    this.formControl.disable({ 
    onlySelf: true 
    }); 
} 

enableCtrl(){ 
    this.formControl.enable({ 
    onlySelf: true, 
    emitEvent: false 
    }); 
} 

enableCtrlWEvent(){ 
    this.formControl.enable({ 
    onlySelf: true 
    }); 
} 

這將解決葉formControls(無子控件)的問題,但此行

this._forEachChild(function (control) { control.disable({ onlySelf: true }); }); 

將調用disable(或enable)函數未通過emitEvent: false。它看起來像一個角度錯誤,所以,作爲解決方法,我們可以重寫這兩個函數。 首次進口AbstractControl

import {ReactiveFormsModule, FormBuilder, FormControl, Validators, AbstractControl} from '@angular/forms' 

比覆蓋這兩個函數:

// OVERRIDE disable and enable methods 
// https://github.com/angular/angular/issues/12366 
// https://github.com/angular/angular/blob/c59c390cdcd825cca67a422bc8738f7cd9ad42c5/packages/forms/src/model.ts#L318 
AbstractControl.prototype.disable = function (opts) { 
    if (opts === void 0) { opts = {}; } 
    this._status = 'DISABLED'; 
    this._errors = null; 
    this._forEachChild(function (control) { 
    control.disable(Object.assign(opts, {onlySelf: true})); 
    }); 
    this._updateValue(); 
    if (opts.emitEvent !== false) { 
     this._valueChanges.emit(this._value); 
     this._statusChanges.emit(this._status); 
    } 
    this._updateAncestors(!!opts.onlySelf); 
    this._onDisabledChange.forEach(function (changeFn) { return changeFn(true); }); 
}; 
AbstractControl.prototype.enable = function (opts) { 
    if (opts === void 0) { opts = {}; } 
    this._status = 'VALID'; 
    this._forEachChild(function (control) { 
    control.enable(Object.assign(opts, {onlySelf: true})); 
    }); 
    this.updateValueAndValidity({ onlySelf: true, emitEvent: opts.emitEvent }); 
    this._updateAncestors(!!opts.onlySelf); 
    this._onDisabledChange.forEach(function (changeFn) { return changeFn(false); }); 
}; 

更新plunker:https://plnkr.co/edit/IIaByz4GlBREj2X9EKvx?p=preview

+0

廣泛和好的答案,很好的挖掘,謝謝!標記爲已回答此問題,因爲只要該錯誤仍然存​​在,這是一種解決方法。 – Bulan