Добавление прослушивателей событий в динамически созданные элементы - PullRequest
1 голос
/ 12 октября 2019

В настоящее время у меня возникают некоторые проблемы при попытке добавить прослушиватель событий щелчка для некоторых foreignObject, отображаемых с использованием vanilla JS.

Это работает, когда я использую встроенные функции d3 при нажатии, но я бы предпочел, чтобы это было сделано с использованием кода javascript.

Однако функция никогда не срабатывает для этих элементов, и я могуНе понимаю, почему.

Пример кода не завершен, но должен подчеркнуть, что я пытаюсь сделать.

var nodes = g.selectAll("foreignObject")
    .data(response.nodes)
    .enter()
    .append("foreignObject")
    .attr("x", function(d) {
        return d.x - nodeWidth / 2;
    })
    .attr("y", function(d) {
        return d.y - nodeHeight / 2;
    })
    .attr("width", nodeWidth)
    .attr("height", nodeHeight)
    .append("xhtml:div")
    .attr("class", "outer")
    .html(function(d) { 
        var nodeHtml = createNodeElement(d);
        return nodeHtml.outerHTML;
    })
   // If I append the img like this, it works, but ends up in the wrong "element scope"
   .append("img")
        .attr("class", "optionsImg")
        .attr("src","/images/options-squares.svg")
        .on("click", function(d) {
            currentTooltipObject = d;
            renderTooltipDiv();
        });


function createNodeElement(d) {
    let nodeElement = document.createElement("div");
    nodeElement.className = "nodeElement";
    let nodeOptionsImg = document.createElement("img");
    nodeOptionsImg.className = "nodeOptionsImg";
    nodeOptionsImg.src = "/images/options-squares.svg";
    nodeOptionsImg.addEventListener("click", function() {
        console.log("Clicked on optionsImg for this object: "+d);
    });
    nodeElement.appendChild(nodeOptionsImg);
    return nodeElement;
}

Ответы [ 2 ]

0 голосов
/ 12 октября 2019

Основная проблема вашего подхода заключается в том, что использование outerHTML и innerHTML (которое используется внутри .html()) для создания / перемещения / копирования элементов похоже на сериализацию и десериализацию вашей HTML DOMдерево. Это работает для самих элементов HTML, но не сохраняет прослушиватель событий. Следовательно, слушатели, которых вы подключили к элементам вашей функции createNodeElement, теряются во время этого процесса. Это вариация других вопросов, таких как, например, «Возможно ли добавить к innerHTML без уничтожения слушателей событий потомков?» .

Если вы сделаете шаг назад и перечитаете D3 API docs , вы поймете, что вы почти на месте: D3 предоставляет средства для добавления собственных узлов DOM к выбору:

выбор . добавление ( тип ) <>

Если указано type - это функция, она оценивается для каждого выбранного элемента по порядку, когда передается текущее значение ( d ), текущий индекс ( i ) итекущая группа ( узлов ), с this в качестве текущего элемента DOM ( узлов [ i ]). Эта функция должна возвращать добавляемый элемент.

Если вы хотите придерживаться реализации createNodeElement для создания элемента с использованием собственных методов JS, вы можете просто передать эту функцию selection.append(), поскольку он возвращает вновь созданный узел вместе со своим <img> дочерним узлом. Таким образом, ваш код может быть упрощен до:

var nodes = g.selectAll("foreignObject")
    /* styling omitted */
  .append("xhtml:div")
    .attr("class", "outer")
  .append(createNodeElement);

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

0 голосов
/ 12 октября 2019

В функции createNodeElement элемент nodeOptionsImg еще не отображается при выполнении addEventListener. Слушатели могут быть добавлены только к отображаемым элементам.

...