sonu sasankan
sonu sasankan

Reputation: 79

jquery callback of addClass execute twice

I have given an append function on a callback of addClass to an element. But that function executes twice. why?

//append new stage function---------//
var newNode;

function appendNewStage() {
  var parent = $('.ci-journey-interactions-canvas__row');
  var newStage = `<ul class="ci-journey-interactions-canvas__journey-list stage">
    <li>
      <span class="ci-journey-interactions-box__droppable-
element ci-droppable"></span>
    </li>
  </ul>`;

  var position = $(parent).find("ul:last").position();
  var width = $(parent).find("ul:last").outerWidth();
  newNode = $(newStage).appendTo(parent);
  if (remain.length > 0) {
    newNode.html(remain);
  }
  $(newNode).find('li:first-child').addClass('first-child');
  newNode.css({
    "position": "absolute",
    "left": (width + position.left - 89),
    "top": (position.top + 140)
  });
  var dropArea = $(newNode).find('.ci-droppable');
  dropArea.droppable();
  dropArea.droppable({
    accept: ".ci-draggable",
  });
  elementSelect(newNode);
};

//staging  function//
function staged(event) {
  $(".stage:last-child").addClass('staged', function(event) {
    appendNewStage();
  });
  $(".stage").find("li:not('.ui-selected')").remove();
  $(".stage").find("li.blank").remove();
  $(".stage").removeClass("stage");
}

I triggering the staged function on a button click event. when I give an alert on staged callback it run two times

Upvotes: 0

Views: 124

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074385

In general, jQuery's animation callbacks happen per-element. So if $(".stage:last-child") matches two elements (because there are two .stage elements that are the last child in their parent), you'll get two callbacks — one for each element. From the [animate documentation](

Callback Functions

If supplied, the start, step, progress, complete, done, fail, and always callbacks are called on a per-element basis... If multiple elements are animated, the callback is executed once per matched element, not once for the animation as a whole. Use the .promise() method to obtain a promise to which you can attach callbacks that fire once for an animated set of any size, including zero elements.

So assuming what you're using plays nicely with jQuery's animation internals (the jQuery UI one does):

$(".stage:last-child").addClass('staged').promise().then(appendNewStage);

Example using jQuery UI's addClass:

$(".stage:last-child").addClass("staged", function() {
  console.log("Callback for " + this.id);
})
.promise().then(function() {
  console.log("All done");
});
.staged {
  color: blue;
}
<div>
  <div id="first" class="stage">
    testing 1 2 3
  </div>
</div>
<div>
  <div id="second" class="stage">
    testing 9 8 7
  </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

(I assume you're using jQuery UI's addClass addition or something else that adds animation to addClass. jQuery on its own doesn't animate it, so doesn't have a callback.)

Upvotes: 1

Related Questions