@@ -17,6 +17,7 @@ import {
17
17
ContentChild ,
18
18
ContentChildren ,
19
19
ElementRef ,
20
+ inject ,
20
21
Inject ,
21
22
InjectionToken ,
22
23
Input ,
@@ -30,8 +31,8 @@ import {
30
31
import { AbstractControlDirective } from '@angular/forms' ;
31
32
import { ThemePalette } from '@angular/material/core' ;
32
33
import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations' ;
33
- import { merge , Subject } from 'rxjs' ;
34
- import { takeUntil } from 'rxjs/operators' ;
34
+ import { EMPTY , merge , Observable , Subject } from 'rxjs' ;
35
+ import { map , switchMap , takeUntil } from 'rxjs/operators' ;
35
36
import { MAT_ERROR , MatError } from './directives/error' ;
36
37
import {
37
38
FLOATING_LABEL_PARENT ,
@@ -52,6 +53,7 @@ import {
52
53
getMatFormFieldMissingControlError ,
53
54
} from './form-field-errors' ;
54
55
import { DOCUMENT } from '@angular/common' ;
56
+ import { SharedResizeObserver } from '@angular/cdk/observers/private' ;
55
57
56
58
/** Type for the available floatLabel values. */
57
59
export type FloatLabelType = 'always' | 'auto' ;
@@ -284,6 +286,9 @@ export class MatFormField
284
286
private _isFocused : boolean | null = null ;
285
287
private _explicitFormFieldControl : MatFormFieldControl < any > ;
286
288
private _needsOutlineLabelOffsetUpdateOnStable = false ;
289
+ private _needsOutlineLabelPrefixResizeObserverUpdateOnStable = true ;
290
+
291
+ private _resizeObserver = inject ( SharedResizeObserver ) ;
287
292
288
293
constructor (
289
294
public _elementRef : ElementRef ,
@@ -473,10 +478,16 @@ export class MatFormField
473
478
* checking every change detection cycle.
474
479
*/
475
480
private _initializeOutlineLabelOffsetSubscriptions ( ) {
476
- // Whenever the prefix changes, schedule an update of the label offset.
477
- this . _prefixChildren . changes . subscribe (
478
- ( ) => ( this . _needsOutlineLabelOffsetUpdateOnStable = true ) ,
479
- ) ;
481
+ // Whenever the prefix changes, schedule an update for label offset.
482
+ this . _prefixChildren . changes . pipe ( map ( prefixes => ! ! prefixes . length ) ) . subscribe ( hasPrefix => {
483
+ // If there are any prefix, schedule an update for their resize observer.
484
+ // Otherwise, just schedule an update for label offset.
485
+ if ( hasPrefix ) {
486
+ this . _needsOutlineLabelPrefixResizeObserverUpdateOnStable = true ;
487
+ } else {
488
+ this . _needsOutlineLabelOffsetUpdateOnStable = true ;
489
+ }
490
+ } ) ;
480
491
481
492
// Note that we have to run outside of the `NgZone` explicitly, in order to avoid
482
493
// throwing users into an infinite loop if `zone-patch-rxjs` is included.
@@ -487,6 +498,18 @@ export class MatFormField
487
498
this . _updateOutlineLabelOffset ( ) ;
488
499
}
489
500
} ) ;
501
+
502
+ this . _ngZone . onStable
503
+ . pipe (
504
+ switchMap ( ( ) => this . _resizeObserver . observe ( this . _elementRef . nativeElement ) ) ,
505
+ takeUntil ( this . _destroyed ) ,
506
+ )
507
+ . subscribe ( ( ) => {
508
+ if ( this . _needsOutlineLabelPrefixResizeObserverUpdateOnStable ) {
509
+ this . _needsOutlineLabelPrefixResizeObserverUpdateOnStable = false ;
510
+ this . _updateOutlineLabelOffsetOnPrefixResize ( ) ;
511
+ }
512
+ } ) ;
490
513
} ) ;
491
514
492
515
this . _dir . change
@@ -672,6 +695,23 @@ export class MatFormField
672
695
)` ;
673
696
}
674
697
698
+ /**
699
+ * Updates the horizontal offset of the label in the outline appearance when the prefix containers are resized.
700
+ */
701
+ private _updateOutlineLabelOffsetOnPrefixResize ( ) {
702
+ const iconPrefixContainer = this . _iconPrefixContainer ?. nativeElement ;
703
+ const textPrefixContainer = this . _textPrefixContainer ?. nativeElement ;
704
+
705
+ merge (
706
+ iconPrefixContainer ? this . _resizeObserver . observe ( iconPrefixContainer ) : EMPTY ,
707
+ textPrefixContainer ? this . _resizeObserver . observe ( textPrefixContainer ) : EMPTY ,
708
+ )
709
+ . pipe ( takeUntil ( this . _prefixChildren . changes ) )
710
+ . subscribe ( ( ) => {
711
+ this . _updateOutlineLabelOffset ( ) ;
712
+ } ) ;
713
+ }
714
+
675
715
/** Checks whether the form field is attached to the DOM. */
676
716
private _isAttachedToDom ( ) : boolean {
677
717
const element : HTMLElement = this . _elementRef . nativeElement ;
0 commit comments