views:

896

answers:

3

I am trying to make a numerical value, say 5000, quickly change to another value, say 4000, using JQuery. Right now I do this fine using:

mod(".class",4000,"add");

function mod(id,value,type){
    var numb = $(id).html();
    var current_value = parseInt(numb);
    do {
        if(type == "add")
            increment(id);
        else
            decrement(id);
        current_value = parseInt(numb);
    }while(current_value != value);

    function decrement(id){
        $(id).html(current_value-1);
    }

    function increment(id){
        $(id).html(current_value+1);
    }
}

I know it's probably not the best way to go about it but what I need for it to do is countdown (or up) the numbers very quickly from the current value to the set value. What I intended with this method was to have a delay using setInterval or setTimeout however that makes the whole script fail pretty badly.

Any advice is appreciated, however I would prefer not to use large plugins for this seemingly simple task.

+2  A: 

When I ran the code you supplied, I was caught in an infinite loop. At the end of the do loop, you have

current_value = parseInt(numb);

but the value of numb is only set at the beginning of the function, so it goes on forever. If you change that to

current_value = parseInt($(id).html());

then it works fine. Except that it appears to happen instantly.

I hacked up a method to achieve the animation using timeouts that seems to work fairly well, but as I'm still fairly new to javascript I don't know if there is a more efficient approach or not. Just tweak the second param passed to setTimeout to get the desired speed. And if you want to change the increment/decrement value, just change the deceleration of dir.

function mod2(id, value) {
    var numb = $(id).html();
    var current_value = parseInt(numb);

    // determine direction to go
    var dir = 1;
    if (current_value - value > 0) {
     dir *= -1;
    }
    getThere(id, current_value, value, dir);
}

function getThere(id, current_value, target_value, dir) {
    current_value += dir;
    $(id).html(current_value);
    if (current_value != target_value) {
     setTimeout("getThere('"+id+"',"+current_value+","+target_value+","+dir+")", 10);
    }
}
thorncp
+3  A: 

What you are doing here is updating the DOM many times in quick succession. As a result, the browser will wait until you've done all your changes, and only then will it re-draw the page. So, you won't get to see any visual change until the number goes all the way down to 4000.

Yes, you do need to use a setTimeout or setInterval / clearInterval. Or, for clarity of code, you could use the jQuery "wait" plugin:

// (code to get new value goes here)

$('.class').wait(100, function(){
    $(this).text(newValue);
});

Instead of html(), I've used text(), since it looks like you don't need to change any HTML structure.

Premasagar
+1  A: 

I like thorn's approach with setTimeout, but I would condense it down to 2 functions and start it after window load to ensure the page has loaded prior to updating the counter:

var counterTimeout = 10; // time between increments in ms
$(window).load(function() {
    mod('class', 'add', 4000);
});

function mod(class, type, targetVal) {
    var $class = $(class);
    var numb = parseInt($class.html());
    numb = (type == 'add') ? numb + 1 : numb - 1;
    $class.html(numb);
    if (numb != targetVal) {
        setTimeout('mod("' + class + '","' + type + '",' + targetVal)', counterTimeout);
    }
}

The base case isn't satisfied in the event $class.html() starts with a value higher than the targetVal in the case of 'add' or lower than the targetVal in the other case. You would have to ensure this does not happen prior to making the function call.

cballou