如何以编程方式将 ngBootstrap 弹出窗口添加到元素?
how to programmatically add ngBootstrap popover to element?
我目前正在我的 angular v8 应用程序中处理日历。
这是我使用的插件:https://fullcalendar.io
这是我在 html 模板中包含的组件:
<full-calendar
defaultView="dayGridMonth"
[editable]="true"
[eventLimit]="5"
[nowIndicator]="true"
[slotLabelFormat]="timeFormat"
[eventTimeFormat]="timeFormat"
[eventClassName]="'fc-event-brand'"
[minTime]="'08:00:00'"
[maxTime]="'24:00:00'"
[header]="{
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth, timeGridWeek, timeGridDay, listWeek'
}"
[plugins]="calendarPlugins"
[events]="calendarEvents"
(eventMouseEnter)="showPopover($event)"
(eventMouseLeave)="hidePopover($event)"
(eventRender)="renderTooltip($event)"></full-calendar>
但是如何向元素添加 ngBootstrap 弹出窗口或工具提示?
这是 renderTooltip():
renderTooltip(event) {
// bind ngBootstrap tooltip or popover to $event.el
}
我会创建一个简单的组件,它基本上只是一个弹出窗口包装器:
@Component({
template: `
<div class="fc-content" [ngbPopover]="template" container="body" triggers="manual">
<ng-content></ng-content>
</div>
`,
})
export class PopoverWrapperComponent {
template: TemplateRef<any>;
@ViewChild(NgbPopover, { static: true }) popover: NgbPopover;
}
template
属性 将从我们的主要组件传递,因此我们可以创建我们想要的任何模板
- 我们还持有
NgbPopover
个实例,因此我们可以稍后使用 popover.open(context)
。
还要确保您已将此组件添加到 NgModule
:
的 entryComponents
数组中
@NgModule({
imports: [ BrowserModule, FullCalendarModule, NgbPopoverModule ],
declarations: [ AppComponent, PopoverWrapperComponent ],
entryComponents: [PopoverWrapperComponent],
\/
like this
bootstrap: [ AppComponent ]
})
export class AppModule { }
现在我们要将此组件动态渲染到 $event.el
元素中,并在 ng-content
中投影子节点。
import { Component, ComponentRef,
TemplateRef, ViewChild, ComponentFactoryResolver,
Injector, ApplicationRef } from '@angular/core';
import dayGridPlugin from '@fullcalendar/daygrid';
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
calendarPlugins = [dayGridPlugin];
calendarEvents = [
{ title: 'event 1', date: '2019-08-09', customProp1: 'customProp1', customProp2: 'customProp2' },
{ title: 'event 2', date: '2019-08-12', customProp1: 'customProp3', customProp2: 'customProp4' }
];
@ViewChild('popoverTmpl', { static: true }) popoverTmpl: TemplateRef<any>;
popoversMap = new Map<any, ComponentRef<PopoverWrapperComponent>>();
popoverFactory = this.resolver.resolveComponentFactory(PopoverWrapperComponent);
constructor(
private resolver: ComponentFactoryResolver,
private injector: Injector,
private appRef: ApplicationRef) {
}
renderTooltip(event) {
const projectableNodes = Array.from(event.el.childNodes)
const compRef = this.popoverFactory.create(this.injector, [projectableNodes], event.el);
compRef.instance.template = this.popoverTmpl;
this.appRef.attachView(compRef.hostView);
this.popoversMap.set(event.el, compRef);
}
destroyTooltip(event) {
const popover = this.popoversMap.get(event.el);
if (popover) {
this.appRef.detachView(popover.hostView);
popover.destroy();
this.popoversMap.delete(event.el);
}
}
showPopover(event) {
const popover = this.popoversMap.get(event.el);
if (popover) {
popover.instance.popover.open({ event: event.event });
}
}
hidePopover(event) {
const popover = this.popoversMap.get(event.el);
if (popover) {
popover.instance.popover.close();
}
}
}
这里的关键部分是我们如何渲染组件 dynamically with projectable nodes:
renderTooltip(event) {
const projectableNodes = Array.from(event.el.childNodes)
const compRef = this.popoverFactory.create(this.injector, [projectableNodes], event.el);
compRef.instance.template = this.popoverTmpl;
this.appRef.attachView(compRef.hostView)
this.popoversMap.set(event.el, compRef)
}
动态呈现的组件与 Angular 变化检测树无关,因此我们必须将其视图添加到 ApplicationRef
视图,以便变化检测应该在那里工作。
确保您已在模板中订阅以下活动:
(eventRender)="renderTooltip($event)"
(eventDestroy)="destroyTooltip($event)"
(eventMouseEnter)="showPopover($event)"
(eventMouseLeave)="hidePopover($event)"
您还应该为弹出窗口定义模板,即:
<ng-template #popoverTmpl let-event="event">
<h6>{{ event.title }}</h6>
<div>
<p>{{ event.extendedProps.customProp1 }}</p>
<p>{{ event.extendedProps.customProp2 }}</p>
</div>
</ng-template>
我目前正在我的 angular v8 应用程序中处理日历。
这是我使用的插件:https://fullcalendar.io
这是我在 html 模板中包含的组件:
<full-calendar
defaultView="dayGridMonth"
[editable]="true"
[eventLimit]="5"
[nowIndicator]="true"
[slotLabelFormat]="timeFormat"
[eventTimeFormat]="timeFormat"
[eventClassName]="'fc-event-brand'"
[minTime]="'08:00:00'"
[maxTime]="'24:00:00'"
[header]="{
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth, timeGridWeek, timeGridDay, listWeek'
}"
[plugins]="calendarPlugins"
[events]="calendarEvents"
(eventMouseEnter)="showPopover($event)"
(eventMouseLeave)="hidePopover($event)"
(eventRender)="renderTooltip($event)"></full-calendar>
但是如何向元素添加 ngBootstrap 弹出窗口或工具提示?
这是 renderTooltip():
renderTooltip(event) {
// bind ngBootstrap tooltip or popover to $event.el
}
我会创建一个简单的组件,它基本上只是一个弹出窗口包装器:
@Component({
template: `
<div class="fc-content" [ngbPopover]="template" container="body" triggers="manual">
<ng-content></ng-content>
</div>
`,
})
export class PopoverWrapperComponent {
template: TemplateRef<any>;
@ViewChild(NgbPopover, { static: true }) popover: NgbPopover;
}
template
属性 将从我们的主要组件传递,因此我们可以创建我们想要的任何模板- 我们还持有
NgbPopover
个实例,因此我们可以稍后使用popover.open(context)
。
还要确保您已将此组件添加到 NgModule
:
entryComponents
数组中
@NgModule({
imports: [ BrowserModule, FullCalendarModule, NgbPopoverModule ],
declarations: [ AppComponent, PopoverWrapperComponent ],
entryComponents: [PopoverWrapperComponent],
\/
like this
bootstrap: [ AppComponent ]
})
export class AppModule { }
现在我们要将此组件动态渲染到 $event.el
元素中,并在 ng-content
中投影子节点。
import { Component, ComponentRef,
TemplateRef, ViewChild, ComponentFactoryResolver,
Injector, ApplicationRef } from '@angular/core';
import dayGridPlugin from '@fullcalendar/daygrid';
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
calendarPlugins = [dayGridPlugin];
calendarEvents = [
{ title: 'event 1', date: '2019-08-09', customProp1: 'customProp1', customProp2: 'customProp2' },
{ title: 'event 2', date: '2019-08-12', customProp1: 'customProp3', customProp2: 'customProp4' }
];
@ViewChild('popoverTmpl', { static: true }) popoverTmpl: TemplateRef<any>;
popoversMap = new Map<any, ComponentRef<PopoverWrapperComponent>>();
popoverFactory = this.resolver.resolveComponentFactory(PopoverWrapperComponent);
constructor(
private resolver: ComponentFactoryResolver,
private injector: Injector,
private appRef: ApplicationRef) {
}
renderTooltip(event) {
const projectableNodes = Array.from(event.el.childNodes)
const compRef = this.popoverFactory.create(this.injector, [projectableNodes], event.el);
compRef.instance.template = this.popoverTmpl;
this.appRef.attachView(compRef.hostView);
this.popoversMap.set(event.el, compRef);
}
destroyTooltip(event) {
const popover = this.popoversMap.get(event.el);
if (popover) {
this.appRef.detachView(popover.hostView);
popover.destroy();
this.popoversMap.delete(event.el);
}
}
showPopover(event) {
const popover = this.popoversMap.get(event.el);
if (popover) {
popover.instance.popover.open({ event: event.event });
}
}
hidePopover(event) {
const popover = this.popoversMap.get(event.el);
if (popover) {
popover.instance.popover.close();
}
}
}
这里的关键部分是我们如何渲染组件 dynamically with projectable nodes:
renderTooltip(event) {
const projectableNodes = Array.from(event.el.childNodes)
const compRef = this.popoverFactory.create(this.injector, [projectableNodes], event.el);
compRef.instance.template = this.popoverTmpl;
this.appRef.attachView(compRef.hostView)
this.popoversMap.set(event.el, compRef)
}
动态呈现的组件与 Angular 变化检测树无关,因此我们必须将其视图添加到 ApplicationRef
视图,以便变化检测应该在那里工作。
确保您已在模板中订阅以下活动:
(eventRender)="renderTooltip($event)"
(eventDestroy)="destroyTooltip($event)"
(eventMouseEnter)="showPopover($event)"
(eventMouseLeave)="hidePopover($event)"
您还应该为弹出窗口定义模板,即:
<ng-template #popoverTmpl let-event="event">
<h6>{{ event.title }}</h6>
<div>
<p>{{ event.extendedProps.customProp1 }}</p>
<p>{{ event.extendedProps.customProp2 }}</p>
</div>
</ng-template>