Skip to content

Commit b2e728d

Browse files
committedAug 13, 2024·
fix(material/form-field): update state if control changes (#29573)
Fixes that the form field wasn't accounting for the case where the form control is swapped out. Fixes #29402. (cherry picked from commit ec35e99)
1 parent dd500b1 commit b2e728d

File tree

1 file changed

+23
-8
lines changed

1 file changed

+23
-8
lines changed
 

‎src/material/form-field/form-field.ts

+23-8
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import {
3737
} from '@angular/core';
3838
import {AbstractControlDirective} from '@angular/forms';
3939
import {ThemePalette} from '@angular/material/core';
40-
import {Subject, merge} from 'rxjs';
40+
import {Subject, Subscription, merge} from 'rxjs';
4141
import {takeUntil} from 'rxjs/operators';
4242
import {MAT_ERROR, MatError} from './directives/error';
4343
import {
@@ -318,6 +318,9 @@ export class MatFormField
318318
private _isFocused: boolean | null = null;
319319
private _explicitFormFieldControl: MatFormFieldControl<any>;
320320
private _needsOutlineLabelOffsetUpdate = false;
321+
private _previousControl: MatFormFieldControl<unknown> | null = null;
322+
private _stateChanges: Subscription | undefined;
323+
private _valueChanges: Subscription | undefined;
321324

322325
private _injector = inject(Injector);
323326

@@ -365,17 +368,23 @@ export class MatFormField
365368

366369
ngAfterContentInit() {
367370
this._assertFormFieldControl();
368-
this._initializeControl();
369371
this._initializeSubscript();
370372
this._initializePrefixAndSuffix();
371373
this._initializeOutlineLabelOffsetSubscriptions();
372374
}
373375

374376
ngAfterContentChecked() {
375377
this._assertFormFieldControl();
378+
379+
if (this._control !== this._previousControl) {
380+
this._initializeControl(this._previousControl);
381+
this._previousControl = this._control;
382+
}
376383
}
377384

378385
ngOnDestroy() {
386+
this._stateChanges?.unsubscribe();
387+
this._valueChanges?.unsubscribe();
379388
this._destroyed.next();
380389
this._destroyed.complete();
381390
}
@@ -409,25 +418,31 @@ export class MatFormField
409418
}
410419

411420
/** Initializes the registered form field control. */
412-
private _initializeControl() {
421+
private _initializeControl(previousControl: MatFormFieldControl<unknown> | null) {
413422
const control = this._control;
423+
const classPrefix = 'mat-mdc-form-field-type-';
424+
425+
if (previousControl) {
426+
this._elementRef.nativeElement.classList.remove(classPrefix + previousControl.controlType);
427+
}
414428

415429
if (control.controlType) {
416-
this._elementRef.nativeElement.classList.add(
417-
`mat-mdc-form-field-type-${control.controlType}`,
418-
);
430+
this._elementRef.nativeElement.classList.add(classPrefix + control.controlType);
419431
}
420432

421433
// Subscribe to changes in the child control state in order to update the form field UI.
422-
control.stateChanges.subscribe(() => {
434+
this._stateChanges?.unsubscribe();
435+
this._stateChanges = control.stateChanges.subscribe(() => {
423436
this._updateFocusState();
424437
this._syncDescribedByIds();
425438
this._changeDetectorRef.markForCheck();
426439
});
427440

441+
this._valueChanges?.unsubscribe();
442+
428443
// Run change detection if the value changes.
429444
if (control.ngControl && control.ngControl.valueChanges) {
430-
control.ngControl.valueChanges
445+
this._valueChanges = control.ngControl.valueChanges
431446
.pipe(takeUntil(this._destroyed))
432447
.subscribe(() => this._changeDetectorRef.markForCheck());
433448
}

0 commit comments

Comments
 (0)
Please sign in to comment.