How can I position an Angular Material panel dialog relative to a button? How can I position an Angular Material panel dialog relative to a button? angularjs angularjs

How can I position an Angular Material panel dialog relative to a button?


I've been working with Angular Material for the past several months and still find the documentation lacking, so forgive the length of this post as my pseudo documentation on the issue. But here is what I do know:

I've only been able to get the panel location to work, relative to a target element, by chaining the addPanelPosition function onto the relativeTo function as such:

var position = this._mdPanel  .newPanelPosition()  .relativeTo(ev.target)  .addPanelPosition('align-start', 'below') // or other values

(in this case, ev is the $event object passed by ng-click)

I was able to track down the acceptable parameters for addPanelPosition and they are the following:

Panel y position only accepts the following values: center | align-tops | align-bottoms | above | below

Panel x Position only accepts the following values: center | align-start | align-end | offset-start | offset-end

Interstingly enough, in the Angular Material demo, they use the this._mdPanel.xPosition.ALIGN_START and this._mdPanel.yPosition.BELOW properties which simply resolve to strings as their x and y values for the addPanelPosition function. I've always gone straight with the string values. However, using string values could be problematic if the development of this feature is still in flux and they change the acceptable string values.

I'll point out one more issue I've seen.

Another trick they use in the demo is to specify a class name in the relativeTo function instead of a target element, then place that class on the target element itself. The reason this approach can be helpful is because the $event object from ng-click can provide different target elements based on what exactly was clicked. For example, clicking the button <div> is going to give a different target than clicking the <span> text inside the button. This wil cause your panel to shift locations unless you provide the additional functionality not to do so.

Codepen

I took their demo and really cut it down to size to focus on this issue. You can see the updated codepen here


As I post in a comment, here you can see it working on a plunker.

My solution is very close the to @I think I can code answer. However, in my answer, instead of a menu, a <md-dialog> is displayed when the button is clicked, as it's requested in the OP.

Besides the working plunker with a dialog, there is no much to add to the good @I think I can code answer. As it's shown in the angular-material md-panel demo, the key here is to set the position of the panel relative to the button. To do that (like in the angular-material demo), we can use a specific css class (demo-dialog-open-button in my example) to find the target element. this is a tricky thing in my opinion...but it works well for this use case (it's also well explained in the other answer).

Code for reference, see the plunker for the complete details:

html (note the css class added to the button):

<md-button class="md-primary md-raised demo-dialog-open-button" ng-click="ctrl.showDialog($event)">   Dialog </md-button>

JS controller.

var position = this._mdPanel.newPanelPosition()      .relativeTo('.demo-dialog-open-button')      .addPanelPosition(this._mdPanel.xPosition.ALIGN_START, this._mdPanel.yPosition.BELOW);

Hope it helps


Dialogs are very simple widgets. Trapping focus is about the most complicated thing they do. It pains me that your issue has evolved into such a complex one.

Just to state the obvious, you do have complete control over positioning any individual dialog thanks to your configured class name.

.demo-dialog-example {    top: 20px;    left: 20px;}

Also, in your showDialog method, why not set up a call-back via a promise for the open method? Something like:

this._mdPanel.open(config).then(function() {    var dialog = angular.element(document.querySelector('.demo-dialog-example'));    //Centering, positioning relative to target, or draggable logic goes here});

I respect that you are trying to improve the logic of the plugin and do things the "Angular way", but these relatively simple requirements should not be causing you this much heartache.