@@ -104,11 +104,11 @@ export class MatMenu implements AfterContentInit, MatMenuPanel<MatMenuItem>, OnI
104
104
private _yPosition : MenuPositionY = this . _defaultOptions . yPosition ;
105
105
private _previousElevation : string ;
106
106
107
- /** Menu items inside the current menu. */
108
- private _items : MatMenuItem [ ] = [ ] ;
107
+ /** All items inside the menu. Includes items nested inside another menu. */
108
+ @ ContentChildren ( MatMenuItem , { descendants : true } ) _allItems : QueryList < MatMenuItem > ;
109
109
110
- /** Emits whenever the amount of menu items changes . */
111
- private _itemChanges = new Subject < MatMenuItem [ ] > ( ) ;
110
+ /** Only the direct descendant menu items. */
111
+ private _directDescendantItems = new QueryList < MatMenuItem > ( ) ;
112
112
113
113
/** Subscription to tab events on the menu panel */
114
114
private _tabSubscription = Subscription . EMPTY ;
@@ -238,19 +238,21 @@ export class MatMenu implements AfterContentInit, MatMenuPanel<MatMenuItem>, OnI
238
238
}
239
239
240
240
ngAfterContentInit ( ) {
241
- this . _keyManager = new FocusKeyManager < MatMenuItem > ( this . _items ) . withWrap ( ) . withTypeAhead ( ) ;
241
+ this . _updateDirectDescendants ( ) ;
242
+ this . _keyManager = new FocusKeyManager ( this . _directDescendantItems ) . withWrap ( ) . withTypeAhead ( ) ;
242
243
this . _tabSubscription = this . _keyManager . tabOut . subscribe ( ( ) => this . closed . emit ( 'tab' ) ) ;
243
244
}
244
245
245
246
ngOnDestroy ( ) {
247
+ this . _directDescendantItems . destroy ( ) ;
246
248
this . _tabSubscription . unsubscribe ( ) ;
247
249
this . closed . complete ( ) ;
248
250
}
249
251
250
252
/** Stream that emits whenever the hovered menu item changes. */
251
253
_hovered ( ) : Observable < MatMenuItem > {
252
- return this . _itemChanges . pipe (
253
- startWith ( this . _items ) ,
254
+ return this . _directDescendantItems . changes . pipe (
255
+ startWith ( this . _directDescendantItems ) ,
254
256
switchMap ( items => merge ( ...items . map ( item => item . _hovered ) ) )
255
257
) ;
256
258
}
@@ -324,35 +326,6 @@ export class MatMenu implements AfterContentInit, MatMenuPanel<MatMenuItem>, OnI
324
326
}
325
327
}
326
328
327
- /**
328
- * Registers a menu item with the menu.
329
- * @docs -private
330
- */
331
- addItem ( item : MatMenuItem ) {
332
- // We register the items through this method, rather than picking them up through
333
- // `ContentChildren`, because we need the items to be picked up by their closest
334
- // `mat-menu` ancestor. If we used `@ContentChildren(MatMenuItem, {descendants: true})`,
335
- // all descendant items will bleed into the top-level menu in the case where the consumer
336
- // has `mat-menu` instances nested inside each other.
337
- if ( this . _items . indexOf ( item ) === - 1 ) {
338
- this . _items . push ( item ) ;
339
- this . _itemChanges . next ( this . _items ) ;
340
- }
341
- }
342
-
343
- /**
344
- * Removes an item from the menu.
345
- * @docs -private
346
- */
347
- removeItem ( item : MatMenuItem ) {
348
- const index = this . _items . indexOf ( item ) ;
349
-
350
- if ( this . _items . indexOf ( item ) > - 1 ) {
351
- this . _items . splice ( index , 1 ) ;
352
- this . _itemChanges . next ( this . _items ) ;
353
- }
354
- }
355
-
356
329
/**
357
330
* Adds classes to the menu panel based on its position. Can be used by
358
331
* consumers to add specific styling based on the position.
@@ -395,4 +368,19 @@ export class MatMenu implements AfterContentInit, MatMenuPanel<MatMenuItem>, OnI
395
368
event . element . scrollTop = 0 ;
396
369
}
397
370
}
371
+
372
+ /**
373
+ * Sets up a stream that will keep track of any newly-added menu items and will update the list
374
+ * of direct descendants. We collect the descendants this way, because `_allItems` can include
375
+ * items that are part of child menus, and using a custom way of registering items is unreliable
376
+ * when it comes to maintaining the item order.
377
+ */
378
+ private _updateDirectDescendants ( ) {
379
+ this . _allItems . changes
380
+ . pipe ( startWith ( this . _allItems ) )
381
+ . subscribe ( ( items : QueryList < MatMenuItem > ) => {
382
+ this . _directDescendantItems . reset ( items . filter ( item => item . _parentMenu === this ) ) ;
383
+ this . _directDescendantItems . notifyOnChanges ( ) ;
384
+ } ) ;
385
+ }
398
386
}
0 commit comments