@@ -28,13 +28,15 @@ import {
28
28
Output ,
29
29
QueryList ,
30
30
ViewEncapsulation ,
31
+ InjectionToken ,
31
32
} from '@angular/core' ;
32
33
import { DOCUMENT } from '@angular/common' ;
33
34
import { merge } from 'rxjs/observable/merge' ;
34
35
import { filter } from 'rxjs/operators/filter' ;
35
36
import { take } from 'rxjs/operators/take' ;
36
37
import { startWith } from 'rxjs/operators/startWith' ;
37
38
import { takeUntil } from 'rxjs/operators/takeUntil' ;
39
+ import { debounceTime } from 'rxjs/operators/debounceTime' ;
38
40
import { map } from 'rxjs/operators/map' ;
39
41
import { Subject } from 'rxjs/Subject' ;
40
42
import { Observable } from 'rxjs/Observable' ;
@@ -54,6 +56,9 @@ export class MatDrawerToggleResult {
54
56
constructor ( public type : 'open' | 'close' , public animationFinished : boolean ) { }
55
57
}
56
58
59
+ /** Configures whether drawers should use auto sizing by default. */
60
+ export const MAT_DRAWER_DEFAULT_AUTOSIZE =
61
+ new InjectionToken < boolean > ( 'MAT_DRAWER_DEFAULT_AUTOSIZE' ) ;
57
62
58
63
@Component ( {
59
64
moduleId : module . id ,
@@ -74,7 +79,7 @@ export class MatDrawerContent implements AfterContentInit {
74
79
* drawer is open. We use margin rather than transform even for push mode because transform breaks
75
80
* fixed position elements inside of the transformed element.
76
81
*/
77
- _margins : { left : number , right : number } = { left : 0 , right : 0 } ;
82
+ _margins : { left : number | null , right : number | null } = { left : null , right : null } ;
78
83
79
84
constructor (
80
85
private _changeDetectorRef : ChangeDetectorRef ,
@@ -403,7 +408,6 @@ export class MatDrawer implements AfterContentInit, OnDestroy {
403
408
} )
404
409
export class MatDrawerContainer implements AfterContentInit , OnDestroy {
405
410
@ContentChildren ( MatDrawer ) _drawers : QueryList < MatDrawer > ;
406
-
407
411
@ContentChild ( MatDrawerContent ) _content : MatDrawerContent ;
408
412
409
413
/** The drawer child with the `start` position. */
@@ -412,6 +416,19 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
412
416
/** The drawer child with the `end` position. */
413
417
get end ( ) : MatDrawer | null { return this . _end ; }
414
418
419
+ /**
420
+ * Whether to automatically resize the container whenever
421
+ * the size of any of its drawers changes.
422
+ *
423
+ * **Use at your own risk!** Enabling this option can cause layout thrashing by measuring
424
+ * the drawers on every change detection cycle. Can be configured globally via the
425
+ * `MAT_DRAWER_DEFAULT_AUTOSIZE` token.
426
+ */
427
+ @Input ( )
428
+ get autosize ( ) : boolean { return this . _autosize ; }
429
+ set autosize ( value : boolean ) { this . _autosize = coerceBooleanProperty ( value ) ; }
430
+ private _autosize : boolean ;
431
+
415
432
/** Event emitted when the drawer backdrop is clicked. */
416
433
@Output ( ) backdropClick = new EventEmitter < void > ( ) ;
417
434
@@ -431,15 +448,23 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
431
448
/** Emits when the component is destroyed. */
432
449
private _destroyed = new Subject < void > ( ) ;
433
450
434
- _contentMargins = new Subject < { left : number , right : number } > ( ) ;
451
+ /** Emits on every ngDoCheck. Used for debouncing reflows. */
452
+ private _doCheckSubject = new Subject < void > ( ) ;
453
+
454
+ _contentMargins = new Subject < { left : number | null , right : number | null } > ( ) ;
435
455
436
- constructor ( @Optional ( ) private _dir : Directionality , private _element : ElementRef ,
437
- private _ngZone : NgZone , private _changeDetectorRef : ChangeDetectorRef ) {
456
+ constructor ( @Optional ( ) private _dir : Directionality ,
457
+ private _element : ElementRef ,
458
+ private _ngZone : NgZone ,
459
+ private _changeDetectorRef : ChangeDetectorRef ,
460
+ @Inject ( MAT_DRAWER_DEFAULT_AUTOSIZE ) defaultAutosize = false ) {
438
461
// If a `Dir` directive exists up the tree, listen direction changes and update the left/right
439
462
// properties to point to the proper start/end.
440
463
if ( _dir != null ) {
441
464
_dir . change . pipe ( takeUntil ( this . _destroyed ) ) . subscribe ( ( ) => this . _validateDrawers ( ) ) ;
442
465
}
466
+
467
+ this . _autosize = defaultAutosize ;
443
468
}
444
469
445
470
ngAfterContentInit ( ) {
@@ -460,9 +485,15 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
460
485
461
486
this . _changeDetectorRef . markForCheck ( ) ;
462
487
} ) ;
488
+
489
+ this . _doCheckSubject . pipe (
490
+ debounceTime ( 10 ) , // Arbitrary debounce time, less than a frame at 60fps
491
+ takeUntil ( this . _destroyed )
492
+ ) . subscribe ( ( ) => this . _updateContentMargins ( ) ) ;
463
493
}
464
494
465
495
ngOnDestroy ( ) {
496
+ this . _doCheckSubject . complete ( ) ;
466
497
this . _destroyed . next ( ) ;
467
498
this . _destroyed . complete ( ) ;
468
499
}
@@ -477,6 +508,14 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
477
508
this . _drawers . forEach ( drawer => drawer . close ( ) ) ;
478
509
}
479
510
511
+ ngDoCheck ( ) {
512
+ // If users opted into autosizing, do a check every change detection cycle.
513
+ if ( this . _autosize && this . _isPushed ( ) ) {
514
+ // Run outside the NgZone, otherwise the debouncer will throw us into an infinite loop.
515
+ this . _ngZone . runOutsideAngular ( ( ) => this . _doCheckSubject . next ( ) ) ;
516
+ }
517
+ }
518
+
480
519
/**
481
520
* Subscribes to drawer events in order to set a class on the main container element when the
482
521
* drawer is open and the backdrop is visible. This ensures any overflow on the container element
@@ -572,6 +611,12 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
572
611
}
573
612
}
574
613
614
+ /** Whether the container is being pushed to the side by one of the drawers. */
615
+ private _isPushed ( ) {
616
+ return ( this . _isDrawerOpen ( this . _start ) && this . _start ! . mode != 'over' ) ||
617
+ ( this . _isDrawerOpen ( this . _end ) && this . _end ! . mode != 'over' ) ;
618
+ }
619
+
575
620
_onBackdropClicked ( ) {
576
621
this . backdropClick . emit ( ) ;
577
622
this . _closeModalDrawer ( ) ;
@@ -628,6 +673,7 @@ export class MatDrawerContainer implements AfterContentInit, OnDestroy {
628
673
}
629
674
}
630
675
631
- this . _contentMargins . next ( { left, right} ) ;
676
+ // Pull back into the NgZone since in some cases we could be outside.
677
+ this . _ngZone . run ( ( ) => this . _contentMargins . next ( { left, right} ) ) ;
632
678
}
633
679
}
0 commit comments