My question is little weird as i have two html buttons
as
<button>ok</button>
<button>ok</button>
and i am attaching onclick events on them like this
var buttons=document.getElementsByTagName('button');
for(var i=0;i < buttons.length; i++){
buttons[i].onclick = function() {
focus = this;
alert("ok i am clicked")
}
}
now after this i am doing
now i have an event attach on window as
window.onclick = function(e) {
console.log(e.target == focus)
}
according to me this console.log(e.target == focus) condition should be true if i click on first button but its also true for second button!
please tell me where i am wrong and please give vanilla JavaScript solution and in my scenario i can't use id i am will br very thankful to you :)
here is its bin.
From the edit, the solution to your problem is quite simple :
You set the focus element on click of each button, then the window listener fires and checks if the target (the button) is the focus element.
Obviously, it will always be true, since you just set it to be the focus element.
You could add the window listener with target.addEventListener(type, listener, useCapture); and set the useCapture to true.
Then it will fire before the button's onclick, and you'll have to click twice for your callback returns true.
You could use an "Immediately-invoked function expression".
This pattern will ensure that during the time of the click i will still hold the correct value as it has its own scope:
var buttons = document.getElementsByTagName('button');
for (var i = 0; i < buttons.length; i++) {
(function (i) {
buttons[i].onclick = function () {
alert("button " + i + " was clicked");
}
}(i));
}
See the fiddle
Related
I want avoid that double click also fire a single click event.
A simple solution i found is to delay the click with a timer and destroy the timer if a double click is fired.
var pendingClick;
function myclick(){
clearTimeout(pendingClick);
pendingClick = setTimeout(function(){
console.log('click');
}, 500);
}
function mydblclick(){
clearTimeout(pendingClick);
console.log('double click');
}
<div onclick="myclick()" ondblclick="mydblclick()">Double Click Me!</div>
But this solution is based on timing, if the double click is too slow (>500ms) it also fire a single click.
There is a stable solution for handle both click and double click?
Double-clicking in itself is "based on timing", even in the standard implementation of dblclick / ondblclick. There will always be the issue of a single-click being fired if the double-click is "too slow". What is "too slow"? 300ms? 500ms? 1000ms? Your double-clicks may be only 50ms apart, while my mom's double-clicks are 1-2 seconds apart...
You can get the event and cancel it with the addEventListener like this:
document.addEventListener('dblclick', (event) => {
event.preventDefault();
event.stopPropagation();
}, true); // With this true, you are cancelling the dblclick event
let pendingClick;
function myclick(){
clearTimeout(pendingClick);
pendingClick = setTimeout(function (){
console.log('click');
}, 500);
}
function mydblclick(){
clearTimeout(pendingClick);
console.log('double click');
}
<div onclick="myclick()" ondblclick="mydblclick()">Double Click Me!</div>
Only work with the 'onclick' function to check if it was one or two clicks and use a variable to count the number of clicks in a given time interval.
Example:
var pendingClick;
var clicked = 0;
var time_dbclick = 500 // 500ms
function myclick(){
clicked++;
if(clicked >= 2){
mydblclick()
clearTimeout(pendingClick)
clicked = 0;
return;
}
clearTimeout(pendingClick)
pendingClick = setTimeout(() => {
console.log('One click!')
clicked = 0;
}, time_dbclick);
}
function mydblclick(){
console.log('double click');
}
<div onclick="myclick()">Double Click Me!</div>
Custom Events instead of inline event handlers
If one prefers to use .addEventListener and .removeEventListener instead of HTML inline-eventhandlers, I would suggest another approach based on Custom Events. That means one would not make use of the standard implementation of "click" and "dblclick", but create own event handling for both:
let lastLeftClick = document.dispatchEvent(new Event("click"));
let doubleclickLength = 300;
function leftClickHandler (e) {
if (e.button != 0) return; // only left clicks shall be handled;
let delaySinceLastClick = e.timeStamp - lastLeftClick.timeStamp;
let eIsDoubleClick = delaySinceLastClick < doubleclickLength;
if (eIsDoubleClick) {
let doubleclickEvt = new CustomEvent("doubleclick", e);
lastLeftClick = lastLeftClick = doubleclickEvt;
document.dispatchEvent(doubleclickEvt);
} else {
let singleClickEvt = new CustomEvent("singleclick", e);
lastLeftClick = singleClickEvt;
document.dispatchEvent(lastLeftClick);
}
}
// adding above click event implementation:
document.addEventListener("click", leftClickHandler);
using the new custom events:
document.addEventListener("singleclick", e=>console.log("single click"));
document.addEventListener("doubleclick", e=>console.log("double click"));
This question already has answers here:
Javascript removeEventListener not working
(13 answers)
Closed 6 years ago.
I have 1 div (a message) which appears on the page when the page is loaded. When a user clicks somewhere on a page outside this message I want this message to disappear and show (ONCE) a log in the console that the message has disappeared. The problem is I continue receiving my console messages every time I click everywhere on my page though the message is already gone. I.E. I cannot detach 'click' event from my page. The code is following:
var elems = document.querySelectorAll(':not(#my-widget)'); //all elements in my page except message
var promptwidget = document.getElementById('my-widget');
console.log('WIDGET==> ' + promptwidget);
if (typeof(promptwidget) != 'undefined' && promptwidget != 'null') {
for (var i = 0; i < elems.length; i++) //add click eventlistener to the rest document
{
elems[i].addEventListener("click", function(e) {
e.preventDefault(),
removeWidget(["my-widget"]), //parentNode.removeChild wrapper, works OK
console.log('widget removed'), //received everytime I click on a page but I need only ONCE
promptwidget = document.getElementById('my-widget'); //tried to reassign a null value to my promptwidget var and call removeEventListener but no work
});
}
} else //this code never called, but I want it after my-widget removal
{
for (var i = 0; i < elems.length; i++) {
elems[i].removeEventListener("click", function(e) {
e.preventDefault(),
console.log("clickevent removed")
});
}
}
Any help would be appreciated.
EDIT_1:
Thank you everyone, the problem was solved as follows:
var elems = document.querySelectorAll(':not(#my-widget)');
var promptwidget = document.getElementById('my-widget');
for(var i = 0; i<elems.length; i++)
{
elems[i].addEventListener("click", function(e)
{
e.preventDefault();
if(typeof(promptwidget) != 'undefined' && promptwidget != null)
{
removeWidget(["my-widget"]),
console.log('widget removed'), //now showed once
promptwidget = undefined
}
});
}
This code was very helpful
addEventListener allows you to specify more than one event handler for each event type, so to remove a specific event handler you need to specify not only the event type, but also which handler you want to remove:
addEventListener(eventType, eventHandler);
removeEventListener(eventType, eventHandler);
// arguments passed to removeEventListener must be exactly the same
// as in addEventListener so you cannot pass an anonymous function
It doesn't make sense to pass a newly declared anonymous function as the 2nd parameter to removeEventListener. You need to pass a reference to the actual function to be removed. You will have to define this function with a name outside of the scope, and then you can use the name as a reference to remove it.
function removeWidgetFn (e) {
e.preventDefault(),
removeWidget(["my-widget"]),
console.log('widget removed'),
promptwidget = document.getElementById('my-widget');
});
And then,
elems[i].addEventListener("click", removeWidgetFn);
And then,
elems[i].removeEventListener("click", removeWidgetFn);
An element can have many click handlers, so you need to specify which click handler you want to remove.
In the following code I have "input" event handler that changes the value of the input as the user types. I also have "change" event handler to keep track of any changes made to this field. For some reason "change" event doesn't fire in Chrome and IE when the user leaves the field. Why is that and how to make it work in all major browsers?
Also note that it's not acceptable to trigger "change" event manually every time "input" event fires.
EDIT: "change" event seems to fire in Chrome only if transform function does not change the resulting string in any way. So if I type lower case letters and focus out after every character, "change" fires only for indexes 0, 2, 4 ...
Link to fiddle: http://jsfiddle.net/3hqxx2pr/
function transform(s) {
var r = "";
for (var i = 0; i < s.length; i++) {
r += i & 1 ? s[i].toUpperCase() : s[i];
}
return r;
}
$(document).ready(function(){
$("#in").on("change", function() {
console.log("changed"); // works only in ff
});
$("#in").on("input propertychange", function() {
$("#in").val(transform($("#in").val()));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<input id="in"/>
Trigger change yourself
$("#in").val(transform($("#in").val())).change();
or
$("#in").val(transform($("#in").val())).trigger("change");
Based on a edit and restriction you made:
$("#in").on("input propertychange", function() {
var inp = $(this);
var orgVal = inp.val();
var transVal = transform(orgVal);
if (orgVal !== transVal) {
inp.val(transVal).trigger("change");
}
});
I have a list of controls contained in a parent div called overlay-controls.
There is many list controls that each have their own overlay-controls.
I am using a for loop to add the event listener to each button that contains the class delete.
Before the user can delete the item, they must confirm. I am trying to attach this to every delete button found in overlay-controls.
I got it to work using a for loop but I know there is a better way using bubbling and capturing. I am having trouble targeting only the delete class inside overlay-controls by bubbling up to parent div.
See the live demo here by clicking on each delete button: http://jsfiddle.net/8qqfeoa2/1/
Here is my code using the for loop:
(function() {
function getConfirmation(e){
var retVal = confirm("Are you sure you want to delete this request?");
if( retVal == true ){
return true;
}else{
e.preventDefault();
return false;
}
}
var del = document.querySelectorAll('.delete');
for(var i = 0, len = del.length; i < len; i++){
del[i].addEventListener('click', function(e) {
getConfirmation(e);
}, false);
}
}());
You dont event need the For / .each loop
Jquery takes care of it internally
$('.delete').on('click', function(e){
getConfirmation(e);
});
Provided you are using jQuery and in getConfirmation method you may also get that specific (clicked) element by using e.target which returns the target on which click happened.
Only Javascript solution
As you requested one
var deletebuttons = document.getElementsByClassName('delete');
for(var button in deletebuttons) {
button.onclick = getConfirmation;
}
How to add multiple event listeners in the same initialization?
For example:
<input type="text" id="text">
<button id="button_click">Search</button>
JavaScript:
var myElement = document.getElementById('button_click');
myElement.addEventListener('click', myFunc());
This is working correctly however I would like to have another event listener for this input filed in the same call if that is possible, so when user clicks enter or presses the button it triggers the same event listener.
Just one note. User needs to be focused on the input field to trigger an "enter" event.
Just bind your function to 2 listeners, each one of the wished element:
document.getElementById('button_click').addEventListener('click', myFunc);
document.getElementById('text').addEventListener('keyup', keyupFunc);
where the new function test if the user pressed enter and then execute the other function :
function keyupFunc(evt) {
if(evt.keyCode === 13) // keycode for return
myFunc();
}
Working jsFiddle : http://jsfiddle.net/cG7HW/
Try this:
function addMultipleEvents(elements, events){
var tokens = events.split(" ");
if(tokens.length == elements.length){
for(var i = 0; i< tokens.length; i++){
elements[i].addEventListener(tokens[i], (e.which == 13 || e.which == 48)?myFunc:); //not myFunc()
}
}
}
var textObj = document.getElementById("textId");
var btnObj = document.getElementById("btnId");
addMultipleEvents([textObj,btnObj], 'click keyup');
UPDATE:
function addMultipleEvents(elements, events) {
var tokens = events.split(" ");
if (tokens.length == elements.length) {
for (var i = 0; i < tokens.length; i++) {
elements[i].addEventListener(tokens[i], myFunc); //not myFunc()
}
}
}
var textObj = document.getElementById("textId");
var btnObj = document.getElementById("btnId");
addMultipleEvents([btnObj, textObj], 'click keyup');
function myFunc(e) {
if (e.which == 13 || e.which == 1) {
alert("hello");
}
}
Working Fiddle
I think the best way to do this is by using for loops.
const events = ["click", "mouseover"]
for (i in events) {
document.getElementById("button_click").addEventListener(events[i], () => myFunc())
}
The code above loops through every events inside an array and adds it to the button.
Yeah this is a good question and can apply to other scenarios. You have a form and a user will have input text field, a radio box, a select option. So now you want the submit button to go from disabled to enabled. You decide to add an event listener to check if fieldA and fieldB and fieldC is first to enable submit button.
If you use event listener on Keyup", and all your fields are valid, the submit button will become enabled only if the last field is a text field because the event will only be triggered when you let go the key. This means it will not trigger if the radio box or select option is selected with your mouse. We must not rely in the order the fields are filled for the logic to work. Again, If you use "click", it sucks, because user will have to click somewhere on page in order for the event listener to fire and run the logic. So i think we'll need an event lister on mouseup, keyup and change for this example below. I assume you made all your validations and variables for the form fields already. We need a function with parameters of multiple events names as a string, the element we want to target (document, or button or form), and a custom function that contains our logic.
// Create function that takes parameters of multiple event listeners, an element to target, and a function to execute logic
function enableTheSubmitButton(element, eventNamesString, customFunction) {
eventNamesString.split(' ').forEach(e => element.addEventListener(e, listener, false));
}
// Call the above function and loop through the three event names inside the string, then invoke each event name to your customFunction, you can add more events or change the event names maybe mousedown, keyup etc.
enableSubmitButton(document, 'keyup mouseup change', function(){
// The logic inside your customFunction
if (isNameValid && isLocationValid && isProjectValid){
publishButton.disabled = false;
} else {
publishButton.disabled = true;
// Do more stuff like: "Hey your fields are not valid."
}
});
// The isNameValid isLocationValid, isProjectValid are coming from your previous validation Javascript for perhaps a select field, radio buttons, and text fields. I am adding it as an example, they have to be equal to true.
// The publishButton is a variable to target the form submit button of which you want enabled or disabled based one weather the form fields are valid or not.
// For example: const publishButton = document.getElementById("publish");