Search code examples
javascripthtmltemplatesshadow-domdocumentfragment

Adding event listeners to elements cloned from the template tag


I am creating a lot of DOM elements (each has the same HTML structure) with the <template> tag:

<template id="weapon-template">
    <div class="button">
        <div class="button-price"  data-price ></div>
        <img class="button-image"  data-image >
        <div class="button-name"   data-name  ></div>
        <div class="button-damage" data-damage></div>
        <div class="button-amount" data-amount></div>
    </div>
</template>

... and a few lines of JavaScript:

var clone;
var template = document.getElementById( "weapon-template" );

template.content.querySelector( "[data-image]"  ).src = data.prev;
template.content.querySelector( "[data-price]"  ).innerHTML = data.cost + "$";
template.content.querySelector( "[data-name]"   ).innerHTML = data.name;
template.content.querySelector( "[data-damage]" ).innerHTML = data.damage;
template.content.querySelector( "[data-amount]" ).innerHTML = 0;

clone = document.importNode( template.content, true )
this.container.appendChild( clone );

I would love to add some event listeners on the cloned elements. I could not find nothing from internet and tired a couple of things my self, like:

template.content.querySelector( "[data-price]" ).addEventListener( "click", action, false );
clone.querySelector( "[data-price]" ).addEventListener( "click", action, false );

... none of these worked. I could simply do something like:

var child  = this.container.childNodes[ 0 ];
var target = child.querySelector( "[data-price]" );

target.addEventListener( "click", action, false );

... but I wonder if there is another, simpler way similar to those that has not worked for me.


Solution

  • Until you 'activate' template using document.importNode, its content are inert nodes which are not part of DOM.

    As per addEventListener docs:

    The event target may be an Element in a document, the Document itself, a Window, or any other object that supports events (such as XMLHttpRequest).

    Therefore adding event listeners in your example won't work until you clone template contents and add them to an existing node in document.

    If you are ready to use jQuery, there is a workaround. You can use event delegation using jquery on method to bind events to parent element.

    something like this:

    $(this.container).on('click', '[data-price]', action);
    

    What this will essentially do that any click which is being triggered from children of this.container will bubble up till parent. If it satisfies the selector criteria of [data-price] action will triggered on it.