Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 31.08.2018, 16:20
Интересующийся
Отправить личное сообщение для __Alex__ Посмотреть профиль Найти все сообщения от __Alex__
 
Регистрация: 19.06.2018
Сообщений: 21

Listener's - срабатывает только последний
Добрый день.

Мне нужно вставлять в DOM, узлы в виде строк, и привешивать к ним listener's.

Вставляю через innerHTML, на практике, работают listener's только из последней вставки. Упрощённо:
<div id='main'></div>
<div id='out'></div>

    <script>
        function out(data) {
            document.getElementById('out').innerHTML += data;
        }

        var main = document.getElementById('main');

        function module1() {
            main.innerHTML = '<div id="first">Some text, id=first </div><br />';
            document.getElementById('first').addEventListener('click', function() {
                out('clicked on first id ');
            });
        }

        function module2() {
            main.innerHTML += '<div id="second">Some text, id=second </div><br />';
            document.getElementById('second').addEventListener('click', function() {
                out('clicked on second id ');
            });
        }

        module1();
        module2();
    </script>


Возможно при применении +=innerHTML затираются более ранние listener's? Но в документации ничего не нашёл...

Как это исправить / решить / обойти?
Ответить с цитированием
  #2 (permalink)  
Старый 31.08.2018, 16:32
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 12,782

Сообщение от __Alex__
Возможно при применении +=innerHTML затираются более ранние listener's?
Они не затираются...
Ты просто создаешь новые элементы. А у них нет обработчиков.

Вот твой аналог

<div id='main'></div>
<div id='out'></div>

<script>
var main = document.getElementById('main');
module1();
module2();

function module1() {
	main.innerHTML = '<div id="first">Some text, id=first </div><br />';
	alert(document.getElementById('first'))
	document.getElementById('first').addEventListener('click', function() {
		out('clicked on first id ');
	});
}
function module2() {
	main.innerHTML = '<div id="first">Some text, id=first </div><br />' + '<div id="second">Some text, id=second </div><br />';
	document.getElementById('second').addEventListener('click', function() {
		out('clicked on second id ');
	});
}
function out(data) {
	document.getElementById('out').innerHTML += data;
}
</script>
Ответить с цитированием
  #3 (permalink)  
Старый 31.08.2018, 16:45
Интересующийся
Отправить личное сообщение для __Alex__ Посмотреть профиль Найти все сообщения от __Alex__
 
Регистрация: 19.06.2018
Сообщений: 21

Как сделать по другому?
Можно конечно всех listener's добавлять после, но их придётся собирать из разных модулей, что сделает структуру запутанной.

Делать из стринга узлы, а потом добавлять через appendChild? Какой-то кривой путь получается, да и не понятно, "слушатели" останутся ли в этом случае?

Других идей как реализовать пока нет. Может у вас есть?
Ответить с цитированием
  #4 (permalink)  
Старый 31.08.2018, 17:12
Аватар для Aetae
Любитель
Отправить личное сообщение для Aetae Посмотреть профиль Найти все сообщения от Aetae
 
Регистрация: 02.01.2010
Сообщений: 5,680

ksa, что значит не затираются, если затираются? Зачем путать человека, придираясь к словам.)

__Alex__
, если так хочешь добавлять именно html как строку - используй метод .insertAdjacentHTML(). Однако, имхо, в твоём случае отлично бы подошёл createElement - не надо было бы переполучать только что созанный элемент, чтоб навесить на него обработчик.
Вообще тебе надо чётко представлять, что страница хранится в памяти в виде DOM - связанной структуры объектов и взаимодействия через createElement, appendChild и прочее - наиболее естественный способ. Строки же html существуют только на этапе загрузки странцы до преобразования текста в DOM. После этого любые обращения к innerHTML требуют сериализации и десериализации.
__________________
29375, 35

Последний раз редактировалось Aetae, 31.08.2018 в 17:31.
Ответить с цитированием
  #5 (permalink)  
Старый 31.08.2018, 17:29
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 12,782

Сообщение от Aetae
что значит не затираются, если затираются?
Если бы элементы были бы те же - тогда затерлись бы только обработчики.
Но меняя innerHTML создаются другие элементы, а у них обработчиков нет.
Ответить с цитированием
  #6 (permalink)  
Старый 31.08.2018, 17:29
Аватар для ksa
ksa ksa вне форума
CacheVar
Отправить личное сообщение для ksa Посмотреть профиль Найти все сообщения от ksa
 
Регистрация: 19.08.2010
Сообщений: 12,782

Сообщение от __Alex__
Других идей как реализовать пока нет. Может у вас есть?
Используй методы ДОМ-модели и не трогай innerHTML...
Ответить с цитированием
  #7 (permalink)  
Старый 31.08.2018, 18:09
Аватар для SuperZen
Профессор
Отправить личное сообщение для SuperZen Посмотреть профиль Найти все сообщения от SuperZen
 
Регистрация: 08.11.2017
Сообщений: 602

<div id='main'></div>
<div id='out' style="color:red"></div>
<button id='add'>add item</button>
<button id='remove'>remove last</button>
<script>
  var callback = (mutationsList) => {
    for (var mutation of mutationsList) {
      // если добавление или удаление Node
      if (mutation.type === 'childList') { // если добавление
        if (mutation.addedNodes.length > 0) {
          let [firstnode] = mutation.addedNodes
          firstnode.addEventListener('click', click)
        } else if (mutation.removedNodes.length > 0) { // если удаление
          let [firstnode] = mutation.removedNodes
          firstnode.removeEventListener('click', click)
        }
      }
    }
  }

  var main = document.getElementById('main')
  var observer = new MutationObserver(callback)
  var config = { attributes: false, childList: true, subtree: false }
  observer.observe(main, config)
  var click = (e) => document.getElementById('out').innerHTML = e.target.id

  document.getElementById('add').addEventListener('click', (e) => {
    var item = document.createElement('div')
    item.id = `item ${main.querySelectorAll('*').length}`
    item.innerHTML = item.id
    main.appendChild(item)
  })

  document.getElementById('remove').addEventListener('click', (e) => {
    var items = main.querySelectorAll('*')
    items.length > 0 && main.removeChild(items[items.length - 1])
  })
</script>
Ответить с цитированием
  #8 (permalink)  
Старый 31.08.2018, 19:04
Интересующийся
Отправить личное сообщение для __Alex__ Посмотреть профиль Найти все сообщения от __Alex__
 
Регистрация: 19.06.2018
Сообщений: 21

Aetae, и всем, большое спасибо. insertAdjacentHTML() - должен отлично подойти.

Пойду применять.
Ответить с цитированием
Ответ



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

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


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
setInterval срабатывает только по клику yaparoff Общие вопросы Javascript 2 16.01.2018 16:03
Событие срабатывает только 1 раз mazahaler Events/DOM/Window 4 24.12.2017 13:00
Таймер срабатывает раньше времени или вообще не срабатывает Terebonko Элементы интерфейса 6 03.08.2017 13:43
Не срабатывает последний цикл arkadii_parovozov Общие вопросы Javascript 7 01.12.2016 16:36
Нажатие по дате в календаре срабатывает только со второго клика afr0 Events/DOM/Window 4 31.10.2012 12:39