Javascript: Tippy.js не работает для динамического контента

У меня есть следующий совет, где при наведении Ajax-вызов идет и получает данные, создает содержимое и показывает его. Но это не работает для динамического контента, потому что при загрузке страницы

<span class="more-tags otherPostTags" data-postId="{{$post->id}}">...</span>

На странице появляется статическое значение, но на вкладке также отображается динамическое.

Таким образом, приведенный ниже код работает для статического

<span class="more-tags otherPostTags" data-postId="{{$post->id}}">...</span>

но не работает для динамического.

<div id="template" style="display: none;">
    Loading a new image...
</div>

<span class="more-tags otherPostTags" data-postId="{{$post->id}}">...</span>

Типпи JQuery:

const template = document.querySelector('#template');
const initialText = template.textContent;

const tip = tippy('.otherPostTags', {
    animation: 'shift-toward',
    arrow: true,
    html: '#template',
    onShow() {
        const content = this.querySelector('.tippy-content')
        if (tip.loading || content.innerHTML !== initialText) return
        tip.loading = true
        node = document.querySelectorAll('[data-tippy]');
        let id = node[0].dataset.postid;
        $.ajax({
            url: '/get/post/'+id+'/tags',
            type: 'GET',
            success: function(res){
                let preparedMarkup = '';
                res.tags.map(function(item) {
                    preparedMarkup +=
                        '<span class="orange-tag" style="background-color: '+item.color+'">'+
                            item.name +
                        '</span>';
                });
                content.innerHTML = preparedMarkup;
                tip.loading = false
            },
            error: function(error) {
                console.log(error);
                content.innerHTML = 'Loading failed';
                tip.loading = false
            },
        });
    },
    onHidden() {
        const content = this.querySelector('.tippy-content');
        content.innerHTML = initialText;

    },
    popperOptions: {
        modifiers: {
            preventOverflow: {
                enabled: false
            },
            hide: {
                enabled: false
            }
        }
    }
});

Что мне здесь не хватает?

3 ответа

Решение

Если вы хотите, чтобы Tippy активировал новые элементы, вам нужно использовать делегирование событий. Документация Tippy покрывает это (разочарование, без привязки к ссылке; поиск "делегирование события"). Вы используете родительский элемент контейнера, а затем сообщаете Tippy, какой селектор использовать для соответствия дочерним элементам. Пример из документации:

tippy('#parent', {
  target: '.child'
})

... так что для вашего примера, используйте контейнер все .otherPostTags элементы находятся в (document.body в худшем случае) и использовать .otherPostTags как target:

tippy('selectorForParentElement', {
  target: '.otherPostTags'
});

Живой пример:

tippy('#container', {
  target: '.otherPostTags'
});
var counter = 0;
var timer = setInterval(function() {
  ++counter;
  var tag = document.createElement("span");
  tag.title = "Tip for span #" + counter;
  tag.className = "otherPostTags";
  tag.innerHTML = "Span #" + counter;
  document.getElementById("container").appendChild(tag);
  if (counter === 6) {
    clearInterval(timer);
  }
}, 250);
.otherPostTags {
  color: white;
  background-color: #2020FF;
  border: 1px solid black;
  padding: 2px;
  margin-left: 2px;
  margin-right: 2px;
  border-radius: 4px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/tippy.js/2.5.4/tippy.css" rel="stylesheet"/>

<div id="container"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/tippy.js/2.5.4/tippy.min.js"></script>

Это изменилось в более новой версии Типпи.

Вам необходимо импортировать delegate метод от tippy.js:

import { delegate } from 'tippy.js';

Затем инициируйте свои типичные всплывающие подсказки с помощью метода делегата для корневого элемента и установите селектор элементов, которые будут иметь фактические всплывающие подсказки через target опора:

delegate( '#root', {
  target: '[data-tippy-content]'
} );

Убедитесь, что #root элемент действительно существует в вашем приложении или используйте что-нибудь еще, например bodyнапример. Затем не забудьте указать фактическим элементамdata-tippy-content атрибут или изменить target селектор соответственно.

Я смог сделать это с Laravel следующим образом:

      @for($i = 0; $i < 10; ++$i)
  <br /> &nbsp;&nbsp;&nbsp;&nbsp;&lt;button data-tippy-content="&lt;img src='https://picsum.photos/300/300?random={{$i + 1}}' /&gt;">Text</button&gt;
  <br />
@endfor

<script>
  tippy('[data-tippy-content]', {
    trigger: 'click',
  });
</script>
Другие вопросы по тегам