How to stop propagating from event handler in JavaScript? - javascript

I have a button that triggers an event on a click. Then I have a subscriber to that event. Inside the subscriber's event handler if certain condition is true then I want to stop processing everything inside button's click event.
I tried calling e.preventDefault(), e.stopPropagation() and e.stopImmediatePropagation() but nothing works.
$("#btn").click(function() {
// trigger event
console.log("triggering event");
$(document).trigger("response.beforeSave");
//I want to stop processing after this when subscriber invokes preventDefault() or
//stopPropagation()
console.log("after trigger. This should not get invoked.");
})
$(document).off("response.beforeSave").on("response.beforeSave", function(e) {
console.log("start subscriber");
if (true) // if condition is true
{
//e.preventDefault();
//e.stopPropagation();
e.stopImmediatePropagation();
return;
}
console.log("exit subscriber. This should not get invoked.");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="btn" type="button">Click Me</button>

You should create your own Event Object and pass that to the .trigger rather than a string with the event name.
This will allow you to check what happened to the event.
An example exists on the jQuery trigger page
var event = jQuery.Event( "submit" );
$( "form" ).first().trigger( event );
if ( event.isDefaultPrevented() ) {
// Perform an action...
}
Here's your code updated to match:
$("#btn").click(function(e) {
// trigger event
console.log("triggering event");
// create a new event object
var beforeSaveEvent = jQuery.Event("response.beforeSave");
$(document).trigger(beforeSaveEvent);
if (beforeSaveEvent.isImmediatePropagationStopped()) {
console.log("event stopped");
// can also check beforeSaveEvent.isDefaultPrevented
// can also check beforeSaveEvent.isPropagationStopped
// e is the click event - function(e) above
// could also use `event` here
// "cancel" the click event
e.stopPropagation();
return;
}
console.log("after trigger. This should not get invoked.");
})
$(document).off("response.beforeSave").on("response.beforeSave", function(e) {
console.log("start subscriber");
if (true) // if condition is true
{
// whichever is used, check the equivalent event.isXXX
//e.preventDefault();
//e.stopPropagation();
e.stopImmediatePropagation();
return;
}
console.log("exit subscriber. This should not get invoked.");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="btn" type="button">Click Me</button>

To put it simple, here's a suggestion by passing arbitrary data (a boolean in your case) via the second parameter of .trigger("EventNamespace", [])
$("#btn").on("click", function(evt) {
const canSave = document.querySelector("[name=canSave]").checked;
$(document).trigger("response.beforeSave", [{canSave}]);
console.log(`Handler before: canSave is ${canSave}`);
if (!canSave) return;
console.log(`Handler after`);
});
$(document).on("response.beforeSave", function(evt, data) {
if (!data.canSave) return;
console.log(`Subscriber: canSave is ${data.canSave}`);
});
<label><input type="checkbox" name="canSave"> toggle "canSave"</label><br>
<button id="btn" type="button">Click Me</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
PS: place $(document).trigger before (like in the example) or after the if(canSave) statement - depending on what you need.

Related

Use off() inside event jquery

$(function(){
$("#selector").on("someevent", function(){
let variable = some_value;
$("#anotherselector").click(function(){
//code involving variable here
if(condition){
$(this).off(reference to click event here);
}
});
});
});
Is there any way to turn off an event from inside its handler? I'm trying to do something like the code above, and I need it to turn off ONLY that specific click event (each click event is different).
To reference the click event, you can simply pass it 'click' and the selector for which to disable the event:
$(function(){
$("#selector").on("someevent", function(){
$("#anotherselector").click(function(){
if(condition){
$('#anotherselector').off('click');
}
});
});
});
let numHandler = 0;
$('#register').click(function () {
let counter = 0;
let num = ++numHandler;
$('#clickme').click(function handler () {
counter++;
console.log(`Handler ${num} clicked!`);
if (counter == 3) $('#clickme').off('click', handler);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="clickme">Click me!</button>
<button id="register">Register new handler</button>
You can read more about the off function in the jQuery documentation.

How do I stop .click()?

I create a button 2 button. "square" and "circle"
When I click square and click circle. Square could not stop working.
<button id="square">square</button>
<button id="circle">circle</button>
Do I need to do?
$('#square').on('click', function () { $("canvas").on({
mousedown: function (e) {
...
},
mousemove: function (e) {
..
},
mouseup: function () {
..
}
}); });
$('#circle').on('click', function () { $("canvas").on({
mousedown: function (e) {
...
},
mousemove: function (e) {
..
},
mouseup: function () {
..
}
}); });
If you add an event listener with jQuery method .on() you can remove this event listener with jQuery method .off() like this:
$('#square').on('click', fnEventHandler); // add ONE on click event listener to #square DOM element
$('#square').off('click'); // remove ALL on click event listeners from #square DOM element
For your specific mockup it could look somehow like this:
$('#square').on('click', function() {
console.log('button#square on click handler'); // just for debug purpose
$('#circle').off('click'); // remove button#circle event listener
// do what ever you want to do after click on #square eg: $("canvas").on(...)
});
$('#circle').on('click', function() {
console.log('button#circle on click handler'); // just for debug purpose
$('#square').off('click'); // remove button#square event listener
// do what ever you want to do after click on #circle eg: $("canvas").on(...)
});
Please click both buttons:
<button id="square">square</button>
<button id="circle">circle</button>
<br>
To reset the behavior click "Run code snippet" again.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Or you make use of the disabled-attribute:
$('#square').on('click', function() {
console.log('button#square on click handler'); // just for debug purpose
$('#circle').prop('disabled', true); // disable button#circle event listener
// do what ever you want to do after click on #square eg: $("canvas").on(...)
});
$('#circle').on('click', function() {
console.log('button#circle on click handler'); // just for debug purpose
$('#square').prop('disabled', true); // disable button#circle event listener
// do what ever you want to do after click on #circle eg: $("canvas").on(...)
});
Please click both buttons:
<button id="square">square</button>
<button id="circle">circle</button>
<br>
To reset the behavior click "Run code snippet" again.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
The snippets above should illustrate whats going on in essence.
The snippet below shows an advanced way to add, remove and re-add event listeners in a somehow more generic way.
(function( $ ) {
var oHasEventListener = {},
removeEventListener = function( sKey ) {
// sanitize sKey first
if ( !oOnClickHandler[ sKey ] ) {
return console.log('sKey: "' + sKey + '" is not available'); // just for debug purpose
}
if ( oHasEventListener[ sKey ] ) {
$('#' + sKey).off('click').prop('disabled', true);
oHasEventListener[ sKey ] = false;
console.log('button#' + sKey + ' on click listener removed'); // just for debug purpose
}
},
addEventListeners = function() {
for ( sKey in oOnClickHandler ) {
if ( !oHasEventListener[ sKey ] ) {
$('#' + sKey).on('click', oOnClickHandler[ sKey ]).prop('disabled', false);
oHasEventListener[ sKey ] = true;
console.log('button#' + sKey + ' on click listener added'); // just for debug purpose
}
}
},
oOnClickHandler = {
square: function() {
console.log('button#square on click event catched'); // just for debug purpose
removeEventListener('circle');
// do what ever you want to do after click on #square eg: $("canvas").on(...)
},
circle: function() {
console.log('button#circle on click event catched'); // just for debug purpose
removeEventListener('square');
// do what ever you want to do after click on #circle eg: $("canvas").on(...)
},
reset: addEventListeners
};
addEventListeners(); // add event listeners on startup
})( jQuery )
<button id="square">square</button>
<button id="circle">circle</button>
<button id="reset">reset</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
If you need some further explanations please feel free to leave a comment.

How to "Hijack" jQuery events and then trigger the default handler on some condition

I am trying to do something like Hijack the jQuery events of some elements, do a judgement, and then trigger the default handler if necessary.
Say I have a page with some inputs and buttons, and each of them are already bind with event handlers(click, focu key events, etc.) to do their jobs.
What I want to achieve is: whenever these elements' events are fired, I'd like to trigger my function first, this function will gather some data, and judge whether the execution should continue.
If no the corresponding handler should not be called like nothing happened.
If yes the original handler should be triggered with the original event data.
I don't want to change the default handlers to achieve this, so, is there a good way to do something like this?
Thanks
You could use the internal method _data()
/* add some event handlers */
$("button").on("click", function() {
console.log("Button clicked");
});
$("button").on("click", function() {
console.log("Button clicked 2");
});
/* hijack them */
var button = $("button"),
boundEvents = $._data(button.get(0)).events;
$.each(boundEvents, function(key, eventHandlers) {
// save the handlers from being "destroyed" by .off()
eventHandlers = eventHandlers.map(function(eh) {
return eh.handler;
});
// remove the event handlers
button.off(key);
// add the hijacked version
$.each(eventHandlers, function(idx, handler) {
button.on(key, function(e) {
if ($("#cb").prop("checked")) {
handler(e);
} else {
console.log("nothing to do...");
}
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type="checkbox" id="cb" />
<br />
<button>Click me</button>
Try defining function at .data() of each that has events attached which is called at if condition within handler. If function returns true , do stuff , if function returns false do not do stuff
$("div").on("click", function() {
// if `check` returns `true`, do stuff
if ($(this).data().check()) {
console.log(this.tagName)
}
});
$("input").on("focus", function() {
// if `check` returns `true`, do stuff
if ($(this).data().check()) {
console.log(this.tagName)
}
});
var elems = $("*").filter(function(i,el) {
return $._data(el).events !== undefined
})
elems.each(function(i, el) {
$(el).data().check = function() {
// define condition here
// if element has `css` `color` property set to `"blue"`
// return `true`, else return `false`
if ($(el).css("color") === "rgb(0, 0, 255)") return true
else return false
}
});
div {
color:blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div>click</div>
<input type="text" />
<span>text</span>

jquery change sometimes event prevents click event

In the following example, there is a simple input field and a button.
<body>
<input type="text" id="in">
<input type="button" value="click" id="button">
</body>
There is a change-event-function on the input field and a click-event-function on the button.
$(document).ready(function() {
$('#in').change(function() {
console.log('change event');
//window.alert('change event');
});
$('#button').click(function() {
console.log('click event');
});
});
On changing the value of the input field and immediately clicking the button (without leaving the cursor), my expectation is, that both events are fired. Unfortunately this behavior depends on the code executed inside the change-function e.g. on uncommenting the window.alert line, the click event is NOT fired - or the click-event-function is not executed. Why? How can I avoid code, which prevents the click-event-function from executing?
Update:
instead of the window.alert, the jquery.hide has the same effect
$(document).ready(function() {
$('#in').change(function() {
console.log('change event');
$('#hide').hide();
});
$('#button').click(function() {
console.log('click event');
});
});
If you want to fire both of two events, you can do like this:
$(document).ready(function() {
$('#in').change(function() {
console.log('change event');
window.alert('change event');
$('#button').click();
});
$('#button').click(function() {
console.log('click event');
});
});
Try
$(document).mousedown(function(e){
console.log('click event');
});
The mousedown event will occur before textbox change and click events so that you need to set time out and check the changed value of the text box if required.

Using click event while button is disabled

I need to check on clicks while the button is disabled is this possible? Or is there any other way to this?
HTML:
<form id="form">
<input type="submit" id="submit" value="Submit" />
</form>
JS:
$("#form").submit(function (e) {
e.preventDefault();
return false;
$("#submit").on("click", function () {
alert("Bla");
});
});
JS Fiddle: http://jsfiddle.net/hjYeR/1/
When you are using preventDefault(), there is no need to use return false.
However, any code after return statement in a function, won't execute.
Also there is no need to attach an event inside another event, write them separately:
$("#form").submit(function (e) {
e.preventDefault();
});
$("#submit").on("click", function () {
alert("Bla");
});
jsFiddle Demo
After you return false; the rest of your function will not run. You can bind your click event before returning false and it should work.
return statements are the end point in the function, the codes will not proceed ahead of that.
What you can do is simply remove the click event handler from within the submit handler itself.
$("#form").submit(function (e) {
return false; //e.preventDefault(); is not needed when used return false;
});
$("#submit").on("click", function () {
alert("Bla");
});

Categories