@@ -22,9 +22,10 @@ import {
2222 TemplatePortal ,
2323 ConnectedPositionStrategy ,
2424 HorizontalConnectionPos ,
25- VerticalConnectionPos
25+ VerticalConnectionPos ,
2626} from '../core' ;
2727import { Subscription } from 'rxjs/Subscription' ;
28+ import { MenuPositionX , MenuPositionY } from './menu-positions' ;
2829
2930/**
3031 * This directive is intended to be used in conjunction with an md-menu tag. It is
@@ -44,6 +45,7 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
4445 private _overlayRef : OverlayRef ;
4546 private _menuOpen : boolean = false ;
4647 private _backdropSubscription : Subscription ;
48+ private _positionSubscription : Subscription ;
4749
4850 // tracking input type is necessary so it's possible to only auto-focus
4951 // the first item of the list when the menu is opened via the keyboard
@@ -92,9 +94,7 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
9294 this . _overlayRef . dispose ( ) ;
9395 this . _overlayRef = null ;
9496
95- if ( this . _backdropSubscription ) {
96- this . _backdropSubscription . unsubscribe ( ) ;
97- }
97+ this . _cleanUpSubscriptions ( ) ;
9898 }
9999 }
100100
@@ -172,7 +172,9 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
172172 private _createOverlay ( ) : void {
173173 if ( ! this . _overlayRef ) {
174174 this . _portal = new TemplatePortal ( this . menu . templateRef , this . _viewContainerRef ) ;
175- this . _overlayRef = this . _overlay . create ( this . _getOverlayConfig ( ) ) ;
175+ const config = this . _getOverlayConfig ( ) ;
176+ this . _subscribeToPositions ( config . positionStrategy as ConnectedPositionStrategy ) ;
177+ this . _overlayRef = this . _overlay . create ( config ) ;
176178 }
177179 }
178180
@@ -190,20 +192,52 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
190192 return overlayState ;
191193 }
192194
195+ /**
196+ * Listens to changes in the position of the overlay and sets the correct classes
197+ * on the menu based on the new position. This ensures the animation origin is always
198+ * correct, even if a fallback position is used for the overlay.
199+ */
200+ private _subscribeToPositions ( position : ConnectedPositionStrategy ) : void {
201+ this . _positionSubscription = position . onPositionChange . subscribe ( ( change ) => {
202+ const posX : MenuPositionX = change . connectionPair . originX === 'start' ? 'after' : 'before' ;
203+ const posY : MenuPositionY = change . connectionPair . originY === 'top' ? 'below' : 'above' ;
204+ this . menu . setPositionClasses ( posX , posY ) ;
205+ } ) ;
206+ }
207+
193208 /**
194209 * This method builds the position strategy for the overlay, so the menu is properly connected
195210 * to the trigger.
196211 * @returns ConnectedPositionStrategy
197212 */
198213 private _getPosition ( ) : ConnectedPositionStrategy {
199- const positionX : HorizontalConnectionPos = this . menu . positionX === 'before' ? 'end' : 'start' ;
200- const positionY : VerticalConnectionPos = this . menu . positionY === 'above' ? 'bottom' : 'top' ;
201-
202- return this . _overlay . position ( ) . connectedTo (
203- this . _element ,
204- { originX : positionX , originY : positionY } ,
205- { overlayX : positionX , overlayY : positionY }
206- ) ;
214+ const [ posX , fallbackX ] : HorizontalConnectionPos [ ] =
215+ this . menu . positionX === 'before' ? [ 'end' , 'start' ] : [ 'start' , 'end' ] ;
216+
217+ const [ posY , fallbackY ] : VerticalConnectionPos [ ] =
218+ this . menu . positionY === 'above' ? [ 'bottom' , 'top' ] : [ 'top' , 'bottom' ] ;
219+
220+ return this . _overlay . position ( )
221+ . connectedTo ( this . _element ,
222+ { originX : posX , originY : posY } , { overlayX : posX , overlayY : posY } )
223+ . withFallbackPosition (
224+ { originX : fallbackX , originY : posY } ,
225+ { overlayX : fallbackX , overlayY : posY } )
226+ . withFallbackPosition (
227+ { originX : posX , originY : fallbackY } ,
228+ { overlayX : posX , overlayY : fallbackY } )
229+ . withFallbackPosition (
230+ { originX : fallbackX , originY : fallbackY } ,
231+ { overlayX : fallbackX , overlayY : fallbackY } ) ;
232+ }
233+
234+ private _cleanUpSubscriptions ( ) : void {
235+ if ( this . _backdropSubscription ) {
236+ this . _backdropSubscription . unsubscribe ( ) ;
237+ }
238+ if ( this . _positionSubscription ) {
239+ this . _positionSubscription . unsubscribe ( ) ;
240+ }
207241 }
208242
209243 _handleMousedown ( event : MouseEvent ) : void {
0 commit comments