jQuery .when().done() not working

你。 提交于 2019-12-12 08:21:38

问题


I'd like to start by saying I'm new to jQuery and I suspect I'm just doing something stupid, so hopefully this will be very simple for someone.

I'm trying to add a sliding mobile sub-menu to my website. I want an accordian effect whereby if I click one parent link, it's child sub-menu opens and all other sub-menus close. The problem is timing - the child sub-menu opens and then is closed again by the resetting of all sub-menus. I presume the answer is to use deferreds but everything I've tried has failed. This is the (currently not working) code:

function ResetMenu(){
    jQuery(".mobile-menu").find(".sub-menu").slideUp(100);
    jQuery(".mobile-menu").find(".menu-item-has-child").removeClass("open");
};

function OpenSubmenu(){
    jQuery(this).next("ul").slideDown(100);
    jQuery(this).parent().addClass("open");
};

jQuery("li.menu-item-has-children > a").click(function(){

    if(jQuery(this).parent().hasClass("open")){
        jQuery(".mobile-menu").find(".sub-menu").slideUp(100);
        jQuery(this).parent().removeClass("open");
    } else {
        jQuery.when(ResetMenu()).done(OpenSubmenu());
    }
    return false;
});

Any help would be greatly appreciated. Thank you!

Ronel


回答1:


This is a common mistake in how to use jQuery.when().

jQuery.when() requires promises as arguments. It does not have magical powers to know when functions you pass it are somehow done. Those functions MUST return promises that are resolved or rejected when the underlying code is done and you can then pass those promises to jQuery.when().

Your ResetMenu() function doesn't return anything so therefore, your jQuery.when() doesn't wait for anything. It executes the .then() handler immediately (which looks like that is not what you want).

So, in this line:

jQuery.when(ResetMenu()).done(OpenSubmenu());

ResetMenu() MUST return a promise for jQuery.when() to know when it is done.

You could fix ResetMenu() to work that way by doing this:

function ResetMenu(){
    return jQuery(".mobile-menu").find(".sub-menu").slideUp(100).promise().then(function() {
        // remove this class when the animation has completed
        jQuery(".mobile-menu").find(".menu-item-has-child").removeClass("open");
    });
};

And, then further, you need to change how you pass a function to .done() to this which both makes it just a function reference that can be executed LATER and binds a appropriate this value to it:

jQuery.when(ResetMenu()).done(OpenSubmenu.bind(this));

Note, the .bind(this) assumes that this is the appropriate value. You can pass whatever value is the correct value there and that will become the this value inside of OpenSubmenu() when it is executed.




回答2:


When you pass a non promise object to $.when() the callbacks passed to done() is invoked immediately, in your case when ResetMenu is not returning anything the OpenSubmenu is called immediately, there is another problem also - you should not invoke OpenSubmenu directly(by adding ()), you need to pass a function reference to done()

function ResetMenu() {
    jQuery(".mobile-menu").find(".menu-item-has-child").removeClass("open");
    return jQuery(".mobile-menu").find(".sub-menu").slideUp(100).promise();

};

function OpenSubmenu() {
    jQuery(this).next("ul").slideDown(100);
    jQuery(this).parent().addClass("open");
};

jQuery("li.menu-item-has-children > a").click(function () {

    if (jQuery(this).parent().hasClass("open")) {
        jQuery(".mobile-menu").find(".sub-menu").slideUp(100);
        jQuery(this).parent().removeClass("open");
    } else {
        jQuery.when(ResetMenu()).done(OpenSubmenu);
    }
    return false;
});


来源:https://stackoverflow.com/questions/28575501/jquery-when-done-not-working

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!