0

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>

7
  • Would a return statement satisfies you need? Commented Sep 1, 2021 at 15:53
  • the only way to stop the execution of a function (which your click handler is), is to return from it. Commented Sep 1, 2021 at 15:55
  • Document already responded to that custom "response.beforeSave" event - makes no sense to stop propagation. Usually stopping an event propagation is a bad idea. Every part of an application should always be notified of occurring events. Or I'm not sure what you're trying to accomplish...?! Commented Sep 1, 2021 at 15:55
  • 1
    The seems like it could be solved by utilising better code structure, instead of preventDefault()/stopPropagation()/a variable to control external function flow. Commented Sep 1, 2021 at 15:56
  • 1
    You want to know if an event you triggered got cancelled? You probably want to rethink how you are coding this. That is an odd pattern. Commented Sep 1, 2021 at 15:56

2 Answers 2

1

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>

Sign up to request clarification or add additional context in comments.

1 Comment

Its worked. However we have to use isImmediatePropagationStopped as function not property if (beforeSaveEvent.isImmediatePropagationStopped())
1

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.

2 Comments

I ended up passing the arbitrary data. But I attached the data to event var beforeSaveEvent = jQuery.Event("response.beforeSave"); beforeSaveEvent.canSave = true; $(document).trigger(beforeSaveEvent); and then in handler set evt.canSave = false
@LP13 yes, that's exactly what you can do by passing data around via that param. Preventing, stopping propagations is almost never a good pattern approach. I really advice for the above solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.