Search code examples
angularangular-directiveng-bootstrap

How to extend NgbDropdown or write a wrapper for it?


Basically for all the dropdowns I want to run myOpenFunction() every time a NgbDropDown opens and run myCloseFunction() every time a dropdown closes?

I was thinking that I could write a custom directive that extends NgbDropDown and run a function before and after dropdown. something like this:

<div myCustomDropdown> <!-- using my own directive instead of ngbDropdown -->
  <button  ngbDropdownToggle>Toggle dropdown</button>
  <div ngbDropdownMenu>
    <button ngbDropdownItem>Action - 1</button>
    <button ngbDropdownItem>Another Action</button>
  </div>
</div>

What I have tried so far based on this here

@Directive({
  selector: '[myCustomDropdown]'
})
export class DropdownDirective extends NgbDropdown implements OnDestroy {


  constructor(_changeDetector: ChangeDetectorRef, config: NgbDropdownConfig, @Inject(DOCUMENT)  _document: any,
              _ngZone: NgZone, _elementRef: ElementRef<HTMLElement>, _renderer: Renderer2,
              @Optional() ngbNavbar: NgbNavbar) {
    super(_changeDetector, config, _document, _ngZone, _elementRef, _renderer, ngbNavbar);
  }


  ngOnDestroy() {
    super.ngOnDestroy();
  }

}

which throws the error

    core.js:6185 ERROR Error: Uncaught (in promise): NullInjectorError: R3InjectorError(TestModule)[NgbDropdown -> NgbDropdown -> NgbDropdown -> NgbDropdown]: 
  NullInjectorError: No provider for NgbDropdown!

Solution

  • Another aproach is create a directive and use HostBinding

    @Directive({
      selector: '[extend-dropdown]'
    })
    export class ExtendDropdown {
      @Input('extend-dropdown')func:(boolean)=>any;
      @HostListener('openChange',['$event']) openChange(event)
      {
        console.log('inner function',event)
        this.func && this.func(event);
      }
    }
    

    You use as

    <div ngbDropdown [extend-dropdown]="open" class="d-inline-block">
      ...
    </div>
    
    //If you has a function in .ts
    open(event)
    {
       console.log("from main",event)
    }
    

    or

    <div ngbDropdown extend-dropdown class="d-inline-block">
      ...
    </div>
    

    See stackblitz