Scenario :
I use this code for a page and apply it on click event, now I have trouble to remove it from page (same way, on click).
How do I do that?
document.addEventListener('touchmove', function(e) {
e.preventDefault();
}, {
passive: false
});
Use a named callback function touchMove when binding/unbinding the event listener to addEventListener and removeEventListener methods.
The event listener to be removed is identified using a combination of
the event type, the event listener function itself, and various
optional options that may affect the matching process;
var touchMove = function(e){
e.preventDefault();
};
document.addEventListener('touchmove', touchMove, { passive: false });
document.removeEventListener('touchmove', touchMove);
So initialize your button to add the event listener on click to the touchmove area, then remove the click function from the button and set it up so the next cick adds the remove event listener for removing the click and touch event. Basically toggle the event listener on the button and the div.
//Touchmove action
function preDef(e) {
e.preventDefault();
}
//Add the touchmove action and toggle the button to remove the action
function addE(e) {
e.target.removeEventListener('click', addE, {passive: false});
e.target.addEventListener('click', removeE, {passive: false});
document.addEventListener('touchmove', preDef, {passive: false});
}
//Remove the touchmove action and toggle the button to add the action
function removeE(e) {
e.target.removeEventListener('click', removeE, {passive: false});
e.target.addEventListener('click', addE, {passive: false});
document.removeEventListener('touchmove', preDef, {passive: false});
}
//Initialize the add action
document.getElementById('somebutton').addEventListener('click', addE, {passive: false});
Related
I have 2 seperate event listeners, the first one is a click event, second one is a window beforeunload listener:
This is the click event listener:
document.body.addEventListener('click',function(event){
if (event.defaultPrevented) return;
console.log('click EL');
})
and this is the beforeunload listener:
window.addEventListener("beforeunload", function (e) {
e.preventDefault();
console.log('beforeunload EL');
})
Can I stop the click event from firing if the beforeunload is fired? I've tried doing it with event.preventDefault(); still it didn't work.
Try this, This is working code:
var beforeunload = function (e) {
e.preventDefault();
console.log('beforeunload EL');
}
window.addEventListener("beforeunload", beforeunload);
document.body.addEventListener('click',function(event){
if (event.defaultPrevented) return;
console.log('click EL');
window.removeEventListener("beforeunload", beforeunload);
});
Just remove the listener if your click happened
Since dispatchEvent, as per the docs, will apply the:
normal event processing rules (including the capturing and optional
bubbling phase)
I'm looking for something similar but with a way to skip this process and trigger the event directly on the element. To trigger the default element event behavior while bypassing the processing stage.
As in, to capture the event at window level (before it reaches the other capture triggers) and pass it straight to the component (text area) invoking it directly.
(For example to trigger the default keydown of a text area without going through the hierarchy)
I've been trying to do it like this but if there is another event at window level this will not work:
window.addEventListener("keydown", this.keyDown, true);
keyDown = (event) => {
event.preventDefault();
event.nativeEvent && event.nativeEvent.stopImmediatePropagation();
event.stopImmediatePropagation && event.stopImmediatePropagation();
event.stopPropagation();
// Pass event straight to the element
return false;
};
I'm looking to trigger the default element event behavior while bypassing the processing
There may well be a more elegant way to do this, but one option is to remove the element from the DOM first, dispatch the event to it, then put it back into the DOM:
document.body.addEventListener('keydown', () => {
console.log('body keydown capturing');
}, true);
document.body.addEventListener('keydown', () => {
console.log('body keydown bubbling');
});
const input = document.querySelector('input');
input.addEventListener('keydown', () => {
console.log('input keydown');
});
const node = document.createTextNode('');
input.replaceWith(node);
input.dispatchEvent(new Event('keydown'));
node.replaceWith(input);
<input>
Since the element isn't in the DOM when the event is dispatched, the elements which used to be its ancestors won't see the event.
Note that events dispatched to detached elements do not capture/bubble regardless, not even to parents or children of element the event was dispatched to.
Without removing the element from the DOM entirely beforehand, if the input can exist in a shadow DOM, you can also dispatch an event to it there, and the event won't capture down or bubble up (though user input, not being custom events, will propagate through):
document.body.addEventListener('keydown', () => {
console.log('body keydown capturing');
}, true);
document.body.addEventListener('keydown', () => {
console.log('body keydown bubbling');
});
outer.attachShadow({mode: 'open'});
const input = document.createElement('input');
outer.shadowRoot.append(input);
input.addEventListener('keydown', () => {
console.log('input keydown');
});
input.dispatchEvent(new Event('keydown'));
<div id="outer"></div>
Another approach would be to call stopPropagation and stopImmediatePropagation in the capturing phase, at the very beginning, when the event is at the window, and then manually call the listener function you want. Make sure to attach your window listener before any other scripts on the page run, to make sure none of the page's listeners can see the event first:
// Your script:
const input = document.body.appendChild(document.createElement('input'));
input.className = 'custom-extension-element';
const handler = (e) => {
setTimeout(() => {
console.log(e.target.value);
});
};
window.addEventListener(
'keydown',
(e) => {
if (e.target.closest('.custom-extension-element')) {
e.stopImmediatePropagation(); // Stop other capturing listeners on window from seeing event
e.stopPropagation(); // Stop all other listeners
handler(e);
}
},
true // add listener in capturing phase
);
// Example page script
// which tries to attach listener to window in capturing phase:
window.addEventListener(
'keydown',
(e) => {
console.log('page sees keydown');
},
true
);
document.body.addEventListener('keydown', () => {
console.log('body keydown capturing');
}, true);
document.body.addEventListener('keydown', () => {
console.log('body keydown bubbling');
});
The best way around propagation issues is to just execute the function:
function tester(){
console.log("Just fire the function! Don't dispatchEvent!");
}
tester();
document.getElementById('test').onkeyup = function(e){
e.stopPropagation();
console.log(this.id); console.log(e.target); tester();
}
document.body.onkeyup = ()=>{
console.log("This shouldn't fire when on #test");
}
<input id='test' type='text' value='' />
I am modifying an HTML5 app that contains the following code to prevent scrolling on one of the screens:
document.addEventListener('touchmove', function (evnt) { evnt.preventDefault(); }, false);
I can't get scrolling to come back afterwards on the other screens - I've looked through multiple answers about removeEventListener and have tried:
document.addEventListener('touchmove', function (evnt) { return true; }, false);
document.addEventListener('touchmove', function (evnt) { evnt.preventDefault(); }, true);
You cannot remove or unbind an anonymous function. (Your callback for the touchmove event).
However, you could easily achieve what you want with a variable that has reference to a function. See below:
var callback = function (evnt) { evnt.preventDefault(); };
document.addEventListener('touchmove', callback, false);
document.removeEventListener('touchmove', callback);
If you bind to touchmove on a child element of the document (maybe the page's container, whatever that may be), then do evnt.stopPropagation() in that event handler, the event will never bubble up to the document and will not get prevented.
document.addEventListener('touchmove', function (evnt) { evnt.preventDefault(); }, false);
child.addEventListener('touchmove', function (evnt) { evnt.stopPropagation(); }, false);
Instead of using an anonymous function, give it a name
var blockScroll = function(evnt) {
evnt.preventDefault();
}
Then you can add it as a listener:
document.addEventListener('touchmove', blockScroll);
And you can later remove it as a listener:
document.removeEventListener('touchmove', blockScroll);
I want to trigger click event on a element when mousedown occurs. Also, I want to enable this feature for all elements in a html page.
Is it possible with jQuery on Chrome ?
Here's my first attempt;
$.fn.mousedown = function (onclick) {
this.bind("click", function (e) { onclick.call(this, e); });
return this;
};
But this mousedown elements fired after click occurs.
$(document).on('mousedown', function (e) { $(e.target).trigger('click') })
I'm not sure though for what this should be useful.
To prevent the second click (which is the normal click) you have to do some extra work
$(document).on('mousedown', function (e) {
$(e.target).trigger('click').once('click', function (e) {
e.preventDefault();
e.stopPropagation();
});
})
In my html I have a span of class dragHandle embedded within a li.
<div class='treeView'>
<ul class='tree'>
<li><span class="dragHandle"></span>Item 1
<ul>
<li><span class="dragHandle"></span>Item 2 link</li>
</ul>
</li>
</ul>
I attach event handlers using jQuery as follows:
$(".tree li").click(function(event) {
alert("click");
event.stopPropagation();
});
$(".dragHandle").mousedown(function(event) {
alert("down");
event.stopPropagation();
});
$(".dragHandle").mouseup(function(event) {
alert("Up");
event.stopPropagation();
});
When I mousedown and mouse up over the element I get the down and up alerts, however I also get the click alert of the li's event handler too. I thought that this should be prevented from by the call to event.stopPropagation in the mousedown and mouseup handlers. How do I stop the click event being called for mousedown/up events on the dragHandle?
TIA,
Adam
How do I stop the click event being called for mousedown/up events on the dragHandle?
You capture... and eat... that event:
$(".dragHandle").click(function(event) { event.stopPropagation(); });
The key here is that click, mousedown, and mouseup are distinct events. Although you might think of a click as being a mousedown followed by a mouseup, in reality you might have click events triggered by user actions that don't even involve the mouse, as well as combinations of mousedown and mouseup that don't result in any click events at all.
You could create a simple wrapper-"class", that keeps track of mouse-down and up events:
(function () {
var DragDropHandler = {
isDrag: false,
mouseDownHandler: function (event) {
alert("down");
event.stopPropagation();
this.isDrag = true;
},
mouseUpHandler: function (event) {
alert("Up");
event.stopPropagation();
this.isDrag = false;
},
clickHandler: function (event) {
event.stopPropagation();
// Check if we've already received a mouseDown-event. If we have,
// disregard the click event since we want drag-functionality
if(this.isDrag) { return; }
alert("click");
}
};
$(".tree li").click(function(event) {
DragDropHandler.clickHandler.call(DragDropHandler, event);
});
$(".dragHandle").mousedown(function(event) {
DragDropHandler.mouseDownHandler.call(DragDropHandler, event);
});
$(".dragHandle").mouseup(function(event) {
DragDropHandler.mouseUpHandler.call(DragDropHandler, event);
});
})();
This creates a closure and delegates the event handling to the DragDropHandler-object. Note that I've used function.call (the first parameter is the context) to ensure that this refers to the DragDropHandler-object inside its methods. Since we have created an anonymous function that can not be reached from global space, I think it's acceptable to use the DragDropHandler reference inside the wrapper event handlers.