Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 21.11.2020, 02:25
Новичок на форуме
Отправить личное сообщение для Vladikslav Посмотреть профиль Найти все сообщения от Vladikslav
 
Регистрация: 10.05.2013
Сообщений: 6

Почему нельзя обратиться к элементу по его классу в шаблоне?
Коллеги, привет.
Почему не работает событие на элементе, созданном в рамках шаблона при помощи другого события?

Вот забацал латй-код для иллюстрации проблемы

Смысл такой. Написал функцию, которая из массива объектов собирает данные, подставляет их в шаблон и аппендит его в секцию DOM-а.
В массиве некоторое количество объектов с данными.
Задача вывести первый шаблон, полученный из первого объекта массива сразу, т.е. при событии DOMContentLoaded я просто запускаю данную функцию. А далее при клике на ссылку "Ещё..." выводить шаблон, полученный из следующего объекта данного массива объектов, ну и так далее выводить по одному следующие шаблоны.

В шаблоне присутствует элемент <a>, на который подвешено событие click, в котором, например, прописано alert('Yo!');
Так вот загвоздка в том, что это событие срабатывает только на первом созданном шаблоне, который генерился при DOMContentLoaded.
На последующих шаблонах событие click у данного элемента не срабатывает:
const testLinks = document.getElementsByClassName("test-link");
for(let testLink of testLinks) {
	testLink.addEventListener('click', function(event) {
		let t = event.target;
		console.log(t);
		alert ('Yo!');
	});
}

Но интересно то, что инспектор видит в доме созданный шаблон, однако показывает, что в самом первом шаблоне на элементе <a> event висит, а на остальных, сгенерированных по событию click ("Ещё..") данного ивента на их элементе <a> нет! (см. пример).

И ещё. Проверка на target при делегировании события родителю работает только в том случае, если родитель лежит за пределами генерируемого html-шаблона. Т.е. в случае с body и проверкой на target наличие нужного класса .test-link событие срабатывает.

ПОЧЕМУ ТАК ПРОИСХОДИТ?!! ПОМОГИТЕ! В ЧЁМ ЗАГВОЗДКА?

ЗЫ: делегирование не подходит мне, так как я на реальном проекте использую сторонние библиотеки, которые ни хрена не отрабатывают события при таком раскладе.

Заранее спасибо.
Ответить с цитированием
  #2 (permalink)  
Старый 21.11.2020, 03:19
Профессор
Отправить личное сообщение для Nexus Посмотреть профиль Найти все сообщения от Nexus
 
Регистрация: 04.12.2012
Сообщений: 3,395

Vladikslav, Честно говоря не дочитал ваше сообщение, т.к. ответ на вопрос стал ясен после ознакомления с макетом и вашим кодом.

Сообщение от Vladikslav
Почему не работает событие на элементе, созданном в рамках шаблона при помощи другого события?
Потому что вы вешаете слушатель события на существующие в данный момент элементы.
Подгружаемые элементы появятся только после нажатия пользователем на кнопку, ваш код к этому моменту уже отработает.

Эту проблему можно решить делегированием слушателя события ближайшему общему родителю для будущих и уже существующих элементов.

Гуглите «js event delegation».
Ответить с цитированием
  #3 (permalink)  
Старый 21.11.2020, 03:25
Профессор
Отправить личное сообщение для Nexus Посмотреть профиль Найти все сообщения от Nexus
 
Регистрация: 04.12.2012
Сообщений: 3,395

Набросал на коленке примерное решение:
document.addEventListener('DOMContentLoaded', () => {
    const wrapper = document.querySelector('.objects');
    if (!wrapper) return;
    
    const selector = '.test-link';
    wrapper.addEventListener('click', e => {
        let target = e.target;
        if (!target || !target.matches(selector) && !(target = target.closest(selector))) {
            return;
        }
        
        console.log(target);
        
        alert('Yo!');
    });
});
Ответить с цитированием
  #4 (permalink)  
Старый 21.11.2020, 08:04
Профессор
Отправить личное сообщение для voraa Посмотреть профиль Найти все сообщения от voraa
 
Регистрация: 03.02.2020
Сообщений: 730

Сообщение от Nexus
 if (!target || !target.matches(selector) && !(target = target.closest(selector))) {
Достаточно
if (!target || !(target = target.closest(selector))) {

(А когда может быть !target ?)
Ответить с цитированием
  #5 (permalink)  
Старый 21.11.2020, 14:21
Профессор
Отправить личное сообщение для Nexus Посмотреть профиль Найти все сообщения от Nexus
 
Регистрация: 04.12.2012
Сообщений: 3,395

Сообщение от voraa
А когда может быть !target ?
Не буду утверждать, но вроде когда-то ловил ошибку из-за отсутствия target, поэтому здесь проверка просто «на всякий случай»

p.s. спасибо за подсказку с .closest, почему-то не думал, что метод возвращает «ближайший родительский элемент (или сам элемент)».

Если предположить, что у события всегда будет свойство target, то условие можно сильно сократить:
if (!target.closest(selector)) return;

Последний раз редактировалось Nexus, 21.11.2020 в 14:25.
Ответить с цитированием
  #6 (permalink)  
Старый 22.11.2020, 01:12
Новичок на форуме
Отправить личное сообщение для Vladikslav Посмотреть профиль Найти все сообщения от Vladikslav
 
Регистрация: 10.05.2013
Сообщений: 6

Сообщение от Nexus Посмотреть сообщение
Vladikslav, Честно говоря не дочитал ваше сообщение, т.к. ответ на вопрос стал ясен после ознакомления с макетом и вашим кодом.
Потому что вы вешаете слушатель события на существующие в данный момент элементы.
Подгружаемые элементы появятся только после нажатия пользователем на кнопку, ваш код к этому моменту уже отработает.

Эту проблему можно решить делегированием слушателя события ближайшему общему родителю для будущих и уже существующих элементов.

Гуглите «js event delegation».

Спасибо за разъяснение, зря не дочитали до конца.

Цитата:
ЗЫ: делегирование не подходит мне, так как я на реальном проекте использую сторонние библиотеки, которые ни хрена не отрабатывают события при таком раскладе.
Я так собственно и думал как вы и описали, с делегированием предварительно тестировал и это действительно работает. Меня сбило с толку другое. Просто я для галереи изображений использовал Fullscreen Lightbox, а там JS аглифицирован и в него не залезть. Но RTFM как обычно рулит Залез в их доку а там о чудо:

Цитата:
After adding new <a> tags to detect new lightboxes or update existing ones use global refreshFsLightbox() function.
const a = document.createElement('a');
a.setAttribute('data-fslightbox', 'gallery');
a.setAttribute('href', 'images/2.jpg');
document.body.appendChild(a);

refreshFsLightbox();


Магия!!! Ребята позаботились об этом!
https://fslightbox.com/javascript/do...use#refreshing

Короче, разобрался с этим сам, можете мне карму повысить, а то я что-то в нулях засиделся здесь почему-то

Последний раз редактировалось Vladikslav, 22.11.2020 в 01:15.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Обратиться к элементу формируемому скриптом spo Общие вопросы Javascript 3 06.12.2012 03:48
как обратиться к элементу созданному с помощью jQuery .after() ? mitiya Общие вопросы Javascript 1 25.09.2012 03:11
как обратиться к элементу из XML Rentony Элементы интерфейса 1 20.12.2011 11:24
Функция не позволяет остаться элементу на странице. Почему? jsuse Общие вопросы Javascript 9 10.11.2011 09:49
как обратиться к childNode по его id в div-е, через id родителя kichSman Events/DOM/Window 5 28.10.2009 02:16