In JQuery I can do:
$(document).on(\"click\",\"a.someBtn\",function(e){
console.log(\"hi\");
});
to add an event listener to an element th
What you want is to use DOM MutationObserver Events to apply the addEventListener. This DOM API is available on all major browser since 2012 I think.
I use this on to lower the google translator bar created by their snippet (https://www.w3schools.com/howto/howto_google_translate.asp). Since it creates the element dynamically (an iframe), it is the same problem you have. Just change the callback function and variables for your need.
//Observer for Google translator bar creation and action to move to bottom
// Select the nodetree that will be observed for mutations
var nodetree = document.getElementsByTagName("body")[0];
// Select the target node atributes (CSS selector)
var targetNode = "iframe.goog-te-banner-frame";
// Options for the observer (which mutations to observe)
var config = { attributes: false, childList: true };
// Callback function to execute when mutations of DOM tree are observed
var lowerGoogleTranslateBar = function(mutations_on_DOMtree) {
for(var mutation of mutations_on_DOMtree) {
if (mutation.type == 'childList') {
console.log(mutation);
if (document.querySelector(targetNode) != null) {
//40px is the height of the bar
document.querySelector(targetNode).style.setProperty("top", "calc(100% - 40px)");
//after action is done, disconnect the observer from the nodetree
observerGoogleTranslator.disconnect();
}
}
}
};
// Create an observer instance linked to the callback function
var observerGoogleTranslator = new MutationObserver(lowerGoogleTranslateBar);
// Start observing the target node for configured mutations
observerGoogleTranslator.observe(nodetree, config);
You can learn more about this here: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
Here's a function that will let you add "live" events like jQuery's .on
. It can be invoked like this:
addLiveListener(scope, selector, event, function reference);
Take a look at the function comment for the description of each of those parameters.
/**
* Adds a istener for specific tags for elements that may not yet
* exist.
* @param scope a reference to an element to look for elements in (i.e. document)
* @param selector the selector in form [tag].[class] (i.e. a.someBtn)
* @param event and event (i.e. click)
* @param funct a function reference to execute on an event
*/
function addLiveListener(scope, selector, event, funct) {
/**
* Set up interval to check for new items that do not
* have listeners yet. This will execute every 1/10 second and
* apply listeners to
*/
setInterval(function() {
var selectorParts = selector.split('.');
var tag = selectorParts.shift();
var className;
if (selectorParts.length)
className = selectorParts.shift();
if (tag != "") {
tag = tag.toUpperCase();
var elements = scope.getElementsByTagName(tag);
} else
var elements = scope.getElementsByClassName(className);
for (var i = 0; i < elements.length; i++) {
if (elements[i][event + '_processed'] === undefined && (tag == "" || elements[i].tagName == tag)) {
elements[i].addEventListener(event, funct);
}
}
}, 1000);
}
And here's a full working demo:
/**
* Adds another anchor with no events attached and lets
* our other code auto-attach events
*/
var currentAnchor = 3;
function addAnchor() {
currentAnchor++;
var element = document.createElement('a');
element.href = "#";
element.innerHTML = "Anchor " + currentAnchor;
element.className = "someBtn";
document.getElementById("holder").appendChild(element);
}
/**
* Adds a istener for specific tags for elements that may not yet
* exist.
* @param scope a reference to an element to look for elements in (i.e. document)
* @param selector the selector in form [tag].[class] (i.e. a.someBtn)
* @param event and event (i.e. click)
* @param funct a function reference to execute on an event
*/
function addLiveListener(scope, selector, event, funct) {
/**
* Set up interval to check for new items that do not
* have listeners yet. This will execute every 1/10 second and
* apply listeners to
*/
setInterval(function() {
var selectorParts = selector.split('.');
var tag = selectorParts.shift();
var className;
if (selectorParts.length)
className = selectorParts.shift();
if (tag != "") {
tag = tag.toUpperCase();
var elements = scope.getElementsByTagName(tag);
} else
var elements = scope.getElementsByClassName(className);
for (var i = 0; i < elements.length; i++) {
if (elements[i][event + '_processed'] === undefined && (tag == "" || elements[i].tagName == tag)) {
elements[i].addEventListener(event, funct);
}
}
}, 1000);
}
/**
* Now let's add live listener for "a" tags
*/
addLiveListener(document, "a.someBtn", "click", function() {
alert('Clicked ' + this.innerHTML);
});
a {
margin-right: 10px;
}
<!-- Add some pre-existing anchors -->
<p id="holder">
<a href="#" class="someBtn">Anchor 1</a><a href="#" class="someBtn">Anchor 2</a><a href="#" class="someBtn">Anchor 3</a>
</p>
<!-- A button to add dynamic new anchors -->
<input type="button" value="Add anchor" onclick="addAnchor();" />
Use the target property in the event
object to get the clicked element. Then, manually test for type/attributes/ids
document.addEventListener( "click", someListener );
function someListener(event){
var element = event.target;
if(element.tagName == 'A' && element.classList.contains("someBtn")){
console.log("hi");
}
}
You can use event.target
A reference to the object that dispatched the event.
Code
(function () {
"use strict";
document.getElementsByTagName('body')[0].addEventListener('click', function(e) {
if (e.target.tagName == 'A' && e.target.classList.contains("someBtn")) {
alert('Clicked');
}
}, false);
})();
(function() {
"use strict";
var a = document.createElement('a');
a.textContent = 'Click Me';
a.href = '#';
document.body.appendChild(a);
document.getElementsByTagName('body')[0].addEventListener('click', function(e) {
if (e.target.tagName == 'A') {
alert('Clicked');
}
}, false);
})();