JQuery Event repeating in dynamic content - javascript

In a page of a website I'm making, the press of a button imports the contents of a another php page and appends it onto the page. However, that other page contains JQuery, and the click event($( ".ExpandRoleButton").click) repeats itself on previous elements every time I import the content. So if I add 3 elements;
Element 1: Repeats the click event 3 times
Element 2: Repeats the click event 2 times
Element 3: Runs the click event once
$("#AjouterPiece").click(function()
{
$.blockUI({ message: '<img src="images/ChargementGeant.gif"/><br/><h1>Un moment svp.</h1>' });
$.post("wizardincl/piste.php", {newPiste: newPiste}, function(data)
{
$("#wizardPistes").append(data);
$.unblockUI();
$(".divNewPiste").fadeTo(300, 1);
$("#nbExemplaires").attr("max", newPiste);
newPiste++
$( ".ExpandRoleButton").click(function()
{
if ($(this).hasClass('RetractRoleButton'))
{
$(this).find('img').attr('src', 'images/ExpandPetitNoir.png');
var that = $(this);
$(this).parent().parent().parent().parent().next().slideUp(500, function() {
that.parent().parent().parent().parent().css('border-bottom', '1px solid #FF790B');
});
$(this).removeClass('RetractRoleButton');
}
else
{
$(this).parent().parent().parent().parent().css('border-bottom', 'none');
$(this).find('img').attr('src', 'images/ExpandPetitNoirRetour.png');
$(this).parent().parent().parent().parent().next().slideDown(500);
$(this).addClass('RetractRoleButton');
}
});
});
});
Currently, part of the JQuery website seems down and after some search, I can't find anything to solve the problem. Is there any way to keep the code from repeating itself like this?

This is because you are binding the event to multiple event handlers. The first time #AjouterPiece is clicked, all .ExpandRoleButton buttons get binded to an onclick handler.
The next time #AjouterPiece is clicked, it gets binded again.
To prevent this, you must unbind the click handlers using the following code before binding it
$( ".ExpandRoleButton").unbind('click')

You can pass in the event with .click(function(e) {...}) and then call e.stopImmediatePropagation() to fire only the current handler, but that only addresses the symptom, not the real problem.
Edit: make sure you are only binding the new instance of the button by adding a context to your selector, like $('.ExpandRoleButton', data). Since you are matching on a class, that selector will grab all the buttons on the page; the context allows you to select only the one inside your result.

A good practice ( solely to prevent issues like this from occurring, unintended multiple click handlers added ) is to..
$(".selector").off('click').on('click', function...
or
$(".selector").unbind('click')...
$(".selector").bind('click')...

Related

Why is my delegated event handler not working?

I have a button with id of Strike but the JQUERY event doesn't seem to work? This event here worked previously, but ONLY if the button existed when the DOM loaded.
dom.el('Strike').onclick = strikeSkill;
Now I have my buttons dynamically generated, so the "Strike" button is generated later. So the previous code above no longer works, because Strike = Null.
I am using the Jquery .on function, filled up my arguments, but now when I click the strike button, nothing happens. No attacking. Why is this?
function strikeSkill() {
activeCheck();
if (upgradeActive == true){
radialSelector(strike);
}
if (upgradeActive == false){
HitCalc(player.cc, monster.cc);
actor.expCounter(player.cc);
actor.balanceCounter(player.cc, monster.cc);
}
};
$('#Strike').on('click', '#Strike', function() {
strikeSkill();
});
Your current event handler is looking for a #Strike element within #Strike, which is incorrect (not to mention would be invalid HTML).
You can fix this by using a static parent element for the primary selector:
$(document).on('click', '#Strike', function(){
strikeSkill();
});
In the example I used the document, however for best performance it should be the nearest static parent element to #Strike which is available when the DOM loads.

onClick function used on dynamic content not working properly

I hit a problem with the onclick function when i add divs with ids like "n_block"+(1-~). When I use the jquery zoom function on the objects to make them smaller or bigger onClick doesn't work anymore. I'm not really good at programming so the code might be kind of confusing.
Heres the code i use for the onClick of items:
$(document).on("click",function (e, ui){
//When the document gets clicked, check if one of the items was clicked.
if($(e.target).is($("#n_block" + cloneCount1)) || $(e.target).is($("#n_block" + cloneCount1+ " span"))){
//Set current item.
var item = $("#n_block" + cloneCount1);
//Set style to current item.
item.css("border-color", "Black");
item.css("border-width","2px");
item.css("background-color", "floralwhite");
jsPlumb.repaintEverything();
//Check if key Delete was pressed while item selected & delete that item with his children.
$('html').keydown(function(e){
if(item.css("border-width")=="2px"){
if(e.keyCode == 46) {
/* Prevents line bugging*/
jsPlumb.detachEveryConnection();
jsPlumb.deleteEveryEndpoint();
var razred = getClass(item, "b_"),
id = item.prop("id");
item.remove();
if(razred == "b_2"){
$(".ovoj."+id).remove();
}
else if (razred == "b_4"){
$(".ovojLoop."+id).remove();
$(".empty_block_c."+id).remove();
}
if ( $('.objects').find('div').length == 2) {
$(".objects").empty();
$(".objects").append('<div class="b_s" id="start_block">START</div><p id="start_text">Insert symbols here!</p><div class="b_s" id="end_block">STOP</div> ');
}else{
/* Connects objects together with line. ****/
povezi(cloneCount, tip_crte, ".objects");
}
}
jsPlumb.repaintEverything();
}
});
}
// If item is not clicked set this css to the current item.
else{
$("#n_block" + cloneCount1).css("border-width","1px");
jsPlumb.repaintEverything();
}
});
And heres the zoom code for zooming in when button is clicked:
var currentZoom = 1.0;
$(".zoomin").click(function (){
//Detaches the connections from item to item.
jsPlumb.detachEveryConnection();
jsPlumb.deleteEveryEndpoint();
//Prevents spamming of button, animates the objects
$(".project").stop().animate({ "zoom": currentZoom += .1}, "slow", function() {
if(!$(".objects").children().is($("p"))){
povezi(cloneCount, tip_crte, ".objects");
}
});
});
Use event delegation for binding events to dynamically added elements.
$(document).on('click', ".zoomin", function (){
//Your code.
});
When you use normal .click() to bind event to an element, then that even gets bound to only those elements which exist in the DOM at the moment of the execution of code. Using event delegation, you can tell jQuery that we need to add the handler to every '.zoomin' element which comes inside a particular element no matter when it is added.
The solution depends when exactly is the script which tries to bind the events are executed.
For Eg: Lets assume this script is in document ready function of jquery
$(document).ready(function(){
$(".zoomin").click(function (){
//your logic here
});
});
Here this script is executed when the page HTML is completed loading into the browser. Now when the script executes it tries to find a element with the class zoomin and if found it will add a event to that element and move on. If the element is not found the script just moves on. So we should actually take care of when the script is executed and is the intended element available at that particular instant of time. If the element is not yet available in the HTML (element might come in later dynamically using jquery) we have 2 options to bind event to the element.
1) Execute the script when the element is being added into the HTML: Lets say I have a event which brings up a pop up with some image. Now I want to zoomin and zoomout the image. Since the image in the popup is added dynamically and I have control of when its being added, I can do this.
$(document).ready(function(){
$('.ViewImage').on('click',function(){
// some code is executed which brings up the popup
// now we know that the image is added into html we can now run the script
$(".zoomin").click(function (){
//your logic here
});
});
});
2) We have no Clue/ Control when the element is added into HTML but still want to bind a event to it: This is scenario where we have no control on when the element is being added or not sure where it is being added from (might be from some external plugin used etc) or not having control at all on the element which is added. Thats when we use this syntax as suggested by #Rejith R Krishnan
$(document).on('click', ".zoomin", function (){
//Your code.
});
This will work on all the elements which are in the HTML at the time of execution of the script and on the elements which will be added in the future with the class name zoomin. So this script can be placed inside/ outside of jquery document ready event

Nesting JQuery .click() events

I want to nest one .click() event with another but its not working. I looked at the .on() event, but I don't think its what I need. Below is basically what I have so far, but its not working as intended.
I want to click on the 'adress1' button, get directed to the next page where I either click the 'profession1' button or the 'profession2' button, and depending on which of the last two buttons is clicked, something respective happens.
//HTML code for first button
adress1
//HTML code on a different page for last two buttons
profession1
profession2
//Javascript/JQuery code
$("#adress").click(function(){
//Some action here based on #address click event
$("#profession-1").click(function(){
//Some action if #profession was clicked after #address
});
$("#profession-2").click(function(){
//Some other action if #profession2 was clicked instead
of profession1
});
});
Someone had told me to use the following:
$('#adress').on('click', '#profession-1', function() {alert("x1")}).on('click', '#profession-2', function() {alert("x2")});
but its not working either. I feel like my program is not registering the click.
Your help is much appreciated!
The "root" element, in this case #address, isn't a proper element to attach the click event. You want to attach to some parent element and target a child element. Events in JavaScript bubble up and trickle back down to the element that initiated the event Event Propagation.
To remedy the issue:
$('#someParentEl').on(
'click',
'#profession-1',
function() {alert("x1")}
).on(
'click',
'#profession-2',
function() {alert("x2")}
);
Further Reading:
http://www.quirksmode.org/js/events_order.html
https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation
http://learn.jquery.com/events/event-delegation/
The best way to accomplish something like this, is to have data attributes store whether or not something was clicked on... assuming this is a single page web app. Also make sure each id is unique, and referenced correctly for each click event.
address1
Then, when you click on that element, check if the data attribute is true or not on each click of the other elements.
$("#address").click(function(){
if($(this).attr("data-clicked") == "true") {
$(this).attr("data-clicked","false")
} else {
$(this).attr("data-clicked","true")
}
});
$("#profession-1").click(function(){
if($("#address").attr("data-clicked") == "true") {
//Some action
}
});
$("#profession-2").click(function(){
if($("#address").attr("data-clicked") == "true") {
//Some action
}
});
None of this was tested, but it should point you in the right direction.

Change Div Class on click takes multiple clicks before it works

I used the methods in this question:
change div class onclick on another div, and change back on body click
So here's my jQuery function:
jQuery('.checkbox_wrapper').on('click', function(e){
jQuery(this).parent()
.toggleClass('not_selected')
.toggleClass('selected');
});
However it doesn't seem to be working properly. It takes multiple clicks before the class changes.
See my jsfiddle:
http://jsfiddle.net/7A3vw/
I cut it down to the bare essentials thinking it might be conflicting javascript, but even with the single function it takes multiple clicks before the class actually changes. Because the production environment has 1 click toggle a hidden checkbox, multiple clicks is not reasonable.
Could someone help me figure out what's causing this issue?
The click function fires twice, once for the image, and once for the input, as both will bubble to the parent element, and firing twice reverts the classes again (proof).
Just target the image instead, as that is what you're really trying to click, not the parent :
jQuery('.deck_card img').on('click', function (e) {
jQuery(this).closest('div').parent().toggleClass('not_selected selected')
});
FIDDLE
i guest you need the checkbox checked together with the toggling of your div.
$(document).ready(function(e) {
$('.checkbox_wrapper').on('click', function(e){
var checked = $(this).find('input[type="checkbox"]').is(":checked");
if(checked){
jQuery(this).parent().addClass('selected').removeClass('not_selected');
}else{
jQuery(this).parent().addClass('not_selected').removeClass('selected');
}
});
});
Your code is triggering click event twice. So use .preventDefault()
This makes the default action of the event will not be triggered.
$('.checkbox_wrapper').on('click', function(e){
$(this).parent()
.toggleClass('not_selected')
.toggleClass('selected');
e.preventDefault(); // prevent the default action to be
}); // triggered for next time
Check this JSFiddle
try this
jQuery(document).on("click",'.checkbox_wrapper', function(e){
jQuery(this).parent()
.toggleClass('not_selected')
.toggleClass('selected');
});
Multiple Clicks are getting triggered because you are using class selector. You need to use not to exclude extra elements :
jQuery("div.checkbox_wrapper :not('div.checkboxdiv')").on('click', function(e){
jQuery(this).parent()
.toggleClass('not_selected selected')
});
Here is a FIDDLE.

jquery - using event.stopPropagation()

When the document is ready, I'm fetching some datas from the server through post request and I'm filling it in the HTML as tags by append. When you click that tag, a comment textarea will be displayed. When you click in the document section, the textarea will be closed. The problem here is I can't enter the text in the textarea, when I click inside, it is hiding. I tried using event.stopPropagation() but no use.
Here is my jquery code:
$.post("/person/keywords/get/", function(data){
for(i=0; i<data.length; i++)
{
count = count + 1;
$(".keywords-set").append('<div class="keyword-item"><span class="keyword" id="keyword-'+count+'">'+data[i]+'</span><textarea class="comment" id="comment-'+count+'"></textarea></div>');
}
});
$(".keywords-set").on('click', "[id^=keyword]", function(event) {
event.preventDefault();
i = $(this).attr("id");
i = i.split('-').pop();
$("#comment-"+i).show();
return false;
});
$(".comment").click(function(event) {
event.stopPropagation();
});
$(document).click(function() {
$(".comment").hide();
});
For complete HTML and javascript code, please check here: https://gist.github.com/3024186
It is working in jsfiddle
but not in my localhost. Could you tell the reason, why is it so?
Thanks!
UPDATE
I've also tried this
$(".keywords_set").on('click', ".comment", function(event) {
event.stopPropagation();
});
event.stopPropagation() is not working for HTML elements updated through ajax. But is working for normal(already given) elements.
When doing this:
$(".keywords_set").on('click', ".comment", function(event) {
You must understand that you're catching the event in the element ".keywords_set", and there you will be checking if it bubbled up through ".comment"
This means that any other "click" events set between ".keywords_set" and ".comment" will also activate.
doing stop propagation or returning false will only take affect from the bubbling of ".keywords_set" to the document.
You can do this:
$(document).click(function() {
if($(".comment:hover").length==0){
$(".comment").hide();
}
});
Edit: reply to: "Hey, that code works, I don't know how you are doing it by mentioning .comment.length could you be more descriptive about that?"
When you do any jquery selector, an array is returned. so if you do $(".comment") all html nodes with the class ".comment" will be returned to you in a list [obj1, obj2, ..., objn]
When you do $(".comment:hover") you are asking jquery to select you any element with the class "comment" which also have the mouse currently on top of it. Meaning if the length of the list returned by $(".comment:hover") is bigger than zero, then you caught a bubble from a click in a ".comment".
Although either returning false or stoping propagation should also work. (dunno why in your case it is not working, although i didn't look much at the full code)
Edit 2:
i was lazy to read the full code. but when you are setting the click event for the comment, the comment doesn't exist yet. so the new comment you are adding will not be be caught by your click handler. add it inside the ajax callback and it will work :)
Edit 3: one more thing:
you are not getting side effects because the click even you are re-defining only has the the stop propagation, but you should add the stop propagation before returning false in the
$(".keywords_set").on('click', ".comment", function(event) {
because in practice all other comments you have will be proccessing N times the click event that you are adding to be processed multiple times
Since post method is a asynchronous. You are binding $(".comment") before it exist.
moving
$(".comment").click(function(event) {
event.stopPropagation();
});
after
$(".keywords-set").append('<div class="keyword-item"><span class="keyword" id="keyword-'+count+'">'+data[i]+'</span><textarea class="comment" id="comment-'+count+'"></textarea></div>');
should work.

Categories

Resources