2017-04-21 4 views
11

mit kantigem (4.x) Ich verwende ReactiveForms und ich habe zu valueChanges auf meinem Formcontrol abonniert ("Input") wie folgt:ValueChanges auf Formcontrol auslöst, wenn Form.enable, auch mit emitEvent: false

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)); 
    } 

So jetzt kann ich auf Änderungen auf den Wert meiner FormControl reagieren, aber natürlich fülle ich die Werte des Formulars von irgendwo zu beginnen, also verwende ich form.patchValue(data), um dies zu tun.

Da dies keine Benutzeränderung ist, möchte ich nicht darauf reagieren, also fügen Sie das Flag emitEvent: false hinzu, wie: this.form.patchValue(data, {emitEvent: false}).

Das funktioniert wie erwartet.

Jetzt habe ich eine gewisse Logik, dass, wenn das Formular Laden ist, habe ich die ganze Form Behinderte, this.form.disable({ emitEvent: false }), und wenn Sie fertig Laden setzt er die ganze Form wieder aktiviert: this.form.disable({ emitEvent: false })

Aber ich habe auch eine Logik, die abhängig von verschiedenen Flaggen setzt die Formcontrol zu aktivieren/deaktivieren: this.formControl.enable({emitEvent: false});


das Problem, das ich jetzt bin sehen, dass, wenn die Form, Statuswechsel, die löst FormControl.valueChanges, obwohl ich die emitEvent: false Flagge zur Verfügung stellen.

Ist dies das erwartete Verhalten oder ein Fehler? Ich erwartete, dass überhaupt kein Ereignis ausgelöst wird, wenn die Flagge zur Verfügung gestellt wird?

Ich habe ein zupfen gemacht, wo dies hier getestet werden kann: https://plnkr.co/edit/RgyDItYtEfzlLVB6P5f3?p=preview

+1

Es scheint, dass dies in der Tat ein Problem: https://github.com/angular/angular/issues/12366 – Bulan

+0

nach der gleichen Quelle, Fixes wurden geschoben und Github Problem ist geschlossen. – Pac0

Antwort

7

beid disable() und enable() Funktionen (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); }); 
}; 

haben rufen:

this._updateAncestors(!!opts.onlySelf); 

welches die updateValueAndValidity() Funktion seines Elternteils ohneaufruftFlagge, die dann

this._valueChanges.emit(this._value); 

dies löst valueChanges Emitter des Formulars aufruft und Sie sehen in der Konsole:

Form.valueChanges: Object { input2: null } 

dies durch Form ausgelöst wird und nicht durch die default Eingabefeld Controller. Um die Aktualisierung der Vorfahren zu stoppen, müssen wir nur das zusätzliche Flag - onlySelf: true angeben, das angibt, nur seine eigenen und nicht die Vorfahren zu aktualisieren. in jedem Aufruf disable() oder enable() Funktionen Also, wo Sie nicht wollen, Vorfahren aktualisieren hinzufügen, um diesen Flag:

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 
    }); 
} 

dies das Problem für Blatt formControls (Kontrollen ohne Kinder) lösen, aber diese Linie

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

Anruf disable (oder enable) Funktion ohne bestanden emitEvent: false. Es sieht aus wie eckiger Fehler, daher können wir diese beiden Funktionen als Workaround überschreiben. Ersteinfuhr AbstractControl:

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

als beide Funktionen außer Kraft setzen:

// 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); }); 
}; 

aktualisiert Plunker: https://plnkr.co/edit/IIaByz4GlBREj2X9EKvx?p=preview

+0

Eine ausführliche und gute Antwort, schönes Graben, danke! Als "Beantwortet" markieren Sie dies, da es sich um einen Workaround handelt, solange der Fehler bestehen bleibt. – Bulan

Verwandte Themen