Extend ng-boostrap popover component with custom angular directive

核能气质少年 提交于 2020-05-09 07:52:40

问题


What i try to achieve is to extend ngbPopover directive and wrap in custom directive all this proeprties so instead of showing them just to include my directive.

For example i am using ngbpopover like this:

<button
    type="button"
    class="btn btn-primary mb-4"
    placement="right-top"
    [ngbPopover]="popOver"
    popoverClass="popover-custom"
    #popOverRef="ngbPopover"
    triggers="manual"
    [autoClose]="false"
    (click)="popOverRef.toggle()"
    (hidden)="onPopoverClose(options)"
>
    Standard Picker
</button>
<ng-template #popOver>
    <popover [data]="options" [popover]="popOverRef"><popover>
</ng-template>

My goal at the end is to have something like:

<button type="button" class="btn btn-primary mb-4" customDirective></button>

so all this props to be handled inside customDirective. Tried to extend ngbPopoverDirective as code below but i struggle to show popover with this approach. Is this doable or some other idea?

Custom directive:

import {
    Directive,
    ElementRef,
    Renderer2,
    Injector,
    ComponentFactoryResolver,
    ViewContainerRef,
    NgZone,
    Inject,
    ChangeDetectorRef,
    ApplicationRef,
    Input,
    OnInit,
} from '@angular/core';
import { NgbPopover, NgbPopoverConfig } from '@ng-bootstrap/ng-bootstrap';
import { DOCUMENT } from '@angular/common';

@Directive({
    selector: '[popover]'
})
export class PopoverDirective extends NgbPopover implements OnInit {
    @Input()
    popover: string;
    config: NgbPopoverConfig = {
        autoClose: false,
        placement: 'right-top',
        triggers: "manual",
        container: 'body',
        disablePopover: false,
        popoverClass: 'popover-custom',
        openDelay: 0,
        closeDelay: 0
    }

    constructor(
        _elementRef: ElementRef<HTMLElement>,
        _renderer: Renderer2,
        injector: Injector,
        componentFactoryResolver: ComponentFactoryResolver,
        viewContainerRef: ViewContainerRef,
        config: NgbPopoverConfig,
        _ngZone: NgZone,
        @Inject(DOCUMENT) _document: any,
        _changeDetector: ChangeDetectorRef,
        applicationRef: ApplicationRef
    ) {
        super(
            _elementRef,
            _renderer,
            injector,
            componentFactoryResolver,
            viewContainerRef,
            config,
            _ngZone,
            _document,
            _changeDetector,
            applicationRef
        );
        console.log("here");
    }

    ngOnInit() {
        console.log("onInit")
    }
}

回答1:


Instead of creating a directive, you could also create a component with the selector my-popover.

This component will hold your HTML template code:

<button
    type="button"
    class="btn btn-primary mb-4"
    placement="right-top"
    [ngbPopover]="popOver"
    popoverClass="popover-custom"
    #popOverRef="ngbPopover"
    triggers="manual"
    [autoClose]="false"
    (click)="popOverRef.toggle()"
    (hidden)="onPopoverClose(options)"
>
    Standard Picker
</button>
<ng-template #popOver>
    <popover [data]="options" [popover]="popOverRef"><popover>
</ng-template>

And then finally to use that, you could do the following:

<my-popover></my-popover>

If you need to interact with that component, e.g. to listen to the click events have a look at input and output bidings of components.

Hope this helps!

For more information on the difference between components and directives, you could check this question.




回答2:


Ok finally got this to work not sure why my previous code was not working. Anyway i succeed with extending ngbPopover directive. In my case i wanted popoup to be open on parent click for example button, this can be change to hover (mouseenter).... etc..

import {
    ElementRef,
    Directive,
    Input,
    TemplateRef,
    EventEmitter,
    Renderer2,
    Injector,
    ComponentFactoryResolver,
    ViewContainerRef,
    NgZone,
    OnInit,
    OnDestroy,
    Inject,
    ChangeDetectorRef,
    ApplicationRef,
} from '@angular/core';
import { NgbPopover, NgbPopoverConfig } from '@ng-bootstrap/ng-bootstrap';
import { DOCUMENT } from '@angular/common';

@Directive({
    selector: '[customPopover]',
    exportAs: 'customPopover',
})
export class PopoverDirective extends NgbPopover implements OnInit {
    @Input() customPopover: TemplateRef<any>;

    constructor(
        private _elRef: ElementRef,
        private _render: Renderer2,
        injector: Injector,
        componentFactoryResolver: ComponentFactoryResolver,
        private viewContainerRef: ViewContainerRef,
        config: NgbPopoverConfig,
        ngZone: NgZone,
        private changeRef: ChangeDetectorRef,
        @Inject(DOCUMENT) _document: any,
        applicationRef: ApplicationRef
    ) {
        super(
            _elRef,
            _render,
            injector,
            componentFactoryResolver,
            viewContainerRef,
            config,
            ngZone,
            _document,
            changeRef,
            applicationRef
        );
        this.triggers = 'manual';
        this.popoverTitle = '';
        this.container = 'body';
        this.popoverClass = 'popover-custom';
        this.autoClose = false;
    }

    ngOnInit(): void {
        super.ngOnInit();
        this.ngbPopover = this.customPopover;

        // we need to listen on parent element click envet for example button
        // and toggle popover
        this._render.listen(this._elRef.nativeElement.parentNode, 'click', () => {
            this.toggle();
        });
    }

    ngOnDestroy(): void {
        super.ngOnDestroy();
    }
}

component that use this directive:

<ng-template #popTemplate>
    <custom-content-comp [data]="test" [popover]="popOverRef"></custom-content-comp>
</ng-template>
<span [customPopover]="popTemplate" #popOverRef="customPopover" placement="right-top" triggers="manual">
    <ng-content></ng-content>
</span>

For popTemplate i am using again custom component this can be whatever we want either string either custom template.

Usage:

<div class="col-3">
                <br />
                <button
                    type="button"
                    class="btn btn-primary mb-4"
                    customPopoverComp
                    >
                    Standard Picker
                    </button>
            </div>


来源:https://stackoverflow.com/questions/61010439/extend-ng-boostrap-popover-component-with-custom-angular-directive

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!