Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stop a JQuery UI addClass / removeClass?

I'm using JQuery UI to addClass(), and later to removeClass().

If removeClass() is called before addClass() completes, it queues up and executes later. This is not ideal, I'd rather have the removeClass() execute immediately from the current CSS values.

If I invoke stop() just before add/removeClass(), animation seems permanently 'frozen' at the moment of the stop() call, though the add/removeClass() callback still fires.

Just the JS here:

var obj = $("#obj");
obj.addClass("obj");

$("#add").click(function(){
    //obj.addClass("adder", 2000, "easeInOutCubic", onAdded);
    obj.stop().addClass("adder", 2000, "easeInOutCubic", onAdded);
});

$("#remove").click(function(){
    //obj.removeClass("adder", 2000, "easeInOutCubic", onRemoved);
    obj.stop().removeClass("adder", 2000, "easeInOutCubic", onRemoved);
});

function onAdded () { console.log("added"); }
function onRemoved () { console.log("removed"); }

All the rest here: http://jsfiddle.net/mmstM/42/

This seems like it would be a common issue but haven't found any good info on SO or elsewhere...note this is for JQuery UI, not core.

like image 398
ericsoco Avatar asked Dec 26 '22 18:12

ericsoco


2 Answers

The issue is occurring because even after the class is removed, the interstitial size rules generated for the animation are still present in the element's style property.

We can fix that part trivially by doing:

obj.stop().attr("style", "").removeClass("adder", 2000, "easeInOutCubic", onRemoved);

However, this causes a rather sizeable jump in the animation for the reason that easings for class manipulation don't take element styles into account - the same reason why simply clearing the queue in the first place didn't work. The quick solution to this, I fear, is pretty ugly: using the .animate() method instead, and moving the styles from the class to your jQuery, like so:

$("#add").click(function(){
    //obj.addClass("adder", 2000, "easeInOutCubic", onAdded);
    obj.stop().animate({
        width: '200px',
        height: '80px',
    }, 2000, "easeInOutCubic", onAdded);
});

$("#remove").click(function(){
    //obj.removeClass("adder", 2000, "easeInOutCubic", onRemoved);
    obj.stop().animate({
        width: '40px',
        height: '40px',
    }, 2000, "easeInOutCubic", onRemoved);
});

You can check out the working example here, with a bonus hack to load the width/height values from CSS and stash them in objects to mimic the add/removeClass() syntax.

like image 145
Winfield Trail Avatar answered Dec 29 '22 09:12

Winfield Trail


Here's where I finally ended up:

$.fn.extend({
    animateClass: function (propNames, className, speed, easing, callback) {
        var $store = $("<div>").css('display', 'none').addClass(className);
        $("body").append($store);

        var i=0, len=propNames.length, name, propsMap={};
        for (i; i<len; i++) {
            name = propNames[i];
            propsMap[name] = $store.css(name);
        }
        $store.remove();

        this.stop().animate(propsMap, speed, easing, callback);
    }
});

var $obj = $("#obj");
$("#bigger").click(function(){
    $obj.animateClass(["width", "height"], "bigger", 2000, "easeOutQuad", function () { console.log("BIG"); });
});

​ Working example with multiple states here.

It's not the prettiest thing in that it requires passing a list of css properties to use in the animation, rather than just using everything in the stylesheet, but I couldn't find a way to separate the properties specified in the stylesheet from all the other styles already on the dummy "$store" div created within animateClass().

I'll accept @sudowned's answer as it was the most helpful in leading me here.

like image 42
ericsoco Avatar answered Dec 29 '22 08:12

ericsoco