Bootstrap stateful button not working as expected

I am trying to trigger my boot button to show "loading ..." while some time consuming function is running (fetching data from an external source). Interestingly, the using reference implementation setTimeout

works fine.

It seems to me that the command $(button).button('loading')

is only executed after the function is closed, and setTimeout runs around it, waiting in the background. How can I replicate the result of the setTimeout command with code that actually does something?

Jsfiddle demonstrates my problem.

here is my HTML code:

<button type="button" class="btn btn-warning" id="comb" data-loading-text="Loading..." autocomplete="off" onclick="comb()">Combinations</button>
<button class="btn btn-primary" id="timer" data-loading-text="Loading..." autocomplete="off" onclick="timer()">Set Timeout</button>

      

and here's the javascript:

function combinations(str) {
    var fn = function (active, rest, a) {
        if (!active && !rest) return;
        if (!rest) {
            a.push(active);
        } else {
            fn(active + rest[0], rest.slice(1), a);
            fn(active, rest.slice(1), a);
        }
        return a;
    }
    return fn("", str, []);
}

function comb() {
    var btn = $('#comb').button('loading');
    console.log(combinations('abcdefghijklmnopqrs'));//this is a function that takes a lot of time (~5s) to execute
    btn.button('reset');
}

function timer() {
    var btn = $('#timer').button('loading');
    setTimeout(function () {
        btn.button('reset');
    }, 3000);
}

      

+3


source to share


1 answer


I found a working solution which is a bit of a hack. I will still appreciate better suggestions and / or explanations of what is going on.

Here is the HTML:

<button type="button" class="btn btn-warning" id="comb" data-loading-text="Loading..." autocomplete="off" onclick="comb()">Combinations</button>

      

and here's a working javascript (basically I wrapped my code in a setTimeout command with a very short timeout:

function combinations(str) {
    var fn = function (active, rest, a) {
        if (!active && !rest) return;
        if (!rest) {
            a.push(active);
        } else {
            fn(active + rest[0], rest.slice(1), a);
            fn(active, rest.slice(1), a);
        }
        return a;
    }
    return fn("", str, []);
}

function comb() {
    var btn = $('#comb').button('loading');
    setTimeout(function () {
        console.log(combinations('abcdefghijklmnopqrs'));
        btn.button('reset');
    },100);
}

      

it seems to me that the code I was running was not allowing the javascript (or jQuery) of the boot files to change the state of the button before it finished. The setTimeout command now gives bootstraps javascript time to change the state of the button before my code. I still find this odd and appreciate the explanation.



Edit:

Here is a jsfiddle demonstrating the solution

Edit2: I figured out that 100ms timeout is safer than 10ms because some slower devices / browsers might not recover the page in 10ms. I've updated the code / jsfiddle accordingly.

Edit3: With peterblazejevicz over the Bootstrap Github tracker , I found this elegant solution using a promise:

function comb() {
    var btn = $('#promise').button('loading');
    var request = $.ajax('/');
    request.done(function (data) {
        console.log(combinations('abcdefghijklmnopqrs'));
    });
    request.always(function () {
        btn.button('reset');
    });
}

      

Here is an updated and final jsfiddle demonstrating the solution

+2


source







All Articles