@@ -29,13 +29,15 @@ import {
2929 QueryList ,
3030 Renderer2 ,
3131 ViewEncapsulation ,
32+ InjectionToken ,
3233} from '@angular/core' ;
3334import { DOCUMENT } from '@angular/platform-browser' ;
3435import { merge } from 'rxjs/observable/merge' ;
3536import { filter } from 'rxjs/operators/filter' ;
3637import { first } from 'rxjs/operators/first' ;
3738import { startWith } from 'rxjs/operators/startWith' ;
3839import { takeUntil } from 'rxjs/operators/takeUntil' ;
40+ import { debounceTime } from 'rxjs/operators/debounceTime' ;
3941import { map } from 'rxjs/operators/map' ;
4042import { Subject } from 'rxjs/Subject' ;
4143import { Observable } from 'rxjs/Observable' ;
@@ -55,6 +57,9 @@ export class MatDrawerToggleResult {
5557 constructor ( public type : 'open' | 'close' , public animationFinished : boolean ) { }
5658}
5759
60+ /** Configures whether drawers should use auto sizing by default. */
61+ export const MAT_DRAWER_DEFAULT_AUTOSIZE =
62+ new InjectionToken < boolean > ( 'MAT_DRAWER_DEFAULT_AUTOSIZE' ) ;
5863
5964@Component ( {
6065 moduleId : module . id ,
@@ -404,7 +409,6 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
404409} )
405410export class MatDrawerContainer implements AfterContentInit , OnDestroy {
406411 @ContentChildren ( MatDrawer ) _drawers : QueryList < MatDrawer > ;
407-
408412 @ContentChild ( MatDrawerContent ) _content : MatDrawerContent ;
409413
410414 /** The drawer child with the `start` position. */
@@ -413,6 +417,19 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
413417 /** The drawer child with the `end` position. */
414418 get end ( ) : MatDrawer | null { return this . _end ; }
415419
420+ /**
421+ * Whether to automatically resize the container whenever
422+ * the size of any of its drawers changes.
423+ *
424+ * **Use at your own risk!** Enabling this option can cause layout thrashing by measuring
425+ * the drawers on every change detection cycle. Can be configured globally via the
426+ * `MAT_DRAWER_DEFAULT_AUTOSIZE` token.
427+ */
428+ @Input ( )
429+ get autosize ( ) : boolean { return this . _autosize ; }
430+ set autosize ( value : boolean ) { this . _autosize = coerceBooleanProperty ( value ) ; }
431+ private _autosize : boolean ;
432+
416433 /** Event emitted when the drawer backdrop is clicked. */
417434 @Output ( ) backdropClick = new EventEmitter < void > ( ) ;
418435
@@ -432,16 +449,27 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
432449 /** Emits when the component is destroyed. */
433450 private _destroyed = new Subject < void > ( ) ;
434451
452+ /** Cached margins used to verify that the values have changed. */
453+ private _margins = { left : 0 , right : 0 } ;
454+
455+ /** Emits on every ngDoCheck. Used for debouncing reflows. */
456+ private _doCheckSubject = new Subject < void > ( ) ;
457+
435458 _contentMargins = new Subject < { left : number , right : number } > ( ) ;
436459
437- constructor ( @Optional ( ) private _dir : Directionality , private _element : ElementRef ,
438- private _renderer : Renderer2 , private _ngZone : NgZone ,
439- private _changeDetectorRef : ChangeDetectorRef ) {
460+ constructor ( @Optional ( ) private _dir : Directionality ,
461+ private _element : ElementRef ,
462+ private _renderer : Renderer2 ,
463+ private _ngZone : NgZone ,
464+ private _changeDetectorRef : ChangeDetectorRef ,
465+ @Inject ( MAT_DRAWER_DEFAULT_AUTOSIZE ) defaultAutosize = false ) {
440466 // If a `Dir` directive exists up the tree, listen direction changes and update the left/right
441467 // properties to point to the proper start/end.
442468 if ( _dir != null ) {
443469 _dir . change . pipe ( takeUntil ( this . _destroyed ) ) . subscribe ( ( ) => this . _validateDrawers ( ) ) ;
444470 }
471+
472+ this . _autosize = defaultAutosize ;
445473 }
446474
447475 ngAfterContentInit ( ) {
@@ -462,9 +490,15 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
462490
463491 this . _changeDetectorRef . markForCheck ( ) ;
464492 } ) ;
493+
494+ this . _doCheckSubject . pipe (
495+ debounceTime ( 10 ) , // Arbitrary debounce time, less than a frame at 60fps
496+ takeUntil ( this . _destroyed )
497+ ) . subscribe ( ( ) => this . _updateContentMargins ( ) ) ;
465498 }
466499
467500 ngOnDestroy ( ) {
501+ this . _doCheckSubject . complete ( ) ;
468502 this . _destroyed . next ( ) ;
469503 this . _destroyed . complete ( ) ;
470504 }
@@ -479,6 +513,14 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
479513 this . _drawers . forEach ( drawer => drawer . close ( ) ) ;
480514 }
481515
516+ ngDoCheck ( ) {
517+ // If users opted into autosizing, do a check every change detection cycle.
518+ if ( this . _autosize && this . _isPushed ( ) ) {
519+ // Run outside the NgZone, otherwise the debouncer will throw us into an infinite loop.
520+ this . _ngZone . runOutsideAngular ( ( ) => this . _doCheckSubject . next ( ) ) ;
521+ }
522+ }
523+
482524 /**
483525 * Subscribes to drawer events in order to set a class on the main container element when the
484526 * drawer is open and the backdrop is visible. This ensures any overflow on the container element
@@ -574,6 +616,12 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
574616 }
575617 }
576618
619+ /** Whether the container is being pushed to the side by one of the drawers. */
620+ private _isPushed ( ) {
621+ return ( this . _isDrawerOpen ( this . _start ) && this . _start ! . mode != 'over' ) ||
622+ ( this . _isDrawerOpen ( this . _end ) && this . _end ! . mode != 'over' ) ;
623+ }
624+
577625 _onBackdropClicked ( ) {
578626 this . backdropClick . emit ( ) ;
579627 this . _closeModalDrawer ( ) ;
@@ -630,6 +678,12 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
630678 }
631679 }
632680
633- this . _contentMargins . next ( { left, right} ) ;
681+ if ( left !== this . _margins . left || right !== this . _margins . right ) {
682+ this . _margins . left = left ;
683+ this . _margins . right = right ;
684+
685+ // Pull back into the NgZone since in some cases we could be outside.
686+ this . _ngZone . run ( ( ) => this . _contentMargins . next ( this . _margins ) ) ;
687+ }
634688 }
635689}
0 commit comments