@@ -17,15 +17,13 @@ import {
17
17
ChangeDetectionStrategy ,
18
18
Component ,
19
19
ContentChild ,
20
- ContentChildren ,
21
20
ElementRef ,
22
21
EventEmitter ,
23
22
Inject ,
24
23
InjectionToken ,
25
24
Input ,
26
25
OnDestroy ,
27
26
Output ,
28
- QueryList ,
29
27
TemplateRef ,
30
28
ViewChild ,
31
29
ViewEncapsulation ,
@@ -35,14 +33,16 @@ import {
35
33
import { Observable } from 'rxjs/Observable' ;
36
34
import { merge } from 'rxjs/observable/merge' ;
37
35
import { Subscription } from 'rxjs/Subscription' ;
36
+ import { Subject } from 'rxjs/Subject' ;
38
37
import { matMenuAnimations } from './menu-animations' ;
39
38
import { throwMatMenuInvalidPositionX , throwMatMenuInvalidPositionY } from './menu-errors' ;
40
39
import { MatMenuItem } from './menu-item' ;
41
- import { MatMenuPanel } from './menu-panel' ;
40
+ import { MatMenuPanel , MAT_MENU_PANEL } from './menu-panel' ;
42
41
import { MatMenuContent } from './menu-content' ;
43
42
import { MenuPositionX , MenuPositionY } from './menu-positions' ;
44
43
import { coerceBooleanProperty } from '@angular/cdk/coercion' ;
45
44
import { FocusOrigin } from '@angular/cdk/a11y' ;
45
+ import { AnimationEvent } from '@angular/animations' ;
46
46
47
47
48
48
/** Default `mat-menu` options that can be overridden. */
@@ -76,18 +76,27 @@ const MAT_MENU_BASE_ELEVATION = 2;
76
76
changeDetection : ChangeDetectionStrategy . OnPush ,
77
77
encapsulation : ViewEncapsulation . None ,
78
78
preserveWhitespaces : false ,
79
+ exportAs : 'matMenu' ,
79
80
animations : [
80
81
matMenuAnimations . transformMenu ,
81
82
matMenuAnimations . fadeInItems
82
83
] ,
83
- exportAs : 'matMenu'
84
+ providers : [
85
+ { provide : MAT_MENU_PANEL , useExisting : MatMenu }
86
+ ]
84
87
} )
85
- export class MatMenu implements OnInit , AfterContentInit , MatMenuPanel , OnDestroy {
88
+ export class MatMenu implements OnInit , AfterContentInit , MatMenuPanel < MatMenuItem > , OnDestroy {
86
89
private _keyManager : FocusKeyManager < MatMenuItem > ;
87
90
private _xPosition : MenuPositionX = this . _defaultOptions . xPosition ;
88
91
private _yPosition : MenuPositionY = this . _defaultOptions . yPosition ;
89
92
private _previousElevation : string ;
90
93
94
+ /** Menu items inside the current menu. */
95
+ private _items : MatMenuItem [ ] = [ ] ;
96
+
97
+ /** Emits whenever the amount of menu items changes. */
98
+ private _itemChanges = new Subject < MatMenuItem [ ] > ( ) ;
99
+
91
100
/** Subscription to tab events on the menu panel */
92
101
private _tabSubscription = Subscription . EMPTY ;
93
102
@@ -97,6 +106,12 @@ export class MatMenu implements OnInit, AfterContentInit, MatMenuPanel, OnDestro
97
106
/** Current state of the panel animation. */
98
107
_panelAnimationState : 'void' | 'enter' = 'void' ;
99
108
109
+ /** Emits whenever an animation on the menu completes. */
110
+ _animationDone = new Subject < AnimationEvent > ( ) ;
111
+
112
+ /** Whether the menu is animating. */
113
+ _isAnimating : boolean ;
114
+
100
115
/** Parent menu of the current menu panel. */
101
116
parentMenu : MatMenuPanel | undefined ;
102
117
@@ -128,9 +143,6 @@ export class MatMenu implements OnInit, AfterContentInit, MatMenuPanel, OnDestro
128
143
/** @docs -private */
129
144
@ViewChild ( TemplateRef ) templateRef : TemplateRef < any > ;
130
145
131
- /** List of the items inside of a menu. */
132
- @ContentChildren ( MatMenuItem ) items : QueryList < MatMenuItem > ;
133
-
134
146
/**
135
147
* Menu content that will be rendered lazily.
136
148
* @docs -private
@@ -196,7 +208,7 @@ export class MatMenu implements OnInit, AfterContentInit, MatMenuPanel, OnDestro
196
208
}
197
209
198
210
ngAfterContentInit ( ) {
199
- this . _keyManager = new FocusKeyManager < MatMenuItem > ( this . items ) . withWrap ( ) . withTypeAhead ( ) ;
211
+ this . _keyManager = new FocusKeyManager < MatMenuItem > ( this . _items ) . withWrap ( ) . withTypeAhead ( ) ;
200
212
this . _tabSubscription = this . _keyManager . tabOut . subscribe ( ( ) => this . close . emit ( 'keydown' ) ) ;
201
213
}
202
214
@@ -207,16 +219,10 @@ export class MatMenu implements OnInit, AfterContentInit, MatMenuPanel, OnDestro
207
219
208
220
/** Stream that emits whenever the hovered menu item changes. */
209
221
_hovered ( ) : Observable < MatMenuItem > {
210
- if ( this . items ) {
211
- return this . items . changes . pipe (
212
- startWith ( this . items ) ,
213
- switchMap ( items => merge ( ...items . map ( item => item . _hovered ) ) )
214
- ) ;
215
- }
216
-
217
- return this . _ngZone . onStable
218
- . asObservable ( )
219
- . pipe ( take ( 1 ) , switchMap ( ( ) => this . _hovered ( ) ) ) ;
222
+ return this . _itemChanges . pipe (
223
+ startWith ( this . _items ) ,
224
+ switchMap ( items => merge ( ...items . map ( item => item . _hovered ) ) )
225
+ ) ;
220
226
}
221
227
222
228
/** Handle a keyboard event from the menu, delegating to the appropriate action. */
@@ -294,6 +300,30 @@ export class MatMenu implements OnInit, AfterContentInit, MatMenuPanel, OnDestro
294
300
}
295
301
}
296
302
303
+ /**
304
+ * Registers a menu item with the menu.
305
+ * @docs -private
306
+ */
307
+ addItem ( item : MatMenuItem ) {
308
+ if ( this . _items . indexOf ( item ) === - 1 ) {
309
+ this . _items . push ( item ) ;
310
+ this . _itemChanges . next ( this . _items ) ;
311
+ }
312
+ }
313
+
314
+ /**
315
+ * Removes an item from the menu.
316
+ * @docs -private
317
+ */
318
+ removeItem ( item : MatMenuItem ) {
319
+ const index = this . _items . indexOf ( item ) ;
320
+
321
+ if ( this . _items . indexOf ( item ) > - 1 ) {
322
+ this . _items . splice ( index , 1 ) ;
323
+ this . _itemChanges . next ( this . _items ) ;
324
+ }
325
+ }
326
+
297
327
/** Starts the enter animation. */
298
328
_startAnimation ( ) {
299
329
// @deletion -target 6.0.0 Combine with _resetAnimation.
@@ -307,7 +337,8 @@ export class MatMenu implements OnInit, AfterContentInit, MatMenuPanel, OnDestro
307
337
}
308
338
309
339
/** Callback that is invoked when the panel animation completes. */
310
- _onAnimationDone ( _event : AnimationEvent ) {
311
- // @deletion -target 6.0.0 Not being used anymore. To be removed.
340
+ _onAnimationDone ( event : AnimationEvent ) {
341
+ this . _animationDone . next ( event ) ;
342
+ this . _isAnimating = false ;
312
343
}
313
344
}
0 commit comments