javascript - Utöka ng-bootstrap popover-komponenten med en anpassad Angular-direktiv
Det jag försöker uppnå är att utöka ngbPopover-direktivet och omsluta alla dessa egenskaper i ett anpassat direktiv så att de inte bara visas, utan inkluderas i mitt direktiv.
Till exempel använder jag ngbpopover på detta sätt:
<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>
Mitt mål i slutet är att ha något som:
<button type="button" class="btn btn-primary mb-4" customDirective></button>
så alla dessa props ska hanteras inom customDirective. Försökte utöka ngbPopoverDirective som koden nedan men jag har svårt att visa popover med detta tillvägagångssätt. Är detta möjligt eller någon annan idé?
Anpassad direktiv:
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")
}
}
Svar #1
Okej, jag fick det äntligen att fungera, är inte säker på varför min tidigare kod inte fungerade. Hur som helst lyckades jag med att utöka ngbPopover-direktivet. I mitt fall ville jag att popupen skulle öppnas vid klick på föräldern, till exempel en knapp, detta kan ändras till hover (mouseenter)... osv.
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();
}
}
komponent som använder denna direktiv:
<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>
För popTemplate använder jag igen en anpassad komponent, detta kan vara vad vi vill, antingen en sträng eller en anpassad mall.
Användning :
<div class="col-3">
<br />
<button
type="button"
class="btn btn-primary mb-4"
customPopoverComp
>
Standard Picker
</button>
</div>
Svar #2
Istället för att skapa en direktiv, kan du också skapa en komponent med selektorn my-popover.
Den här komponenten kommer att innehålla din HTML-mallkod:
<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>
Och sedan, för att slutligen använda det, kan du göra följande:
<my-popover></my-popover>
Om du behöver interagera med den komponenten, t.ex. för att lyssna på klickhändelser, ta en titt på komponenters input- och output-bindningar.
Hoppas det här hjälper!
För mer information om skillnaden mellan komponenter och direktiv kan du kolla denna fråga.
