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.
Related
Using Javascript, how do you remove a single function from a "click" event listener, after the first click event, when there are multiple functions being used on the element with the "click" event listener? Here, after the first click, only toggleView() should remain and renderList() should be removed.
const button = document.getElementById("view_button");
button.addEventListener("click", () => {
toggleView(); // want to keep this indefinitely
renderList(); // want to remove this after the first click
button.removeEventListener("click", renderList);
});
You need to add both separately, and specify { once: true } on the one you want removed after first execution.
See MDN:
once
A boolean value indicating that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked.
function toggleView() {
console.log('toggleView');
}
function renderList(evt) {
console.log('renderList');
}
const button = document.getElementById("view_button");
button.addEventListener("click", toggleView);
button.addEventListener("click", renderList, { once: true });
<button type="button" id="view_button">Click</button>
You can add two event listeners and remove the one
function toggleView() {
console.log('toggleView');
}
function renderList(evt) {
evt.currentTarget.removeEventListener("click", renderList);
console.log('renderList');
}
const button = document.getElementById("view_button");
button.addEventListener("click", toggleView);
button.addEventListener("click", renderList);
<button type="button" id="view_button">Click</button>
or you can just add logic to determine if the function should be run.
function toggleView() {
console.log('toggleView');
}
function renderList() {
console.log('renderList');
}
const button = document.getElementById("view_button");
button.addEventListener("click", () => {
toggleView();
if (!button.dataset.clicked) {
renderList();
button.dataset.clicked = '1';
}
});
<button type="button" id="view_button">Click</button>
I would use a closure here to keep track of if the item has been clicked.
const button = document.getElementById("view_button");
function toggleView() {
console.log('Toggle View');
}
function renderList() {
console.log('Render List');
}
function clickHandler() {
let hasBeenClicked = false;
return function () {
toggleView();
if (!hasBeenClicked) {
renderList();
hasBeenClicked = true;
}
};
}
button.addEventListener("click", clickHandler());
<button id="view_button" type="button">View Button</button>
I have a bootstrap modal that has some custom events, like hidden.bs.modal, depending on where the user does, I want the function in this event to be replaced, maybe it's better to understand with a simple example, consider:
const currentModal; // imagine an any modal here.
window.addEventListener('load', () => {
currentModal.addEventListener('hidden.bs.modal', standardFunction );
});
function standardFunction(){
alert('hi there');
// this is standard output to modal closed
}
function buttonClickedChange(){
// Here, i need override standardFunction
this.standardFunction = function(){
alert('modal event hidden.bs.modal changed with success!');
// this must be override previous output
};
}
What happens is that regardless of the redeclaration of the function, the output for the method is still standard, this is because the eventlistener does not refer to the stored function but only "copy" its content and creates its scope only inside.
The problem you have is when you bind the event, you are referencing that function. When you replace it does not update the reference to that function. You can clearly see that this will not work with the example
var btn = document.querySelector("button");
function myFunc () {
console.log(1);
}
btn.addEventListener("click", myFunc);
myFunc = function() {
console.log(2);
}
<button>Click Will Show 1</button>
Just remove the event listener and bind a new event.
currentModal.removeEventListener('hidden.bs.modal', standardFunction );
currentModal.addEventListener('hidden.bs.modal', myUpdatedFunction );
function myFunc () {
console.log(1);
}
var btn = document.querySelector("button");
btn.addEventListener("click", myFunc);
function myFunc2() {
console.log(2);
}
btn.removeEventListener("click", myFunc);
btn.addEventListener("click", myFunc2);
<button>Click</button>
If for some reason you can not remove the event, the only way around it would not to bind directly to the function, but to have another function call that function.
var btn = document.querySelector("button");
var myFunc = function() {
console.log(1);
}
function clickFunction () {
myFunc();
}
btn.addEventListener("click", clickFunction);
myFunc = function() {
console.log(2);
}
<button>Click</button>
Or how most people would do it is to add the logic into the function on what to do
var btn = document.querySelector("button");
var state = 0;
var myFunc = function() {
if (state===0) {
console.log(1);
} else {
console.log(2);
}
}
state = 1;
btn.addEventListener("click", myFunc);
<button>Click</button>
You used function expressin instead of function declaration. When you use function yourFunction it is moved to the top with all of the other declared functions. When you use var yourFunction = function () it is right there where you declared it. This means that hidden.bs.modal is searching for the top most function with that name which in this case is the first one you declared or the standard one. One of the ways is that you can declare your function in the global scope: function standardFunctionOverride() and add that to the listener.
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.
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()} )
Say I have an existing button and attach a click to it via jQuery:
var $button = $('#test').click(function () { console.log('original function') });
Now, say I want to override that click so that I can add some logic to the function before and after it. I have tried binding and wrapping using the functions below.
Function.prototype.bind = function () {
var fn = this;
var args = Array.prototype.slice.call(arguments);
var object = args.shift();
return function () {
return fn.apply(object, args.concat(Array.prototype.slice.call(arguments)));
}
}
function wrap(object, method, wrapper) {
var fn = object[method];
return object[method] = function() {
return wrapper.apply(this, [fn.bind(this)].concat(
Array.prototype.slice.call(arguments)));
}
}
so I call wrap with the object that the method is a property of, the method and an anonymous function that I want to execute instead. I thought:
wrap($button 'click', function (click) {
console.log('do stuff before original function');
click();
console.log('do stuff after original function');
});
This only calls the original function. I have used this approach on a method of an object before with success. Something like: See this Plunker
Can anyone help me do this with my specific example please?
Thanks
You could create a jQuery function that gets the original event handler function from data, removes the click event, then adds a new event handler. This function would have two parameters (each functions) of before and after handlers.
$(function() {
jQuery.fn.wrapClick = function(before, after) {
// Get and store the original click handler.
// TODO: add a conditional to check if click event exists.
var _orgClick = $._data(this[0], 'events').click[0].handler,
_self = this;
// Remove click event from object.
_self.off('click');
// Add new click event with before and after functions.
return _self.click(function() {
before.call(_self);
_orgClick.call(_self);
after.call(_self);
});
};
var $btn = $('.btn').click(function() {
console.log('original click');
});
$btn.wrapClick(function() {
console.log('before click');
}, function() {
console.log('after click');
});
});
Here is a Codepen
After a long search I reached the same answer as #Corey, here is a similar way of doing it considering multiple events:
function wrap(object, method, wrapper) {
var arr = []
var events = $._data(object[0], 'events')
if(events[method] && events[method].length > 0){ // add all functions to array
events[method].forEach(function(obj){
arr.push(obj.handler)
})
}
if(arr.length){
function processAll(){ // process all original functions in the right order
arr.forEach(function(func){
func.call(object)
})
}
object.off(method).on(method, function(e){wrapper.call(object,processAll)}) //unregister previous events and call new method passing old methods
}
}
$(function(){
$('#test').click(function () { console.log('original function 1') });
var $button = $('#test').click(function () { console.log('original function 2') });
wrap($button, 'click', function (click,e) {
console.log('do stuff before original functions');
click()
console.log('do stuff after original functions');
});
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id='test'>click me</div>