I want to create a popover component which will have api like below:

<button popover [content]="popover_content" >popover test</button><ng-template #popover_content><ul><li>1</li><li>2</li><li>3</li><li>4</li></ul></ng-template>

I have tried to some extent, pls see stackblitz

The problem is:

  1. Content is appearing inside the button. How do I avoid it?

enter image description here

  1. I want the content to give it some css class but when I access it I just get a comment node.
 @Input() set content(val: TemplateRef<void>) {this.popoverContent = val;console.log(val.elementRef.nativeElement);//this is a comment node. WHY??}

I am not sure how to solve above two problems. Would be great if someone could advice.

3

Best Answer


Since ng-template is being compiled to comment, you can't actually get its content. You could try to set it to a hidden div and that might work (https://stackblitz.com/edit/angular-bj2ke4).

In any case, I made a small change with the API so it'll match the following pattern (I hope that's ok with you):

<app-popover buttonText="Click Me"><ul><li>THIS</li><li>IS</li><li>MY POPOVER</li></ul></app-popover>

It's pretty straight forward, popover.component.ts:

import { Component, Input } from '@angular/core';@Component({selector: 'app-popover',templateUrl: './popover.component.html',styleUrls: ['./popover.component.css']})export class PopoverComponent {@Input() buttonText: string;isActive = false;toggle() {this.isActive = !this.isActive;}}

popover.component.html:

<button (click)="toggle()">{{ buttonText }}</button><div class="popover" [class.active]="isActive"><ng-content></ng-content></div>

Stackblitz Demo - https://stackblitz.com/edit/angular-ovecbp

If you use ionic, you can use their ion-popover component. Otherwise, you can try a pure CSS route.

To get a basic popover working, you need a background layer with position: absolute as well as a top z-index. You can use height: 100% and width: 100% for convenience. It'll cover the entire screen.

<section class="popover-background">...</section>

Then you need to create the visible container for the popover, such as a modal over the popover-background. You can position this container however you like, it'll be the visible popover element. This container will be relative to the absolute positioned popover-background.

<section class="popover-background"><article class="popover-container"><!-- popover content --></article></section>

Now, you can put whatever content you need inside the container.

<section class="popover-background"><article class="popover-container"><ng-content></ng-content></article></section>

Assuming this popover belong to a my-popover component. You can choose show the content of the popover like this:

<button (click)="showPopver()">Show Popover</button><my-popover *ngIf="show"><ul><li>1</li><li>2</li><li>3</li><li>4</li></ul></my-popover>

Additionally, you can modify this piece of code further to have dynamic popover content.

<my-popover *ngIf="show"><a *ngIf="showA"></a><b *ngIf="showB"></b></my-popover>

You can take a look at this changes that i did in the Stackblitz .

Added a mouseOver event but can also be done onClick

<div ngClass="myclass" (mouseenter)="changeStyle($event)" (mouseleave)="changeStyle($event)"><ng-content></ng-content><div *ngIf = "test"><ng-container *ngTemplateOutlet="popoverContent"></ng-container></div> </div>