Reputation: 34149
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>
Upvotes: 0
Views: 252
Reputation: 28621
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>
Upvotes: 1
Reputation: 206565
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.
Upvotes: 1