26

Here's the scenario, my content is loaded asynchronously based on a class. So if I have a link with the class ajaxLink it fires as below:

$('a.ajaxLink').click(function (e) {
        e.preventDefault();
        var container = $(this).parents('div.fullBottomContent');
        var href = $(this).attr('href');
        container.fadeOut('fast', function () {
            $.ajax({
                url: href,
                dataType: "html",
                type: "GET",
                success: function (data) {
                    container.html(data);
                    BindEventHandlers();
                    container.fadeIn();
                    $.validator.unobtrusive.parse('form');
                },
                error: function () {
                    alert('An error has occurred');
                }
            });
        });

    });

All lovely. Now in one instance I want to display a warning to the user to confirm that they want to load the page and loose all their changes so I've written this:

$('a.addANewHotel').click(function (e) {
        if (!confirm('Adding a new hotel will loose any unsaved changes, continue?')) {
            e.stopPropagation();
        }
    });

now I've tried return false, e.preventDefault() and e.stopPropagation(); but no matter what the first method is always fired? How can I prevent the extra click event from firing? Is this an order of events thing?

Don't see how this is relevant but my HTML is:

<a style="" href="/CMS/CreateANewHotel?regionID=3&amp;destinationID=1&amp;countryName=Australia" class="button wideBorderlessButton ajaxLink addANewHotel">Add a new hotel</a>
Liam
  • 27,717
  • 28
  • 128
  • 190
  • What does your html look like? – Asciiom Oct 03 '12 at 12:44
  • 1
    I don't understand why you're doing this by binding 2 different events to a same element. I would just show/not show the confirmation message depending on which element was clicked, but all inside the same click event (for example using a hasClass if) – Th0rndike Oct 03 '12 at 12:49
  • Of course it's relevant, only now do we know there is only one `a`tag with several classes and you bind two click handlers to that same a tag. – Asciiom Oct 03 '12 at 12:49
  • @ThOrndike I suppose I could do that but it's not very elegant. the ajax link code works, seems a pity to clutter it up with lots of if else's – Liam Oct 03 '12 at 12:52
  • Are the two `$(..).click()` calls executed in the same order that you've written in your post? – FixMaker Oct 03 '12 at 12:56

2 Answers2

53

Have you tried: event.stopImmediatePropagation?

I believe it is what you are looking for:

http://api.jquery.com/event.stopImmediatePropagation/

$('a.addANewHotel').click(function (e) {
        if (!confirm('Adding a new hotel will loose any unsaved changes, continue?')) {
            e.stopImmediatePropagation();
            e.preventDefault();
        }
    });
Liam
  • 27,717
  • 28
  • 128
  • 190
bstakes
  • 1,898
  • 14
  • 12
  • 1
    Will not work. He has two handlers on the same element, this would only stop propagation to parent elements and not help him with this problem. – Asciiom Oct 03 '12 at 12:54
  • 2
    From the docs: "Keeps the rest of the handlers from being executed and prevents the event from bubbling up the DOM tree." – bstakes Oct 03 '12 at 12:55
  • change my mind, this is a nicer solution! Needed a slight tweak so code eventually looked like: `if (!confirm('Adding a new hotel will loose any unsaved changes, continue?')) { e.stopImmediatePropagation(); e.preventDefault(); }` – Liam Oct 03 '12 at 13:07
  • 1
    Wow... Saved my life! Thanks :) this even works with Angular2 when I have situation to use jquery click event under Angular2!!! – normalUser Aug 29 '16 at 12:00
3

stopPropagation would stop the event from bubbling to parent elements, not prevent other click handlers on the same element from firing. So your solution won't work.

You could do it like this for example:

$('a.ajaxLink').click(function (e) {
    e.preventDefault();

    if($(this).hasClass("a.addANewHotel") &&
           !confirm('Adding a new hotel will loose any unsaved changes, continue?')){
        return false;
    }

    var container = $(this).parents('div.fullBottomContent');
    var href = $(this).attr('href');
    container.fadeOut('fast', function () {
        $.ajax({
            url: href,
            dataType: "html",
            type: "GET",
            success: function (data) {
                container.html(data);
                BindEventHandlers();
                container.fadeIn();
                $.validator.unobtrusive.parse('form');
            },
            error: function () {
                alert('An error has occurred');
            }
        });
    });

});

If you'd have a lot of different types of links you should put the common code in a function and bind the handlers using the differentiating class. These handlers can then call the common code when appropriate.

Asciiom
  • 9,867
  • 7
  • 38
  • 57
  • +1 Yes I could, would be nicer if I didn't have to cluter my generic ajaxLink click with lots of if else's though? – Liam Oct 03 '12 at 12:54
  • Depends, if you would have a lot of different kinds of links who need different handling this would get cluttered, but for this one exception it's acceptable I think. Extra suggestion added to answer. – Asciiom Oct 03 '12 at 12:56