1

I'm trying to make simple autotype with Javascript. My problem is the autotype is cannot run sequentially if i call it from view (.cshtml).

My cshtml like this:

<script type="text/javascript" src="@Url.Content("/Scripts/autotype.js")"></script>

@foreach (var temp in @Model)
{
    <script>
        auto_type("ABCDEFG", 0)
    </script>
}

<div id="divauto"></div>

and it's autotype.js :

function auto_type(wrt, i) {

    wrt = wrt.split('');
    var delay = 100;
    while (i < wrt.length) {
        setTimeout(function () {
            $('#divauto').append(wrt.shift())
        }, delay * i)
        i++;
    }
}

From these codes, the output will be like "AAABBBCCCDDDEEEFFFGGG" but i need the output like: "ABCDEFGABCDEFGABCDEFG"

satisfy
  • 23
  • 4
  • The output is "ABCDEFG", not "AAABBBCCC...". – Cᴏʀʏ Dec 01 '14 at 19:24
  • I get this `AAAAABBBBBCCCCCDDDDDEEEEE` in my repro. – Jason Evans Dec 01 '14 at 19:28
  • I would really question if you need to use Razor to output script in a loop like this. It's almost always better to leave script for client-side behavior, and use Razor for server-side behavior. You can certain use Razor to provide data for your client-side code to act upon, but trying to mix the two like this is asking for trouble. – Heretic Monkey Dec 01 '14 at 22:57

3 Answers3

0

I think what you are looking for is a typewriter, or teletype effect, where the text is written out like a typewriter?

In that case, check out this SO question, as it looks like it will provide what you need.

Typewriter Effect with jQuery

Community
  • 1
  • 1
Jason Evans
  • 28,906
  • 14
  • 90
  • 154
0

The issue is that i is getting set to 7 at the end of your loop, which occurs before the first instance of it being called. Try something like this:

function auto_type(wrt) {
    wrt = wrt.split('');
    if (wrt.length > 0) {
        var delay = 100;
        type_loop(wrt, delay);    
    }
}

function type_loop(wrt, delay) {
    var myTimeout = setTimeout(function () {
        clearTimeout(myTimeout);
        $('#divauto').text($('#divauto').text() + wrt.shift());
        if (wrt.length > 0) {
            type_loop(wrt, delay);
        }
    }, delay);
}

$(document).ready(function() {
    auto_type("ABCDEFG", 0);
});

This method is called tail recursion in case you're curious.

charles
  • 547
  • 1
  • 3
  • 11
0

You can do this with jQuery deferreds. In this case I had to use two recursive functions since you need flow control for both the iteration through the viewItems list as well as for kicking off setInterval() to update #divAuto for each character.

As an example of how promises are used here to add control, in autoType() you get a promise returned from the new autoTypeUtil(). When the promise is resolved within autoTypeUtil() you call autoType() again with the remaining list. This gives you flow control for the input items while still running asynchronously.

You may check out the fiddle for a working example.

function timeString(arr, timeFactor, deferred) {
    if (arr.length === 0) { deferred.resolve(); }

    var ch = arr.shift();
    var deferredInternal = new $.Deferred();
    var promise = deferredInternal.promise();
    var delay = 100;

    setTimeout(function () {
        $('#divauto').append(ch);
        deferredInternal.resolve("done");
    }, delay * timeFactor)

    promise.done(function() { 
        timeString(arr, timeFactor, deferred); 
    });
}

function autoTypeUtil(inputString, timeFactor) {
    var deferredTimeString = new $.Deferred();
    var deferredInternal = new $.Deferred();
    var promiseTimeString = deferredTimeString.promise();

    inputString = inputString.split('');
    timeString(inputString, timeFactor, deferredTimeString);

    promiseTimeString.then(function() {
        deferredInternal.resolve()
    });
    return deferredInternal.promise();
}

function autoType(arr, timeFactor) {
    if (arr.length === 0) { return; }

    var promise = autoTypeUtil(arr.shift(), timeFactor);

    promise.done(function() {
        autoType(arr, timeFactor);
    });
}

var viewItems = ["I", "love", "jQuery", "promises"];
autoType(viewItems, 1);
anthonyserious
  • 1,758
  • 17
  • 15