jQuery stopPropagation()?
Asked Answered
I

5

6

Never come across this before can anyone give me any pointers?

I'm creating a web app for making notes like post it notes onto a whiteboard. At the moment the spawn button will spawn notes but I want to make it so that the user can click anywhere on the canvas (whiteboard) and it will spawn a new note at that position.

Here is the code for that: -

$("#canvas").bind('click', function(e){

// Calculate offset for width, put box to the left top corner of the mouse click.
   var x = e.pageX + "px";
   var y = e.pageY + "px";

$("#note").clone().insertBefore("#insertAfter").attr("id", "note" + noteID).show();
    $("#note" + noteID).children(".title").text("Note " + noteID);
        $("#note" + noteID).css({left:x, top:y, "z-index" : zindex});

    noteID++;
    zindex++;

e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();

});

The problem arises when the user clicks on one of the notes, because the notes are cloned into the canvas each time the user clicks on the note its creating another note. I want to stop this behaviour and ONLY create a note when a user clicks on a blank canvas area. I have tried preventDefauly, stopPropagation and stopImmediate... but none of them seem to have any influence.

I have also tried them on other actions such as the note click but just can't seem to get the right one in the right place? or am I going about this completely the wrong way?

example here:

http://www.kryptonite-dove.com/sandbox/animate

UPDATE:

$('#canvas').on('click', '.note', function(e) {
    e.stopPropagation();
});

This solved the problem of the notes bubbling up however it now prevents any click actions on the note class, I'm in uncharted waters here! would appreciate any pointers on how to get the click actions back working for the note title and text :)

Internuncial answered 23/3, 2012 at 22:14 Comment(0)
H
12

If you want to do something on click on #canvas, but only if the click is directly on #canvas and not on its children, then the two main options available to you are:

  1. As per your update you can handle the click on each child and stop it propagating up to the #canvas but of course that complicates other processing you might want to do for the children.

  2. Test the event.target property to see if the DOM element that initiated the event is your #canvas element.

So, noting also that (unrelated to the problem at hand) you can and should chain jQuery methods rather than re-selecting the same element:

$("#canvas").bind('click', function(e){

   // if the clicked element wasn't #canvas return immediately
   if (e.target != this)
      return;

   // Calculate offset for width, put box to the left top corner of the mouse click.
   var x = e.pageX + "px";
   var y = e.pageY + "px";

   $("#note").clone().insertBefore("#insertAfter")
                     .attr("id", "note" + noteID)
                     .css({left:x, top:y, "z-index" : zindex})
                     .show()
                     .children(".title").text("Note " + noteID);

   noteID++;  
   zindex++;

   // You may not need any of the following any more (depending on
   // what your other requirements are)
   e.preventDefault();
   e.stopPropagation();
   e.stopImmediatePropagation();

});

Here's a demo (with a much cut-down version of your JS, basically just the function from this answer and your styles): http://jsfiddle.net/H6XrW/

(Note that you don't ever need to call both of .stopImmediatePropagation() and .stopPropagation() since the former implicitly calls the latter for you.)

Hebraist answered 24/3, 2012 at 2:20 Comment(1)
Brilliant thank you!! great explanation, condensed code and JS fiddle got you the win :)Internuncial
S
3

This code will stop clicks on the notes from creating new notes:

$("#canvas").bind('click', function(e){

// Calculate offset for width, put box to the left top corner of the mouse click.
   var x = e.pageX + "px";
   var y = e.pageY + "px";

    $("#note").clone().insertBefore("#insertAfter").attr("id", "note" + noteID).show();
    $("#note" + noteID).children(".title").text("Note " + noteID);
    $("#note" + noteID).css({left:x, top:y, "z-index" : zindex});

    noteID++;
    zindex++;
});

$('#canvas').on('click', '.note', function(e) {
    e.stopPropagation();
});

It works by stopping any clicks on the notes from propagating up to the canvas div.

Stall answered 23/3, 2012 at 22:25 Comment(3)
This works to stop the propagation which is GREAT thankyou! :) however.. every other click action on the note is also now not working. Feel like its coming together but still something missing!Internuncial
If you are assuming that the note class exists, than you should probably say so. Otherwise, this approach is a more elegant version of my simplified example. +1!Patent
@elusive I checked the example which contains the note class.Stall
P
1

You will need to stop the propagation when clicking the notes, so that the #canvas element is not notified when one of its children is clicked (I am assuming that #insertAfter is a child of #canvas). Attach a click handler to each new note, that prevents the event from bubbling up:

$("#note" + noteID).click(function (e) {
    e.stopPropagation();
});
Patent answered 23/3, 2012 at 22:19 Comment(1)
have tried the above and with live but no joy, the notes are still bubbling, anymore ideas?Internuncial
R
0

I'm a bit of jquery noob so there may well be a neater way of doing this, but I've tested the following and it works for me. I would be interested to hear from others if I could have done anything better. I didn't touch the HTML or CSS.

// ----------------- BRING TO FRONT ------------------- 

$(".note").live("click", function (e) {
    console.log("Note click");
    $(this).css({"z-index" : zindex}); //Increment zindex
        zindex++;

    indexPos = $(this).css("zIndex"); // Get current z-index value
    e.stopPropagation();
});

// ----------------- CLONE NOTE ELEMENT -------------------


$(document).on("click", "#canvas, .clone", function(e){

    var left; 
    var top; 

    if ($(this).hasClass("clone")) {
        // If the button fired the click put the note at the top of the viewport
        console.log("Button click");
        left = 0 + noteOffset;
        top = 50 + noteOffset;
        noteOffset = noteOffset + 15;
    } else {
        // If the canvas fired the click put the note on the current mouse position
        console.log("Canvas click");
        left = e.pageX + "px";
        top = e.pageY + "px";
    }

    $("#note").clone().insertBefore("#insertAfter").attr("id", "note" + noteID).show()
        .children(".title").text("Note " + noteID).end().css({
            left: left, 
            top: top, 
            "z-index": zindex
        });

    noteID++;
    zindex++;

});


// ----------------- REMOVE NOTE ELEMENT -------------------

$(".close").live("click", function (e) {
    console.log("Close click");
    $(this).parent().remove();
    e.stopPropagation();
});
Rushing answered 24/3, 2012 at 1:3 Comment(0)
P
0

If you put the stopEventPropagation call inside the canvas click you are preventing the click event to propagate to the CANVAS PARENTS only. The click "travels" from inner element up in the DOM.

Here is a link with an example:

http://redfishmemories.blogspot.it/2014/08/jquery-prevent-event-propagation-and.html

Partin answered 9/8, 2014 at 11:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.