I'm using Angular 6
.
I have declared a directive StickyPopover by extending NbgPopover and have added in declaration
of app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { AuthLayoutComponent } from './layouts/auth-layout/auth-layout.component';
import {AdminLayoutComponent} from './layouts/admin-layout/admin-layout.component';
import {FormsModule} from '@angular/forms';
import {RouterModule} from '@angular/router';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
import {StickyPopoverDirective} from './sticky-popover.directive';
@NgModule({
declarations: [
AppComponent,
AuthLayoutComponent,
AdminLayoutComponent,
StickyPopoverDirective // custom created directive
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
FormsModule,
HttpClientModule,
RouterModule,
NgbModule.forRoot(),
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule { }
and the location of the directive is at the same level as that of app.module.ts file.
Contents of sticky-popover.directive.ts is
import {
ElementRef,
Directive, Input, TemplateRef,
EventEmitter,
Renderer2,
Injector,
ComponentFactoryResolver,
ViewContainerRef,
NgZone, OnInit, OnDestroy
} from '@angular/core';
import { NgbPopover, NgbPopoverConfig } from '@ng-bootstrap/ng-bootstrap';
@Directive({
selector: '[appStickyPopover]',
exportAs: 'stickyPopover'
})
export class StickyPopoverDirective extends NgbPopover implements OnInit, OnDestroy {
@Input() stickyPopover: TemplateRef<any>;
popoverTitle: string;
placement: 'auto' | 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' |
'bottom-right' | 'left-top' | 'left-bottom' | 'right-top' | 'right-bottom' | ('auto' | 'top' | 'bottom' |
'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'left-top' | 'left-bottom' |
'right-top' | 'right-bottom')[];
triggers: string;
container: string;
shown: EventEmitter<{}>;
hidden: EventEmitter<{}>;
ngpPopover: TemplateRef<any>;
canClosePopover: boolean;
toggle(): void {
super.toggle();
}
isOpen(): boolean {
return super.isOpen();
}
constructor(
private _elRef: ElementRef,
private _render: Renderer2,
injector: Injector,
componentFactoryResolver: ComponentFactoryResolver,
private viewContainerRef: ViewContainerRef,
config: NgbPopoverConfig,
ngZone: NgZone
) {
super(_elRef, _render, injector, componentFactoryResolver, viewContainerRef, config, ngZone, document);
this.triggers = 'manual';
this.popoverTitle = 'Permissions';
this.container = 'body';
}
ngOnInit(): void {
super.ngOnInit();
this.ngbPopover = this.stickyPopover;
this._render.listen(this._elRef.nativeElement, 'mouseenter', () => {
this.canClosePopover = true;
this.open();
});
this._render.listen(this._elRef.nativeElement, 'mouseleave', (event: Event) => {
setTimeout(() => { if (this.canClosePopover) { this.close(); } }, 100);
});
this._render.listen(this._elRef.nativeElement, 'click', () => {
this.close();
});
}
ngOnDestroy(): void {
super.ngOnDestroy();
}
open() {
super.open();
const popover = window.document.querySelector('.popover');
this._render.listen(popover, 'mouseover', () => {
this.canClosePopover = false;
});
this._render.listen(popover, 'mouseout', () => {
this.canClosePopover = true;
setTimeout(() => { if (this.canClosePopover) { this.close(); } }, 0);
});
}
close() {
super.close();
}
}
I have a module SavedSearches which is imported inside of AdminModule
which is further declared inside app.module.ts
When I use StickyPopover directive inside the template of SavedSearches module like
<i class="fa fa-plus-circle" aria-hidden="true" appStickyPopover [popoverTitle]="additional" [autoClose]="true" data-placement="right"></i>
It gives error as
can't bind to 'popoverTitle' since it isn't a known property of i
When I move the directive inside the SavedSearches module and include it in the saved-searches.module.ts declaration
, it works fine without any error.
But Then I can't use it in another module and using it in other modules gives
StickyPopovoerDirective is a part of the declaration of 2 modules. Move it in the upper module which imports these two modules.
Put a debugger; statement inside the constructor of your directive. Then you'll know for sure when it's working and you can remove it. Make sure you have selector: '[magicFeature]' and not selector: 'magicFeature' Sometimes you need to restart your ng serve to make sure everything is refreshed.
Steps to be followed to create custom attribute directive Create a class decorated with @Directive. Assign the attribute directive name to the selector metadata of @Directive decorator. Use ElementRef class to access DOM to change host element appearance and behavior.
If you use dynamic views and dynamic components instantiation as described in the Here is what you need to know about dynamic components in Angular you can use components from the A module without adding them into exports array. Of course you will still need to import the A module.
That directive is visible only for AppModule
, if you want to use it into another modules, you can create a SharedModule
. Then add StickyPopoverDirective
into the declarations and exports.
@NgModule({
declarations: [StickyPopoverDirective],
exports: [StickyPopoverDirective]
})
export class SharedModule { }
After this you can import SharedModule
into another modules and use your directive there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With