Как расширить NgbDropdown или написать обертку для него? - PullRequest
2 голосов
/ 08 апреля 2020

В основном для всех выпадающих меню, которые я хочу запустить myOpenFunction() каждый раз, когда NgbDropDown открывается и запускается myCloseFunction() каждый раз, когда закрывается выпадающее меню?

Я думал, что смогу написать пользовательскую директиву, расширяющую NgbDropDown, и запустить функцию до и после раскрывающегося списка. что-то вроде этого:

<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>

То, что я до сих пор пробовал, основано на этом здесь

@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();
  }

}

, который выдает ошибку

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

Ответы [ 3 ]

2 голосов
/ 08 апреля 2020

Еще один подход - создать директиву и использовать 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);
  }
}

Вы используете

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

//If you has a function in .ts
open(event)
{
   console.log("from main",event)
}

или

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

См. stackblitz

1 голос
/ 08 апреля 2020

Вдохновленный ответом @ Eliseo , пока ngbDropdown В директиве есть метод openChange, который сообщит открытому основанию логического значения, что мы можем создать новое событие, такое как open и close и выдать базу значений открытого состояния

ExtendDropdownDirective

@Directive({
  selector: "[extend-dropdown]"
})
export class ExtendDropdownDirective {
  @Output() open: EventEmitter<any> = new EventEmitter();
  @Output() close: EventEmitter<any> = new EventEmitter();

  @HostListener("openChange", ["$event"]) openChangeHandler(state: boolean) {
    if (state) {
      this.open.emit();
    } else {
      this.close.emit();
    }
  }
}

теперь мы можем использовать его следующим образом

div ngbDropdown extend-dropdown class="d-inline-block" (open)="open()" (close)="close()">
        ...
</div>

демо ?

1 голос
/ 08 апреля 2020

вы можете просто создать компонент для переноса для раскрывающегося списка со всей конфигурацией, а затем использовать его везде как ngbDropdown

раскрывающийся список

<div ngbDropdown class="d-inline-block">
    <button class="btn btn-outline-primary" [id]="id" 
           ngbDropdownToggle>Toggle dropdown</button>
    <div ngbDropdownMenu [attr.aria-labelledby]="id">
        <button 
               *ngFor="let item of items" 
               ngbDropdownItem 
               (click)="clickHandler(item.action)" >
           {{item.label}}
         </button>
    </div>
</div>

компонент

export class DropdownComponent implements OnInit {
  @Input() items =[];
  constructor() { }

  clickHandler(action){
    if (action){
      action()
    }
  }
}

теперь у вас есть база многоразового использования ngbDropdown, которая может принимать список элементов qan с обратным вызовом

шаблон приложения

<app-dropdown [items]="dropDownItems"></app-dropdown>

демо ?

...