Reputation: 11039
I have tried creating an animated typing/erasing effect. It does type, but when it finishes the first sentence, it doesn't do anything else. It seems it is stuck in the very first if statement.
window.onload = () => {
const sentences = ['Who am I?', 'Who are you?', 'Who are we?'];
const input = document.getElementsByName('q')[0];
let sentence = 0;
let character = 0;
let typing = true;
(function typing() {
if (character === sentences[sentence].length - 1) {
typing = false;
} else if (character === 0) {
if (sentence < sentences.length - 1) {
sentence++;
} else {
sentence = 0
}
typing = true;
}
if (typing) {
character++;
} else {
character--;
}
input.placeholder = sentences[sentence].substring(0, character);
setTimeout(typing, ~~(Math.random() * (300 - 60 + 1) + 60));
})();
};
Upvotes: 1
Views: 153
Reputation: 3683
Take a look at this approach using Promises
and some Array
functions:
var sentences = ['Who am I?', 'Who are you?', 'Who are we?'],
input = document.getElementsByName('q')[0];
// Waits for a time passed as parameter
let wait = ms =>new Promise( resolve => setTimeout(resolve, ms)),
isPaused,
// Function that returns a Promise that remove ONE character from the placeholder
removeOne = ()=> new Promise( (rs, rj) =>{
setTimeout( ()=>{
input.placeholder = input
.placeholder
.substring(0, input.placeholder.length - 1);
rs();
}, ~~( Math.random() * (300 - 60 + 1) + 60) );
}),
// Function that takes a char and return a Promise that add the char to placeholder
addOne = char => new Promise( (rs, rj) =>{
if (isPaused) return rj('Paused');
setTimeout( ()=>{
input.placeholder += char;
rs();
}, ~~(Math.random() * (300 - 60 + 1) + 60));
}),
// Cleans the placeholder char by char sequentially
// as random as typed.
clean = ()=> Array.apply(null, { length : input.placeholder.length + 1 })
.reduce( chain => chain.then(removeOne), Promise.resolve() ),
// Type one sentence into the placeholder sequentially
// then wait, then clean then wait
type = sent => sent.split('')
.reduce( (chain, char)=> chain.then( addOne.bind(null, char) ), Promise.resolve() )
.then(wait.bind(null, 1000))
.then(clean)
.then(wait.bind(null, 500)),
//.catch(Promise.reject),
// Execute an infine loop that type each sentence
// sequentially
loop = ()=>{
isPaused = false;
return sentences.reduce( (chain, sent)=> chain
.then( ()=> type(sent) )
.catch( Promise.reject )
, Promise.resolve() )
.then(loop);
},
// Change the boolean to true, this will cause a rejection in addOne Promise
// then will call clean to clean the placeholder.
pause = ()=> {
isPaused = true;
return clean();
};
// Execute the loop at first time
loop();
// Pause the execution in 20 seconds
// As this is a promise you can also listen for pause to complete
// i.e. pause().then(wait.bind(null, 1000)).then(loop);
setTimeout(pause, 20000);
<input type = "text" name= "q">
Upvotes: 0
Reputation: 13211
You override your function in the function itself, setTimeout
receives a boolean as first argument
For function names its better to use verbs like typeSentence
For boolean its good to use questions like isTyping
Upvotes: 1