I want to create class and want to pass my element to it and fire events form class instead of triggering from javascript events everytime.
My try
HTML :
<div id="upload-container">
<label for="myfile">Select a file:</label>
<input type="file" id="fileInput" name="myfile">
<button id="send"> Upload </button> </div>
Javascript class :
function Myevents(ele) {
this.element = ele;
}
Myevents.prototype = {
init: function() {
this.element.addEventListener('click', function(file) {
console.log(file)
}(this.element));
this.element.addEventListener('mouseover', function(file) {
console.log(file)
}(this.element));
}
}
var ele = document.getElementById('send');
var instance = new Myevents(ele);
instance.init();
instance.click() ; // should be able to call it manually
instance.mouseover(); // should be able to call it manually
here both above two calls are not firing as required, how to handle this ,any help would appreciated.
Here I recreate your Myevents function. I make a click function as a prototype and attach click event listener and call it implicitly.
const Myevents = function(el) {
this.element = el;
}
Myevents.prototype = {
click: function() {
// Attach the event listener
this.element.addEventListener('click', (e) => {
e.preventDefault();
console.log('clicked');
});
// Finally fire the click
// this.element.click();
}
}
const el = document.querySelector('#clickbtn');
const instance = new Myevents(el);
instance.click();
<div>
<p>Hello World</p>
<button id="clickbtn">Ok</button>
</div>
Note: I don't know but let me know if it fulfills your requirement.
Related
I have a scenario where I wanted to load a page on inital load. I found that this would do the trick:
<main id="mainContent">
<iframe id="InitalIframe" src="./Pages/Start/index.html" onload="this.before((this.contentDocument.body||this.contentDocument).children[0]);this.remove()"></iframe>
</main>
I have some links in my header which I attach click listners to:
(function() {
document.querySelectorAll(".link").forEach((item) => {
item.addEventListener("click", (event) => {
event.preventDefault();
const url = event.target.dataset["url"];
getHtmlFile(`./Pages/${url}/`, (data) => {
document.getElementById("mainContent").innerHTML = data;
executeScripts();
});
return false;
});
});
})();
This worked untill I added a few links inside of the Start/Index.html file which gets renderd via the iframe.
I have these two buttons inside of that html.
<button type="button" class="link refbtn" data-Url="One">
One
</button>
<button type="button" class="link refbtn" data-Url="Two">
Two
</button>
Since I attached my listners before the iframe has loaded they never get picked up.
But when I waited for the iframe to load:
document.getElementById("InitalIframe").onload = function() {
document.querySelectorAll(".link").forEach((item) => {
item.addEventListener("click", (event) => {
event.preventDefault();
const url = event.target.dataset["url"];
getHtmlFile(`./Pages/${url}/`, (data) => {
document.getElementById("mainContent").innerHTML = data;
executeScripts();
});
return false;
});
});
};
the click events did not get attached and I got a weird looking result on the page.
Question is how do I accomplish this?
For anyone struggling with the same:
I made my life easier by listening for document click events. when I found that an element with a certain class was clicked I triggered desierd functions:
document.addEventListener(
"click",
function(event) {
event.preventDefault();
const classes = event.target.classList;
if (classes.contains("link")) {
const url = event.target.dataset["url"];
app.fetcHtml(`./Pages/${url}/`, (data) => {
document.getElementById("mainContent").innerHTML = data;
});
}
return false;
},
false
);
You can get to work this with a different approach also. In other words, I had the method closest() in pure Javascript finding me the closest event target that is trigerred when I click inside the container. It will always get me the nearest <a> element which I clicked when I had wandered throught the clickable div/container area.
let base; // the container for the variable content
let dataSet;
base = document.getElementById(base.id); // target your Iframe in this case.
base.addEventListener('click', function (event) {
let selector = '.link'; // any css selector for children
// find the closest parent of the event target that
// matches the selector
let closest = event.target.closest(selector);
if (closest !== undefined && base.contains(closest)) {
dataSet= event.target.dataset["url"];
app.fetcHtml(`./Pages/${url}/`, (data) => {
document.getElementById("mainContent").innerHTML = data;
});
}
});
You can try and see if it works like this also.
Cheers
first of all, I'm new to javascript.
my question is how can I add an event listener to the button and call the function from the myObj script. I tried to google but I don't know what is the keyword for that. thank you
<div id="my-btn"></div>
<script>
myObj.button('my-btn',{
onClick: function() {
alert('Button is clicked !');
},
onCancel: function() {
alert('You cancel the process !');
}
});
</script>
and my object
var myObj = {
button: function(btnId, methods)
{
var btn = document.getElementById(btnId);
for (var method in methods)
{
if (method.toLowerCase() == 'onclick')
{
//btn.addEventListener('click', function(e) {
//}
// i want to add listener
// and call the function "onClick"
}
}
// render button
btn.innerHTML = '<input type="button" value="My Button"></button>';
}
}
thank you for your advice.
Here's one way.
<html>
<head></head>
<body>
<div id="my-btn"></div>
</body>
<script>
const myObj = {
button: (btnId, methods) => {
const btn = document.getElementById(btnId);
for (let method in methods) {
const nameLower = method.toLowerCase();
if (nameLower.startsWith('on')) {
btn.addEventListener(nameLower.substr(2), function(e) {
methods[method]();
});
}
}
// render button
btn.innerHTML = '<input type="button" value="My Button"></button>';
}
};
myObj.button('my-btn',{
onClick: () => alert('Button is clicked !'),
onCancel: () => alert('You cancel the process !')
});
</script>
</html>
We can map the function names to their events by converting to lowercase and stripping off the "on" prefix. So onClick becomes click. You could simplify things by just using the standard event names in your call to myObj.button.
Start by iterating over the functions, map the name and add the event listener. Inside the event listener all we do is call the function provided in the arguments.
I'm doing something obviously wrong but can't explain to myself.
The goal is to listen on a click event (START, first). If user clicks Start the second click listener should get ready but only fire if clicked on the particular element. If second click happens outside, the second click event listener should again be removed.
As simple as it sounds, here are my problems:
When clicking on "start" why is the document.body.addEventListener('click' firing?
How can I accomplish what I've explained?
var Blubb = function(element){
this.element = element;
document.addEventListener('make-ready', this.makeBlubbReady.bind(this), false);
};
Blubb.prototype.makeBlubbReady = function(){
var options = {one: true, two: false };
this.element.classList.remove('disabled');
this.element.addEventListener('click', (function(){this.go(options)}).bind(this), false);
document.body.addEventListener(
'click',
(function(event){
console.log('This shouldn\'t be ready before clicking "start"');
if(event.target == this.element) {
return;
}
this.element.removeEventListener('click', this.go)
}).bind(this),
false
);
};
Blubb.prototype.go = function(options){
console.log('Blubb go, options.one: ', options.one);
};
document.querySelector('.first').addEventListener('click', function(){
new Blubb(document.querySelector('.second'));
document.dispatchEvent(new CustomEvent('make-ready', {}));
}, false)
.second.disabled {
display: none;
}
<div class="first">START</div>
<br />
<div class="second disabled">BLUBB</div>
Next is pretty much the same as above. Just to explain the 1. problem more. Why does the console logs 3 when only setting up the event listener on the body? I expected to behave like setting up the event listener on this.element which also just waits to get a click event..
var Blubb = function(element){
this.element = element;
document.addEventListener('make-ready', this.makeBlubbReady.bind(this), false);
};
Blubb.prototype.makeBlubbReady = function(){
var options = {one: true, two: false };
this.element.classList.remove('disabled');
console.log('1');
this.element.addEventListener('click', (function(){
console.log('2');
this.go(options)
}).bind(this), false);
document.body.addEventListener('click', (function(){
console.log('3');
}).bind(this),
false
);
};
Blubb.prototype.go = function(options){
console.log('Blubb go, options.one: ', options.one);
};
document.querySelector('.first').addEventListener('click', function(){
new Blubb(document.querySelector('.second'));
document.dispatchEvent(new CustomEvent('make-ready', {}));
}, false)
.second.disabled {
display: none;
}
<div class="first">START</div>
<br />
<div class="second disabled">BLUBB</div>
The problem with your code is that you're using bind to bind a reference of the class to the listener, but bind would create a new reference of the listener each time it's used. Therefore you won't be able to remove the listener later on. To fix this you have to save the listener reference into a variable for later use. Also your binding the listener to the document therefore it gets executed instantly, to prevent this you could wrap the binding into a setTimeout or set the useCapture option to true.
Also you should consider making your class a singleton or destroy the previous instance because multiple instances would influence each other because of the listeners on the document.
Here's an example of a class using the techniques descripted above:
var Blubb = (function(doc) {
var defaults = {
one: true,
two: false
},
disabledClass = 'disabled',
instance = null;
function Blubb(element, options) {
if (instance) {
instance.destroy();
};
this.element = element;
this.options = Object.assign({}, defaults, options);
this.element.classList.remove(disabledClass);
this.removeListener = setupListener.call(this);
instance = this;
}
function setupListener() {
var listener = onClick.bind(this);
doc.addEventListener('click', listener, true);
return function() {
doc.removeEventListener('click', listener, true);
}
}
function onClick(event) {
if (event.target === this.element) {
this.go(this.options);
} else {
this.destroy();
}
}
Blubb.prototype.go = function(options) {
console.log('Blubb go, options: ', options);
}
Blubb.prototype.destroy = function() {
this.element.classList.add(disabledClass);
this.element = null;
instance = null;
this.removeListener();
}
return Blubb;
})(document);
// setup
document.querySelector('.first').addEventListener('click', function() {
new Blubb(document.querySelector('.second'));
}, false)
.second.disabled {
display: none;
}
.first,
.second {
background: #eee;
cursor: pointer;
}
<div class="first">START</div>
<br />
<div class="second disabled">BLUBB</div>
EDIT: You can also use bind the listener with useCapture instead of wrapping it into a setTimeout. I edited the snippet above.
I want to add 'click' listeners to dynamically created elements. My code is:
function addListenerToElements (){
var aTags = document.getElementsByClassName("classElements")
for (var i=0;i<aTags.length;i++){
aTags[i].addEventListener('click',myFunction);
}
}
function myFunction() {
console.log("something");
}
but it doesn't work(there is no errors in console)
As you are saying dynamically added elements, event delegation would be the better way to go. Below works for both static elements, but also for dynamically added ones:
document.getElementById("container").addEventListener("click", function(e) {
if (e.target && e.target.matches("div.className")) {
console.log('element clicked', e.target.innerText);
// or call your function
}
});
var index = 0;
document.getElementById('add').addEventListener('click', function(e) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(index++));
div.className = 'className';
document.getElementById('container').appendChild(div);
});
<div id="container">
<div class="className">a</div>
<div class="className">b</div>
<div class="className">c</div>
<div class="className">d</div>
<div class="className">e</div>
</div>
<button id="add">Add Element</button>
Ok you missed something here, the events wont register until you call the function
addListenerToElements();
https://jsfiddle.net/xrqnn20f/1/
addListenerToElements();
function addListenerToElements (){
var aTags = document.getElementsByClassName("classElements")
for (var i=0;i<aTags.length;i++){
aTags[i].addEventListener('click',myFunction);
}
}
function myFunction() {
console.log("something");
}
I am trying to make a function that would allow me to toggle eventListener of an element.
In the example below, I have three buttons: main, on and off. When I click on the on button, the main button becomes functional. After I click off button, the main button should not work anymore (but now it still does).
Now I can achieve a desired behavior by clicking on button for the second time, but I guess it's a bad coincidence and it's not supposed to work that way.
Maybe I should add that I would like to work this out without using jQuery or similar and it needs to be a function, because I am going to use it for a lot of buttons.
(I suspect something with scope causes the problem (clickHandler when calling the function to activate the button is not the same as the clickHandler when calling the function to disable the button), but I can't think of a way to test it.)
// buttons definitions, not important
var mainButton = document.querySelector("#mainButton");
var onButton = document.querySelector("#onButton");
var offButton = document.querySelector("#offButton");
// main function
var toggleButtons = function(toggleVal, button, element) {
var activateButton, clickHandler, disableButton;
// callback function for listener bellow
clickHandler = function() {
document.querySelector(element).classList.toggle("yellow");
};
activateButton = function() {
button.addEventListener("click", clickHandler);
};
disableButton = function() {
button.removeEventListener("click", clickHandler);
};
// when first argument is 1, make the button functional, otherwise disable its functionality
if (toggleVal === 1) {
activateButton();
} else {
disableButton();
}
};
// when onButton is clicked, call main function with arguments
// this works
onButton.addEventListener("click", function() {
toggleButtons(1, mainButton, "body");
});
// this fails to disable the button
offButton.addEventListener("click", function() {
toggleButtons(0, mainButton);
});
.yellow {
background-color: yellow;
}
<button type="button" id="mainButton">mainButton
</button>
<button type="button" id="onButton">onButton
</button>
<button type="button" id="offButton">offButton
</button>
<p>mainButton: toggles background color on click
</p>
<p>onButton: turns on mainButtons's functionality</p>
<p>offButton: supposed to turn off mainButton's functionality</p>
var mainButton = document.querySelector("#mainButton");
var onButton = document.querySelector("#onButton");
var offButon = document.querySelector("#offButton");
var element; // declare the element here and change it from toggleButtons when needed.
function clickHandler() {
document.querySelector(element).classList.toggle('yellow');
}
function activateButton(button) { // You missed this part
button.addEventListener('click', clickHandler);
}
function disableButton(button) { // You missed this part
button.removeEventListener('click', clickHandler);
}
function toggleButtons(value, button) {
if (value === 1) {
activateButton(button); // You missed this part
} else {
disableButton(button); // You missed this part
}
};
onButton.addEventListener('click', function() {
element = 'body'; // you can change it to some other element
toggleButtons(1, mainButton);
});
offButton.addEventListener('click', function() {
element = 'body'; // you can change it to some other element
toggleButtons(0, mainButton);
});
Below code helps to toggle between two functions from an eventListener:
var playmusic=false;
function playSound() {
const audio = document.querySelector(`audio[data-key="${event.keyCode}"]`)
audio.currentTime = 0
audio.play()
playmusic=true;
}
function stopSound() {
const audio = document.querySelector(`audio[data-key="${event.keyCode}"]`)
audio.pause()
playmusic=false;
}
window.addEventListener('keydown',
function(){playmusic?stopSound():playSound()} )