25

How do I manually position a popover in Ionic 2?

I can't set the position in a css class, since the popover controller sets the position with an inline style.

Schlaus
  • 18,144
  • 10
  • 36
  • 64

7 Answers7

49

Looking through the code, there doesn't seem to be an option for the popover's position. However, when opening the popover as a result of the user tapping something, it can be positioned by the click event. We can use that knowledge for manual positioning as well:

let pop = this.popoverCtrl.create(MyPopover);

let ev = {
  target : {
    getBoundingClientRect : () => {
      return {
        top: 100
      };
    }
  }
};

pop.present({ev});

A few things to note:

  • You can set the value for top, left, or both.
  • The values must be given in pixels, as numbers.
  • If top or left is not given, then the usual positioning algorithm is used for that value.

I'd be happy to know if there's a better way, but so far this is the best I could come up with.

This certainly works in Ionic2 and 3, happy to have someone confirm if it works in Ionic4 as well!

Dennis T
  • 3
  • 3
Schlaus
  • 18,144
  • 10
  • 36
  • 64
  • Excellent. I needed to position a popover on an OpenLayers map and this solution worked well. However, I had to use a different approach eventually because I could not get rid of the overlay. BTW, How did you come by this solution? Is it documented? – daudihus Jan 12 '18 at 19:46
  • 1
    I think it should be `top: 100` - as a number instead of a string. Otherwise, I'm getting a casting error. – Orlandster Mar 31 '18 at 15:37
  • I can't seem to make sense of this. @Schlaus Are you passing the click event to the function? – Jeremy Thomas Jul 18 '18 at 13:27
  • @JeremyThomas I'm not, because then the popover would be placed where the user tapped. Instead I'm creating the "fake event" `ev` that I'm creating in the answer, and the popover will be placed according to the position returned by my own `getBoundingClientRect()`. Hope this clarifies it! – Schlaus Jul 20 '18 at 20:34
  • Ok.. err.. I am using Ionic 4 and it IS working. Whereas the suggestion from @Mnemo below doesnt work in Ionic 4, leastwise I cant get it to. The class is being used but the positioning isn't and I guess that is because it is handled algorithmically ? It does feel a bit of a hack, but I'll go with since it works.. – Brett JB May 15 '19 at 11:53
  • I had to "cast" ev to unknown then to event: `ev as unknown as Event` and pass that into create method of the popoverController to get it to work in ionic 4. – JoshStrange Jul 02 '19 at 03:25
11

Though the above code works for some people, but I found a better solution where passing the cssClass on popover.

To make use of the cssClass, you must declare it globally in app.scss as shown below:

.custom-popover .popover-content {
  width: 80%;
  top: 70px;
  left: 30px;
  bottom: 70px
}

In your .ts file, you can pass the class like below:

let popover = this.popoverCtrl.create(PopoverPage, {}, {cssClass: 'custom-popover'});

popover.present();
Mnemo
  • 652
  • 1
  • 13
  • 18
7

If you only want to change the placement of the popover relative to the pressed element, CSS transformations might help. E.g. to place it to the top-right / left-bottom of the clicked element, instead of default bottom-right corner.

Add cssClass option:

let popover = this.popoverCtrl.create(PopoverPage, {}, {cssClass: 'popover-top-right'});

popover.present({
  ev: event
});

and use the following CSS somewhere:

.popover-top-right .popover-content {
  transform: translateY(-120%) !important;
}

This solution is somewhat like Mnemo suggested, but more generic as you don't need to specify fixed coordinates. Though it's not that customizable as the accepted workaround from Schlaus.

This way you can use translateXY(-100%, -100%) to put the popover to the left-top corner, etc. The !important is perhaps needed to override ionic styles (or use more specific CSS selector instead).

Alexey Grinko
  • 2,773
  • 22
  • 21
4

if you want the popover next to te button, pass to the function create() the event, like this

//home.html

<button ion-button icon-only (click)="presentRadioPopover($event)">
        <ion-icon name="more"></ion-icon>
 </button>

//home.ts

 presentRadioPopover(event) {
    const popover = this.popoverCtrl.create(HomepopoverPage);
    popover.present({
      ev: event
    });
  }
Francesco Taioli
  • 2,687
  • 1
  • 19
  • 34
3

So I was finding something similar for my recent project where I wanted to place the ion-popover to the bottom instead of it's default position. Something similar to Android's Bottom Sheet.

After looking into several answers and doing a bit of tweaks on my own, I found a way to fix this.

Step 1: Assign a class to the Pop-Over:

this.popover = await this.popoverController.create({
      component: AddToCartComponentComponent,
      event: ev,
      translucent: true,
      animated: false,
      cssClass: 'bottom-sheet-popover'
    });

Step 2: Adding CSS

Once you assign a custom class to your pop-over element during the creation, head over to the global CSS and implement these tweaks:

.bottom-sheet-popover .popover-content {
    width: 100% !important;
    left: 0 !important;
    bottom: 0 !important;
    right: 0 !important;
    top: calc(100% - 200px) !important;
    max-height: 200px;
    min-height: 200px; 
  }

That's it. You're done.

enter image description here

Note: This works well with Ionic 4.

1

I found a simpler solution by adding the styles in the app.scss (Globle CSS )

.popover-content{
  top: 60px !important;
}
0

For me, the problem was solved by setting the position using css. First you have to set the cssClass of your element:

Component/Page code:

async showPopover (ev) { 
 component: myComponent,
 event: ev,
 cssClass: 'myPopoverStyle'
}

then, you have to set the global css (generally app.scss).

app.scss

.myPopoverStyle .popover-content{
    top: 60px !important;
}