Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

According to a discussion at Github one cannot position a standard dialog (api), but panel dialogs (api) can be positioned.

A simplified demo shows that this is true:

var position = this._mdPanel.newPanelPosition().bottom(0).right(0);

The Angular Material docs show a method that allows positioning relative to the clicked element (or whatever is passed in). I'm unable to get this to work, however.

var target = el.target;
var position = this._mdPanel.newPanelPosition().relativeTo(target); 

Passing in hard values for .top() and .right(), for example, allows positioning relative to the viewport. I can't get positioning relative to the clicked element, though. How is this supposed to work?

like image 318
isherwood Avatar asked Aug 15 '16 18:08

isherwood


2 Answers

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

like image 118
I think I can code Avatar answered Oct 08 '22 18:10

I think I can code


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

like image 45
troig Avatar answered Oct 08 '22 18:10

troig