Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Listener's - срабатывает только последний (https://javascript.ru/forum/events/75080-listener%27s-srabatyvaet-tolko-poslednijj.html)

__Alex__ 31.08.2018 15:20

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? Но в документации ничего не нашёл...

Как это исправить / решить / обойти?

ksa 31.08.2018 15:32

Цитата:

Сообщение от __Alex__
Возможно при применении +=innerHTML затираются более ранние listener's?

Они не затираются... :no:
Ты просто создаешь новые элементы. А у них нет обработчиков.

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

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

__Alex__ 31.08.2018 15:45

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

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

Других идей как реализовать пока нет. Может у вас есть?

Aetae 31.08.2018 16:12

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

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

ksa 31.08.2018 16:29

Цитата:

Сообщение от Aetae
что значит не затираются, если затираются?

Если бы элементы были бы те же - тогда затерлись бы только обработчики.
Но меняя innerHTML создаются другие элементы, а у них обработчиков нет.

ksa 31.08.2018 16:29

Цитата:

Сообщение от __Alex__
Других идей как реализовать пока нет. Может у вас есть?

Используй методы ДОМ-модели и не трогай innerHTML... ;)

SuperZen 31.08.2018 17:09

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

__Alex__ 31.08.2018 18:04

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

Пойду применять.


Часовой пояс GMT +3, время: 05:52.