JavaScript event-handling (propagation/bubbling) - javascript

I've added an event listener to my document, that is listening on keydown. When certain shortcuts, i.e. CTRL+s, is hit, I want something to happen.
The problem is that an event is created everytime a key is pressed down, and when the right combination of keys is pressed down ALL the events that are saved up are fired at once.
Example:
I have a textbox that the user can write into. Every time they press a key an event is saved.
If they write abc into the textbox, then I have three events; a, ab and abc.
I only want the last event to be fired, not the first two.
The reason this happens, as far as I know, is because of propagation (earlier called bubbling).
What can I do to only fire the last event in the bubble?
My code:
useEffect(() => {
window.addEventListener("keydown", (event) => {
if (event.ctrlKey && event.key === "s") {
var isBtnDisabled = document.getElementsByClassName("flex-none align-middle mb-5").item(0).firstChild.disabled;
if (!isBtnDisabled)
Save();
event.preventDefault();
}
}, false
);
}, [signature]);

Related

JavaScript/WebGL take periodically mouse coordinates from one click event until the second one

I have a program that simulates a cloth (made by spring and vertices) in WebGL. What the program must do is to permit the user to click on a point in the cloth, dragging it following the mouse and if the user clicks again, release it. I need to check which click event is the one that starts the dragging and which one terminates it, then I used a global variable "clicked", set it to false at the beginning and swapped everytime the event click is triggered. Now for the dragging I need periodically to take the coordinates of the mouse, then I though using a "mousemove" event was the best solution: if the "clicked" is set to true, this means that we are in the "dragging phase", then the mousemove event must be called and continue to work until the next click event. The problem is that I don't know how to use the mousemove in connection to the click event: if I put the mousemove event outside the click event, we never enter in that, and if I put the mousemove event inside the click event, also if the "clicked" variable change from true to false, the mousemove event is always called. The skeleton of the code is the following one:
var clicked = false;
function exec() {
let web_gl = document.getElementById("webgl-canvas").getContext('webgl2');
web_gl.canvas.addEventListener('click', (e) => {
clicked = !clicked;
console.log(clicked);
if (clicked == true) {
web_gl.canvas.addEventListener('mousemove', (e) => {
//do something for dragging
});
};
});
}
function main() {
exec();
};
Here also if the console prints both false and true in the correct way, we enter always in the if condition, it seems the condition sees "clicked" always true.
The other option was this one:
var clicked = false;
function exec() {
let web_gl = document.getElementById("webgl-canvas").getContext('webgl2');
web_gl.canvas.addEventListener('click', (e) => {
clicked = !clicked;
console.log(clicked);
});
if (clicked == true) {
web_gl.canvas.addEventListener('click', (e) => {
\\do something for dragging
});
}
}
function main() {
exec();
};
In this case we never enter in the event, and I don't understand why.
Does someone have an hint about this problem, or a better idea to handle what I need to implement?
Adressing your second snippet: your code is executed asynchronously, the event handlers are not executed until the event is emitted, hence clicked will still be in its initial state (false) when the condition to add the mousemove handler is evaluated, thus is will not be added and hence never be executed.
What you want to do is to add both event handlers and check within the mousemove event handler if clicked is true.
Btw. the logic you're about to implement means that a user has to click(mouse down and up) to activate the dragging and click again to disengage, rather than what's common UI practice: click(mousedown) and hold to drag things.
I found the solution. I used the click event in the main() function that is called only once, set a flag such that it is negated when a click is detected (passing from false to true and vice-versa). Inside the click event, if the flag is true, this is the first click, I add the mousemove event, picking the coordinates.

JS function setting too many addEventListeners

I have a single page app (SPA) with search functionality where I am trying to track how users interact with the search bar in Adobe Analytics. If I navigate to 5 different "pages" of my SPA, the following code will fire the event 6 times. Seems the addEventListener is being set but not cleared if no search happens on a "page". These eventListeners essentially get queued each time a "page" loads, and once a search is entered, they all fire at the same time, clearing the queue.
How can I clear the eventListeners if a search is NOT performed and only have this event fire once a search is performed via pressing enter?
Suppose I have the code:
clearInterval(interval);
var interval = setInterval(function(){
if (document.querySelector("form div[data-autoid='search_bar'] input")) {
inputField = document.querySelector("form div[data-autoid='search_bar'] input")
inputField.addEventListener('keydown', searchEntered)
clearInterval(interval);
}
}, 500);
function searchEntered(e) {
if (e.key == "Enter") {
console.log("search entered");
var event = new CustomEvent('searchEntered');
dispatchEvent(event);
}
}
If you want remove an existing event listener, use EventTarget.removeEventListener().
As the MDN page states, you need to specify the same type and listener parameters that you passed to addEventListener(). If you passed options, also, you should also pass the same ones to removeEventListener():
Given an event listener previously added by calling addEventListener(), you may eventually come to a point at which you need to remove it. Obviously, you need to specify the same type and listener parameters to removeEventListener(), but what about the options or useCapture parameters?
While addEventListener() will let you add the same listener more than once for the same type if the options are different, the only option removeEventListener() checks is the capture/useCapture flag. Its value must match for removeEventListener() to match, but the other values don't.
Note that is not possible to add multiple identical listeners to the same element. From MDN page:
If multiple identical EventListeners are registered on the same EventTarget with the same parameters, the duplicate instances are discarded. They do not cause the EventListener to be called twice, and they do not need to be removed manually with the removeEventListener() method.
If you add the event listener to window it will capture all keydown events on the page (delegate target) once that happens make a check to see if it was triggered by the Enter key and if the parentNode has the attribute data-autoid='search_bar'.
If true dispatch your custom event.
This will continue to work even if the DOM changes
addEventListener('keydown', e => {
if (e.key == 'Enter' && e.target.parentNode.dataset.autoid == 'search_bar') {
console.log('search entered');
const event = new CustomEvent('searchEntered');
dispatchEvent(event);
}
})
<div data-autoid='search_bar'>
Will trigger <input />
</div>
<label>
Won't trigger <input />
</label>
var interval = setInterval(function(){
var inputField = document.querySelector("form div[data-autoid='search_bar'] input");
if (inputField && !inputField.dataset.searchEventAttached) {
inputField.addEventListener('keydown', searchEntered);
inputField.dataset.searchEventAttached = true;
}
clearInterval(interval);
}, 500);

Tap (no realease) or click event in javascript?

I'd like to have an event fire whenever a user does a mouse click or a touchscreen tap. I've tried using the "click" event, but on touchscreens it waits until the tap has finished and is more of a tap-and-release than a tap event. It does not feel correct.
Is there an event which does either tap (no release) or click listening?
P.S. This question (JavaScript custom tap event) is about jquery.
No, there is no single event which represents the default "selection" action of both mouse and touch screen. You can, though, use a mix of events.
The two most common events users expect to create a reaction are "click" and "touchstart", but you can't simply listen to both of those because the click event is generally triggered after the touchstart event (leading to a double trigger).
The following is some simple code for avoiding this issue:
function onTapOrClick(element, cb) {
let debounce; // temporarily disables on click events when touchstarts happen
element.addEventListener("touchstart", (event) => {
if (debounce) { clearTimeout(debounce); }
debounce = setTimeout(() => debounce = undefined, 1000); // debounce is 1000ms, could easily be longer
cb(event);
});
element.addEventListener("click", (event) => {
if (debounce) { return; }
cb(event);
});
}

Jquery different data trapped from direct mousedown event and simulation via $(this).trigger('mousedown');

I need to trap some data in my webpage then user make a mousedown event or simulate it when user press TAB key on a page element.
For mousedown i use standard code like:
$('*').on('mousedown', function (e) {
// make sure the event isn't bubbling
if (e.target != this) {
return;
}
//...my code
});
and all work done, for TAB key pressure i use this code for simulate mousedown event
$(':input').keydown(function(e) {
var keyCode = e.keyCode || e.which;
if (keyCode == 9) {
$(this).trigger('mousedown');
}
});
and all seems to be done, but then i look at the e data with
console.dir(e)
there are many difference and in second case many missed data:
SAME ELEMENT CLICK AND TAB EVENTS
CLICK
mousedown event:
TAB
and with $(this).trigger('mousedown');
There are far fewer data!! For example i need e.pageX and e.pageY parameters but if i trigger event there aren't.
How can i have the same e data on both case??
Thanks in advance
In your first print, you could see the "OriginalEvent: MouseEvent" which is the one that provides the pageX/pageY...when you simulate "mousedown" you don't have the original event. Depending on which event type triggered the handler you can't access the original event. Maybe this is the case.

How to capture a tabOut event for an HTML element like button?

Using Javascript (ExtJS), how can I add an event listener for tab out of a button. I know, blur() is one way but this will also fire when the element loose focus because of other events like mouseout etc.
I want to be able to distinguish a Tabout from these other event. Is it possible?
//event parameter gives me no information whether its tab key or mouse
//btn is Ext.button.Button...
btn.on('blur', function (obj, event) {
}
You can use the keydown event:
$("button").on("keydown", function(e) {
if(e.which === 9) {
console.log("Tab pressed");
}
});
Example jsFiddle

Categories