Используйте tippy.js в angular

У меня есть директива со следующим кодом

import { Directive, Input, OnInit, ElementRef, SimpleChanges, OnChanges } from '@angular/core';
import tippy from 'tippy.js';

@Directive({
  selector: '[tippy]'
})
export class TippyDirective implements OnInit, OnChanges {

  @Input('tippyOptions') public tippyOptions: Object;

  private el: any;
  private tippy: any = null;
  private popper: any = null;

  constructor(el: ElementRef) {
    this.el = el;
  }

  public ngOnInit() {
    this.loadTippy();
  }

  public ngOnChanges(changes: SimpleChanges) {
    if (changes.tippyOptions) {
      this.tippyOptions = changes.tippyOptions.currentValue;
      this.loadTippy();
    }
  }

  public tippyClose() {
    this.loadTippy();
  }

  private loadTippy() {
    setTimeout(() => {
      let el = this.el.nativeElement;
      let tippyOptions = this.tippyOptions || {};

      if (this.tippy) {
        this.tippy.destroyAll(this.popper);
      }

      this.tippy = tippy(el, tippyOptions, true);
      this.popper = this.tippy.getPopperElement(el);
    });
  }
}

И используя следующую директиву

<input tippy [tippyOptions]="{
              arrow: true,
              createPopperInstanceOnInit: true
            }" class="search-input" type="text" 
(keyup)="searchInputKeyDown($event)">

Как я могу отобразить Tippy на mouseenter или focus, поскольку это триггеры по умолчанию, из экземпляра tippy, который у меня есть в директиве, это то, что я получаю, когда помещаю console.log(this.tippy) в строку 44

{
  destroyAll:ƒ destroyAll()
  options:{placement: "top", livePlacement: true, trigger: "mouseenter focus", animation: "shift-away", html: false, …}
  selector:input.search-input
  tooltips:[]
}

Поскольку я получаю сообщение об ошибке при попытке использовать

this.popper = this.tippy.getPopperElement(el);

ERROR TypeError: _this.tippy.getPopperElement is not a function

Как я могу заставить эту директиву работать, если я взял ее из репо в github

https://github.com/tdanielcox/ngx-tippy/blob/master/lib/tippy.directive.ts

Что мне здесь не хватает, любая помощь приветствуется, спасибо

4
0
5 352
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Я не уверен, что они пытались достичь в связанном репо, которое вы включили. Чтобы заставить tippy.js работать, вы должны иметь возможность изменить директиву на следующее:

import { Directive, Input, OnInit, ElementRef } from '@angular/core';
import tippy from 'tippy.js';

@Directive({
  /* tslint:disable-next-line */
  selector: '[tippy]'
})
export class TippyDirective implements OnInit {

  @Input('tippyOptions') public tippyOptions: Object;

  constructor(private el: ElementRef) {
    this.el = el;
  }

  public ngOnInit() {
    tippy(this.el.nativeElement, this.tippyOptions || {}, true);
  }
}

Репо рабочий пример

Эй .. ладно, позволь мне попробовать

teebo 10.08.2018 21:37

Привет, @peinearydevelopment, чувак !!! Говорят, никогда не сдавайся, я не могу в это поверить! Я пытался заставить его работать весь день, я даже пошел выпить немного холодных напитков, чтобы остыть, теперь я вернулся, и теперь это выясняется !, большое спасибо, я очень ценю вашу помощь: D

teebo 10.08.2018 21:52

С удовольствием, рад, что помог тебе. Заглянув в файл tippy.js, там не было ничего под названием getPopperElement, поэтому я не совсем уверен, что они пытались с этим сделать.

peinearydevelopment 10.08.2018 21:58

Вы также можете использовать крючок жизненного цикла ngAfterViewInit, тогда вам не понадобится setTimeout.

public ngAfterViewInit() {
    this.loadTippy();
}

Это работает с tippy.js 6.x

@Directive({selector: '[tooltip],[tooltipOptions]'})
export class TooltipDirective implements OnDestroy, AfterViewInit, OnChanges {
  constructor(private readonly el: ElementRef) {}

  private instance: Instance<Props> = null;

  @Input() tooltip: string;
  @Input() tooltipOptions: Partial<Props>;

  ngAfterViewInit() {
    this.instance = tippy(this.el.nativeElement as Element, {});
    this.updateProps({
      ...(this.tooltipOptions ?? {}),
      content: this.tooltip,
    });
  }

  ngOnDestroy() {
    this.instance?.destroy();
    this.instance = null;
  }

  ngOnChanges(changes: SimpleChanges) {
    let props = {
      ...(this.tooltipOptions ?? {}),
      content: this.tooltip,
    };

    if (changes.tooltipOptions) {
      props = {...(changes.tooltipOptions.currentValue ?? {}), content: this.tooltip};
    }
    if (changes.tooltip) {
      props.content = changes.tooltip.currentValue;
    }

    this.updateProps(props);
  }

  private updateProps(props: Partial<Props>) {
    if (this.instance && !jsonEqual<any>(props, this.instance.props)) {
      this.instance.setProps(this.normalizeOptions(props));
      if (!props.content) {
        this.instance.disable();
      } else {
        this.instance.enable();
      }
    }
  }

  private normalizeOptions = (props: Partial<Props>): Partial<Props> => ({
    ...(props || {}),
    duration: props?.duration ?? [50, 50],
  });
}

Использование этого выглядит так:

<button [tooltip]="'Hello!'">Hover here</button>
<button [tooltip]="'Hi!'" [tooltipOptions]="{placement: 'left'}">Hover here</button>

Хорошая директива @ alex-rempel. Не могли бы вы объяснить, что такое jsonEqual, потому что я с ним не знаком?

Mike Poole 24.06.2021 17:20

Другие вопросы по теме