Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

can't use directive declared inside app module in child modules in Angular 6

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.

like image 668
Anuj TBE Avatar asked Oct 04 '18 06:10

Anuj TBE


People also ask

Why directive is not working in Angular?

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.

How do you declare directives in Angular 6?

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.

Can we have module inside module in Angular?

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.


1 Answers

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.

like image 151
Suren Srapyan Avatar answered Sep 30 '22 17:09

Suren Srapyan