2

I have this function:

var decreaseBar = function (barElement) {
   insertCSSTransitions(barElement);
   $(barElement).find('.bar').width(0);
}

The insertCSSTransitions(barElement) function, do this:

var insertCSSTransitions = function (barElement) {
      var timeBar = settings.timeBar;
      $(barElement).find('.bar').attr('style', 'transition:width ' + timeBar + 's; -moz-transition:width ' + timeBar + 's; -webkit-transition:width ' + timeBar + 's; -o-transition:width ' + timeBar + 's');
}

What happens is: the $(barElement).find('.bar').width(0); line set the width to 0 before the style of cssTransitions work.

Because, if I modify decreaseBar function to that, it works:

var decreaseBar = function (barElement) {
   insertCSSTransitions(barElement);

   // set a delay of 1 second before set to 0
   setTimeout(function() {
      $(barElement).find('.bar').width(0);
   }, 1000)
}

The code is not synchronized when manipulating the DOM with jQuery?

Acaz Souza
  • 8,311
  • 11
  • 54
  • 97

4 Answers4

0

What is probably happening here, is the style changes made by insertCSSTransitions() are not effective until your release control of the browser, when it does repaint.

You really just need to use setTimeout(..., 1) to ensure that change to the element width are done after the browser has processed the transition style.

ddaa
  • 52,890
  • 7
  • 50
  • 59
  • setTimeout() sometimes works, sometimes don't works. But if a set the width of the element to the same width, it works: $bar.width($bar.width()); – Acaz Souza Apr 28 '12 at 16:41
0

Use a callback ?

var decreaseBar = function (barElement) {
   insertCSSTransitions(barElement, function() {
       $(barElement).find('.bar').width(0);
   });
}

var insertCSSTransitions = function (barElement, callback) {
    var timeBar = settings.timeBar;
    $(barElement).find('.bar').attr('style', 'transition:width ' + timeBar + 's; -moz-transition:width ' + timeBar + 's; -webkit-transition:width ' + timeBar + 's; -o-transition:width ' + timeBar + 's');

    setTimeout(function() {callback.call();}, timebar*1000);
}

That's just a simple example of a callback, it does not wait for CSS transitions to take place, and there shoud be a simple typeof check to see if the callback is a function if it's intended for something else aswell.

EDIT:

As Pointy points out, the callback does'nt do much, other than show how it's done etc. binding the callback to the transition end is probably the way to go, but that property has a bunch of prefixes, solved here with some simple browser detection, but there are libraries out there for checking actual support in the browser.

var insertCSSTransitions = function (barElement, callback) {
    var timeBar = settings.timeBar,
        transitionEnd = "TransitionEnd";
    if ($.browser.webkit) {transitionEnd = "webkitTransitionEnd";}
    else if ($.browser.mozilla) {transitionEnd = "transitionend";}
    else if ($.browser.opera) {transitionEnd = "oTransitionEnd"; }

    $(barElement).find('.bar')
                 .attr('style', 'transition:width ' + timeBar + 's; -moz-transition:width ' + timeBar + 's; -webkit-transition:width ' + timeBar + 's; -o-transition:width ' + timeBar + 's');
                 .on(transitionEnd, function() {
                     callback.call();
    });
}
adeneo
  • 312,895
  • 29
  • 395
  • 388
  • I don't understand the purpose of your callback, the code with your callback is the same as mine without callback, it will happens one after the other. Can you explain a bit more? – Acaz Souza Apr 28 '12 at 16:34
  • Yes, it's exactly like your code with an added callback ? What does the css transitions do, and how long do they take, are they set to one second in CSS ? There's no "wait for css transition" function in JS, so a timeout with the same time as the transition is probably the way to go, but a callback will ensure that the width(0) is only executed after the insert function completes, that is, the JS part completes, the timers set in CSS does not have a JS callback. – adeneo Apr 28 '12 at 16:41
  • When callback.call(); run, the dom in page will not have added the 'style' attribute, because the browser did not redraw. – Acaz Souza Apr 28 '12 at 16:45
  • The style attribute is added almost immediately, but for changing styles you should consider using the css() method. Again, does your transitions have timers set in CSS. – adeneo Apr 28 '12 at 16:53
  • The callback here is pretty much useless unless it's set up as an event handler for the "transitionend" event (or the appropriate browser-specific flavor of that). That'll fire on the element when the transition is finished, which is what the question is really asking. – Pointy Apr 28 '12 at 17:27
0

People talk about asynchronous behavior like it is the holy grail, but getting JS to be synchronous when you want it to can often be the more difficult task. Frame.js (like other flow control libraries such as asnyc and flow.js) was designed to solve this problem. In Frame you would do:

var decreaseBar = function (barElement) {
    Frame(function(next)){
        insertCSSTransitions(barElement);
        next();
    });
    Frame(function(next)){
        $(barElement).find('.bar').width(0);
        next();
    });
    Frame.init();
}
BishopZ
  • 6,269
  • 8
  • 45
  • 58
0

JavaScript is always synchronous unless an AJAX call is being made: When is JavaScript synchronous?.

Your code is not working because you are using a CSS transition which would not be synchronous with JavaScript. JavaScript is "adding" the style transitions to the DOM and once complete, moving on.

I'm not quite sure of the purpose of your functions, so its difficult to come up with a better solution. All-in-all, it is usually bad practice to have JavaScript add hard coded styles like you are doing.

Community
  • 1
  • 1
Andrew Bessa
  • 271
  • 3
  • 9