0

I'm building a practice project from scratch. It's a vanilla javascript plugin that allows you to create an "animated typing effect".

Code pen with the demo so far: https://codepen.io/juan-sebasti-n-bonnett/pen/oNoVGad

const TypingEffect = { options: { parallel: false, showCursor: true, removeOtherCursors: true, removeCursorAfter: 0, cursorColor: '#000', cursorBG: '#000', cursorWeight: '0px', cursorInterval: 400, typingSpeed: 80, cursorChar: '|', eraseSpeed: 50, showcaseEraseDelay: 3000, }, type: function(_elem, _str) { let elem; if (typeof(_elem) != 'string' && typeof(_elem) != 'object') return; if (typeof(_elem) == 'string') { console.log('we have to query a selector'); elem = document.querySelector(_elem); console.log(elem); } if (this.options.showCursor) elem = this.cursor(elem); let typingSpeed = parseInt(this.options.typingSpeed); let str = _str || elem.innerHTML; let strArray = str.split(''); let currentString = ''; let i = 0; return new Promise((resolve, reject) => { let typing = setInterval(() => { if (i < strArray.length) { currentString = currentString + strArray[i]; elem.innerHTML = currentString; i++; } else { clearInterval(typing); resolve(elem); } }, typingSpeed); }); }, typeMultiple: function(elements) { let promise = Promise.resolve(); elements.forEach(element => { promise = promise.then(() => { return this.type(element); }); }); promise.then(() => { if (parseInt(this.options.removeCursorAfter) > 0) { setTimeout(() => { this.removeCursor(); }, this.options.removeCursorAfter); } }); return promise; }, typeSelector: function(selector) { let elements = document.querySelectorAll(selector); if (this.options.parallel) { elements.forEach(element => { this.type(element); });; } else { return this.typeMultiple(elements); } }, erase: function(elem) { if (typeof(elem) != 'string' && typeof(elem) != 'object') return; if (typeof(elem) == 'string') { elem = document.querySelector(elem); } let str = elem.innerHTML; return new Promise((resolve, reject) => { let erasing = setInterval(() => { if (str.length > 0) { str = str.slice(0, -1); elem.innerHTML = str; } else { clearInterval(erasing); resolve(elem); } }, parseInt(this.options.eraseSpeed)); }); }, cursor: function(elem) { if (this.options.removeOtherCursors) this.removeCursor(); let string = elem.innerHTML; let cursorInterval = parseInt(this.options.cursorInterval); let cursorVisible = true; const cursorNode = document.createElement('span'); const cursor = document.createTextNode(this.options.cursorChar); const stringNode = document.createElement('span'); const stringContent = document.createTextNode(string); elem.innerHTML = ''; stringNode.appendChild(stringContent); elem.appendChild(stringNode); stringNode.id = 'typing-string-content'; cursorNode.appendChild(cursor); elem.appendChild(cursorNode); cursorNode.id = 'typing-cursor'; cursorNode.style.paddingLeft = this.options.cursorWeight; cursorNode.style.backgroundColor = this.options.cursorBG; cursorNode.style.color = this.options.cursorColor; setInterval(() => { if (cursorVisible) { cursorNode.style.opacity = 0; cursorVisible = false; } else { cursorNode.style.opacity = 1; cursorVisible = true; } }, cursorInterval); return stringNode; }, removeCursor: function(_cursor) { let cursor = _cursor || document.getElementById('typing-cursor'); if (cursor) cursor.remove(); }, init: function(_options) { if (_options) Object.assign(this.options, _options); }, } /* Typing Effect usage */ let newOptions = { typingSpeed: 120, eraseSpeed: 120, cursorColor: 'rgb(14, 231, 32)', } TypingEffect.init(newOptions); let string = `Hello! I'm using the type() function`; let done = TypingEffect.type('#type-here', string); done.then((elem) => { if (elem) { let notice = document.getElementById('notice'); notice.innerHTML = `Done Typing! But I will be erased after 6 seconds`; setTimeout(() => { let doneErasing = TypingEffect.erase(elem); doneErasing.then((elem) => { notice.innerHTML = `Done erasing!`; }); }, 6000); } });
* { box-sizing: border-box; } body { background-color: #000; } .container { width: 100%; /*display: flex; align-items: center; justify-content: center;*/ } .typing-effect { font-family: 'Consolas'; color: rgb(14, 231, 32); font-size: 22px; } #notice { color: white; font-size: 22px; font-family: sans-serif; padding-top: 54px; }
<div class="container"> <p id="type-here" class="typing-effect"></p> </div> <div id="notice"></div>

I already have the mechanism that allows me to type a string inside an HTML element and another one that allows me to erase it. But my goal now is to be able to create a third function that receives an array of sentences and it starts typing a sentence, then waits a bit, erases it and then types the other sentence until the end of the array, then start over from index 0.

The code right now uses Promises and the logic goes as follows:

function type(selector, string) { // returns a promise that resolves // when we're done typing the string // and returns the element that contains the text (the selector) } function erase(selector) { // returns a promise that resolves when // we're done erasing the whole node's content // and returns the element that is now empty (the selector) } 

Now, I'm still new to this concept of promises, and although they're easy to understand when they're explained with APIs and so, it gets hard to manipulate them in chain, mostly when you need something like this:

function typeMultipleSentences(selector, arrayOfSentences) { // LOOP: // types the first sentence of the array // when its done typing, waits for a couple seconds and then erases it // when it's done erasing, does the same with the next sentence in the array } //Usage typeMultipleSentences('#type-here', ['Hello World', 'Hola Mundo', 'Hallo Welt']); 

Other functions inside the object I shared are just helpers and they do other kind of stuff with this effect, like adding the cursor to the end, typing paragraphs one after the other, etc. But those are not important, I only need to know how to achieve this kind of "Promise Chaining Delaying thing"

4
  • use a for loop in an async function and await the results Commented Mar 6, 2022 at 5:28
  • That's what I've been trying, but again, I'm new to the Promises concept and still getting a lot of trouble with that. Commented Mar 6, 2022 at 5:30
  • That's what I've been trying - where? Commented Mar 6, 2022 at 5:34
  • @Bravo I took the time to explain my code, how it works now and my intentions, I just need a bit of guiding, that's all Commented Mar 6, 2022 at 5:40

1 Answer 1

1

It sounds like you need a little delay function, and you can do this by returning a promise that resolves after a set time, and then using async/await to simplify the code so you're not "chaining" anything, just waiting.

function delay(time) { return new Promise(res => { setTimeout(() => res(), time); }); } async function main(data) { for (const el of data) { console.log(`Writing ${el}`); await delay(2000); console.log(`Erasing ${el}`); await delay(2000); } console.log('Done!'); } const data = ['Hello World', 'Hola Mundo', 'Hallo Welt']; main(data);

Sign up to request clarification or add additional context in comments.

5 Comments

Gonna try something based on your answer, although I don't want to depend on timers, but all the promises actually being fulfilled before continuing... I'll let you know
"my goal now is to be able to create a third function that receives an array of sentences and it starts typing a sentence, then waits a bit, erases it and then types the other sentence". You maybe thinking about promises the wrong way.
yep, I might be... I think you gave me an Idea, i'll let you know if it works. I apologize, I'm still trying to get my head around all these promises chaining things
Ah, mate, it's fine. You may find this post useful too. Same topic.
Man, I had to analyze your answer a couple times and I realised I missunderstood the first time I saw it, now I know where you were going with it, made the proper changes to fit that to my program and now it works as intended. Just a bit of tweaking that I can do by myself. I wanna thank you from the bottom of my heart

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.