text.length is not defined in Javascript, but text is defined - javascript

I have a code that is supposed to show some text in a typewriter effect, but the console says that length is not defined. I do not know what to do, please help me.
function typeWriter(theX) {
var i = 0;
text = theX;
var leng = text.length;
if (i < leng) {
document.getElementById("theTexts").innerHTML += text.charAt(i);
setTimeout(typeWriter, speed);
}
}
var speed = 50;
typeWriter('Frog-E Console');
var speed = 60;
typeWriter('Booting up');

By calling setTimeout(typeWriter, speed) you are calling typeWriter without passing it anything. This function expect one argument (a string), so you need to pass it :
function typeWriter(theX) {
var i = 0;
text = theX;
var leng = text.length;
if (i < leng) {
document.getElementById("theTexts").innerHTML += text.charAt(i);
setTimeout(typeWriter.bind(this, text), speed);
}
}
var speed = 50;
typeWriter('Frog-E Console');
var speed = 60;
typeWriter('Booting up');
<div id="theTexts"></div>
However this doesn't produce the expected result, you should do something like this :
function typeWriter(text) {
const char = text[0]
theTexts.innerHTML += char;
if (text.length > 1) setTimeout(typeWriter.bind(this, text.substring(1)), speed);
}
var speed = 50;
typeWriter('Frog-E Console');
<div id="theTexts"></div>

Some issues:
When setTimeout calls your typeWriter function, it won't pass it a value for theX so you end up with theX being undefined, so text is undefined, so you get the error.
Your second typeWriter call won't wait until the previous one finishes before starting, so they'll stomp on each other. You can fix that by having typeWriter return a promise it fulfills when it's done.
Your text variable is undeclared, making it what I call an implicit global; we don't need that variable, so let's just ditch it.
Probably best to pass speed in rather than using a global.
Rather than having setTimeout call typeWriter directly, I'd probably use an inner function. See comments:
// Accept both text and speed
function typeWriter(text, speed) {
// Return a promise we'll fulfill when done
return new Promise(resolve => {
// Start out showing nothing
let currentLength = 0;
// Start the process by showing the first character
tick();
function tick() {
// Add one to what we're showing
++currentLength;
// Show it
document.getElementById("theTexts").innerHTML = text.substring(0, currentLength);
// Done?
if (currentLength === text.length) {
// Yes, fulfill the promise
resolve();
} else {
// No, keep going after a delay
setTimeout(tick, speed);
}
}
});
}
// Do the first one, wait for it to finish, then do the next
typeWriter("Frog-E Console", 50)
.then(() => {
return typeWriter("Booting up", 60);
});
<div id="theTexts"></div>

Related

setInterval vs setTimeout which is better to run a loop at a specified speed

var speed = 200,
len = 0;
if (e in know) {
function typing() {
if (len < know[e].length) {
if (len === know[e].length - 1) {
t.innerHTML = know[e];
g = d.getAttribute("data-bottom") ? d.getAttribute("data-bottom") : 0;
if (parseInt(g) < ((d.scrollHeight - t.offsetTop) - p.clientHeight) + 10) d.scrollTo(0, d.scrollHeight);
else alert("new message");
}
len++;
setTimeout(typing, speed);
}
}
typing();
setTimeout vs
setInterval code...
var setIn = setInterval(() => {
if (len < know[e].length) {
if (len === know[e].length - 1) {
clearInterval(setIn);
t.innerHTML = know[e];
g = d.getAttribute("data-bottom") ? d.getAttribute("data-bottom") : 0;
if (parseInt(g) < ((d.scrollHeight - t.offsetTop) - p.clientHeight) + 10) d.scrollTo(0, d.scrollHeight);
else alert("new message");
}
len++;
}
}, speed)
I'm trying to make a reply bot that starts typing after 1 seconds and that will reply back at the speed of the String.length and they both did the same thing but someone once told me using setTimeout is bad practice, but I need them to run that exact way. If there is another work around for it I'm open to all suggestions, Thanks in advance.
You can use async/await to emulate typing and create delays:
//
// Async timeout function
const timeout = ms => new Promise(resolve => setTimeout(resolve, ms));
//
// Bot typing function
const runBot = text => {
// Use promises
return new Promise(async (resolve, reject) => {
// DOM
const div = document.getElementById('text');
// Create chars array
const chars = text.split('');
// Wait 1 sec before typing
await timeout(1000);
// Type text
while(chars.length) {
// Put one char at iteration
div.innerHTML += chars.shift();
// Wait some amount
await timeout(100);
}
// Add new line to the text box
div.innerHTML += '<br>'
// Finish function
return resolve();
});
}
//
// Text typing runner and button controller
const typeText = async text => {
// DOM
const button = document.querySelector('button');
// Disable button
button.disabled = true;
// Run bot and wait till it finishes
await runBot(text);
// Enable button
button.disabled = false;
}
<div id="text" style="padding:10px;border:1px solid #000"></div>
<button onClick="typeText('This is demo text!')">Start bot</button>
You can have multiple approaches:
setInterval
setTimeout
window.requestAnimationFrame
If you need to wait for 1 second, then you must have a setTimeout and inside, I encourage you to use the 3rd option if you want to save performance, but combining setTimeout with setInterval is an available option. The use of them is not a bad practice in general, just in particular cases.

trying to write character by character with delay using setTimeout

I'm trying to make a function to write some text character by character, with some delay, I've expected this would work but it doesn't, after 1000ms the word is written completely, if anyone can help me to fix this or show me a better way to do this it would be really great, here is my code:
const container = document.getElementById('typer')
function typer(text) {
for(let i = 0; i <= text.length; i++) {
setInterval(() => {
container.innerHTML = text.substr(0, i)
}, 1000)
}
}
let x = "hello"
typer(x)
You need to use one setInterval() that runs each 1000ms, and when it finishes the task you need to stop it by using clearInterval, check this link to understand better how to use it.
Try this code:
const container = document.getElementById('typer')
function typer(text) {
const textLength = text.length
let i = 0
const writter = setInterval(() => {
if ( i === textLength ) {
clearInterval(writter)
} else {
container.innerHTML += text[i]
i++
}
}, 1000)
}
let x = "hello"
typer(x)
<p id="typer"></p>
setInterval is already act as a loop. So you can do as simple as below
const container = document.getElementById('typer');
function typer(text) {
let counter = 0, my_delay = setInterval(() => {
if(counter<text.length) container.innerHTML += text[counter++];
else clearInterval(my_delay);
}, 1000);
}
typer("hello");
<p id="typer"></p>
She setInterval function runs after set time, but does not block following code from executing before the timer is done.
try:
let i=0;//counter variable
setInterval(() => {// runs every second.
if (i <= text.length()){//run if the counter below the string length
container.innerHTML = text.substr(0, i);
}
i++;//increment counter
}, 1000)
actually you are doing it partially right but when the for loop runs it set all the setintervals for 1000 millisecond so all of them fired after 1 second that's why we always see hello
what i am done is i put fe for loop inside setinterval and added a setTimeout and each timeout will fire only after 500 millisecond after than the previous one,
the const sum = (text.length * (text.length +1)) / 2; is used to find sum of all i values which is used inside the for loop then only we will be able to fire setInterval only after the hello completed hope this helps you
but actually there is a simple css way is there you must try that.
https://css-tricks.com/snippets/css/typewriter-effect/
const container = document.getElementById('typer')
function typer(text) {
const sum = (text.length * (text.length +1)) / 2;
setInterval(()=>{
for(let i = 0; i <= text.length; i++) {
setTimeout(() => {
container.innerHTML = text.substr(0, i)
}, 500+500*i)
}
},sum*500)
}
let x = "hello"
typer(x)
<span id="typer"></span>

For Loop running infinitely

So Ive been fighting with this for loop for a day and a half now, when I get it to actually print it goes infinitely, even when the if statement (logCount === 10) is satisfied...
Not too sure what to try anymore, really feel like its far simpler than what I'm trying....
Any attempts at a solution are appreciated..
var timers = [];
var log = (function(outputFunc) {
var counter = 0;
var callerLog = [];
var dateTime = [];
//assigning current Date to a variable to print for logs
let logDate = new Date();
return function(timer) {
for (var logCount = 0; logCount <= 10; logCount++) {
//printing data without using printFunc, as specified
document.getElementById("output").innerHTML += logCount + " " + timer + " " + logDate + "<br>";
//TODO: add after for loop is resolved.
if (logCount >= 10) {
clearInterval(timer1);
clearInterval(timer2);
clearInterval(timer3);
document.getElementById("output").innerHTML += "<br><br/> Logging stopped.";
}
}
}
})(printFunc);
function printFunc(output) {
document.write(output + "<br>");
}
function startMeUp() {
// add each of the timer references to the timers array
// as part of invoking the log function following each interval
timers.push(setInterval("log('Timer1')", 1000));
timers.push(setInterval("log('Timer2')", 1200));
timers.push(setInterval("log('Timer3')", 1700));
}
I'm guessing this is what you're trying to achieve:
function printFunc(output) {
// Replaced with console.log for my own convenience
console.log(output);
}
// Not really a factory, just a curry of the outputFunc
function loggerFactory(outputFunc) {
return function startLogger(name, interval) {
// Variables to keep track of the iterations and a reference to the interval to cancel
let logCount = 0;
let intervalRef;
function tick() {
// On each tick, check if we're done
// If yes, clear the interval and do the last output
// If no, do some output and increment the iterator
// Once the next tick passes we'll check again
// If you were using setTimeout instead you would have to requeue the tick here
if (logCount >= 10) {
clearInterval(intervalRef);
outputFunc('Done ' + name);
} else {
outputFunc(logCount + " " + name);
logCount += 1;
}
}
// Start it of
intervalRef = setInterval(tick, interval);
}
}
const logger = loggerFactory(printFunc);
function startMeUp() {
console.log('Starting');
logger('Log1', 1000);
logger('Log2', 1200);
logger('Log3', 1700);
}
startMeUp();
Some notes:
You could push the intervalRefs into an array but I find it nicer to encapsulate that work within the same logger, since it should only clean up itself anyway.
When working with intervals (or asynchronous code in general) for loops are usually not what you're looking for. For loops are inherently synchronous, all iterations will be run directly after each other, without space for anything else. What you were looking for was a way to run multiple asynchronous "tracks" at the same time. You could use a for loop to start these "tracks", such as:
for () {
logger('Log' + i, 1000 * i);
}
But the key lies in that the logger quickly sets up the interval function and then returns. That way your for loop can quickly "schedule" the tasks but the logger runs the iterations internally asynchronously by using setInterval or setTimeout.

Changing speed of console.log in loop

I want to slow down console.log in my loop
// function update to actualize value
function update() {
requestAnimationFrame(update);
analyser.getByteFrequencyData(data);
var count=0;
for (var i=data.length; i--;) {
count+=data[i];
if(count >= 1) {
console.log(data);
}
};
}
For example, show one console.log immediatly, and then, each .5s
How can we do that ?
(maybe with setTimeout() but I don't want start delay)
The simplest way would be to introduce a timeout before running the update again each time...
// function update to actualize value
function update() {
analyser.getByteFrequencyData(data);
var count=0;
for (var i=data.length; i--;) {
count+=data[i];
if(count >= 1) {
console.log(data);
}
};
requestAnimationFrame(function() {
setTimeout(update, 5000);
});
}
I used setTimeout() in preference over setInterval() as doing it this way (as well as moving the call to the end of the function) will make sure everything is completed, before starting the 5 second pause. It ensures there's no overlap, should the preceeding code take longer than 5 seconds.
First create a variable to store the time of the last console.log. Next, update that variable each time you console.log a value. Finally, add a check for the threshold.
var lastOutput = 0; // Setting this to 0 initially will ensure it runs immediately
var outputThreshold = 500; // in milliseconds
function update() {
requestAnimationFrame(update);
analyser.getByteFrequencyData(data);
if (new Date().valueOf() - lastOutput > outputThreshold) {
// threshold met, output and update
var count=0;
for (var i=data.length; i--;) {
count+=data[i];
if(count >= 1) {
console.log(data);
}
};
lastOutput = new Date().valueOf();
}
}
update(); // fire first call to update, after that requestAnimationFrame() will handle future calls
If you want the time delay inside the for loop, you'd do this:
function update() {
requestAnimationFrame(update);
analyser.getByteFrequencyData(data);
var i = data.length - 1, count = 0;
function logger() {
count += data[i];
if (count >= 1)
console.log(data);
if (i-- >= 0)
setTimeout(logger, 500);
}
logger();
}
Now, things are going to be pretty messy because you're also using requestAnimationFrame() to schedule another iteration of the whole thing; that really won't make sense anymore. You'll probably want to have that wait until the logging process is done:
function update() {
analyser.getByteFrequencyData(data);
var i = data.length - 1, count = 0;
function logger() {
count += data[i];
if (count >= 1)
console.log(data);
if (i-- >= 0)
setTimeout(logger, 500);
else
requestAnimationFrame(update);
}
logger();
}

How to create pause or delay in FOR loop?

I am working on a website, where I need to create a pause or delay.
So please tell me How to create pause or delay in for loop in javascript or jQuery
This is a test example
var s = document.getElementById("div1");
for (i = 0; i < 10; i++) {
s.innerHTML = s.innerHTML + i.toString();
//create a pause of 2 seconds.
}
You can't use a delay in the function, because then the change that you do to the element would not show up until you exit the function.
Use the setTimeout to run pieces of code at a later time:
var s = document.getElementById("div1");
for (i = 0; i < 10; i++) {
// create a closure to preserve the value of "i"
(function(i){
window.setTimeout(function(){
s.innerHTML = s.innerHTML + i.toString();
}, i * 2000);
}(i));
}
var wonderfulFunction = function(i) {
var s = document.getElementById("div1"); //you could pass this element as a parameter as well
i = i || 0;
if(i < 10) {
s.innerHTML = s.innerHTML + i.toString();
i++;
//create a pause of 2 seconds.
setTimeout(function() { wonderfulFunction(i) }, 2000);
}
}
//first call
wonderfulFunction(); //or wonderfulFunction(0);
You can't pause javascript code, the whole language is made to work with events, the solution I provided let's you execute the function with some delay, but the execution never stops.
I tried all one, but I think this code is better one, it is very simple code.
var s = document.getElementById("div1");
var i = 0;
setInterval(function () {s.innerHTML = s.innerHTML + i.toString(); i++;}, 2000);
if you want to create pause or delay in FOR loop,the only real method is
while (true) {
if( new Date()-startTime >= 2000) {
break;
}
}
the startTime is the time before you run the while
but this method will cause the browsers become very slow
It is impossible to directly pause a Javascript function within a for loop then later resume at that point.
This is how you should do it
var i = 0;
setTimeout(function() {
s.innerHTML = s.innerHTML + i.toString();
i++;
},2000);
The following code is an example of pseudo-multithreading that you can do in JS, it's roughly an example of how you can delay each iteration of a loop:
var counter = 0;
// A single iteration of your loop
// log the current value of counter as an example
// then wait before doing the next iteration
function printCounter() {
console.log(counter);
counter++;
if (counter < 10)
setTimeout(printCounter, 1000);
}
// Start the loop
printCounter();
While several of the other answers would work, I find the code to be less elegant. The Frame.js library was designed to solve this problem exactly. Using Frame you could do it like this:
var s = document.getElementById("div1");
for (i = 0; i < 10; i++) {
Frame(2000, function(callback){ // each iteration would pause by 2 secs
s.innerHTML = s.innerHTML + i.toString();
callback();
});
}
Frame.start();
In this case, it is nearly the same as the examples that use setTimeout, but Frame offers a lot of advantages, especially if the you are trying to do multiple or nested timeouts, or have a larger JS application that the timeouts need to work within.
I am executing a function where I need access to the outside object properties. So, the closure in Guffa solution doesn't work for me. I found a variation of nicosantangelo solution by simply wrapping the setTimeout in an if statement so it doesn't run forever.
var i = 0;
function test(){
rootObj.arrayOfObj[i].someFunction();
i++;
if( i < rootObj.arrayOfObj.length ){
setTimeout(test, 50 ); //50ms delay
}
}
test();
The way I found was to simply use setInterval() to loop instead. Here's my code example :
var i = 0;
var inte = setInterval(() => {
doSomething();
if (i == 9) clearInterval(inte);
i++;
}, 1000);
function doSomething() {
console.log(i);
};
This loops from 0 to 9 waiting 1 second in between each iteration.
Output :
0 1 2 3 4 5 6 7 8 9
It is not possible to pause a loop. However you can delay the execution of code fragments with the setTimeout() function. It would not make a lot of sense to pause the entire execution anyway.
I am using while loop and check the pause variable to check the user pause/resume the code.
var pause = false;
(async () => {
for (let index = 0; index < 1000; index++) {
while (pause) {
await new Promise((res) => setTimeout(res, 1000));
console.log("waiting");
}
await new Promise((res) => setTimeout(res, 1000));
console.log(index);
}
})();
const pausefunc = async () => {
pause = true;
};
const playfunc = () => {
pause = false;
};
<button onclick="playfunc()">Play</button>
<button onclick="pausefunc()">Pause</button>
I used a do...while loop to put a delay in my code for a modal dialog that was closing too quickly.
your stuff....
var tNow = Date.now();
var dateDiff = 0;
do {
dateDiff = Date.now() - tNow;
} while (dateDiff < 1000); //milliseconds - 2000 = 2 seconds
your stuff....

Categories

Resources