I'm trying to execute an async function twice one after another. But the problem is that they are executing together. But, what I want is that the 2nd execution must be start after the execution of first is completed.
PS, there are many questions on SO, with same title, like this one JavaScript: execute async function one by one. But none of them solve my problem.
Please, check the Fiddle
$(document).ready(function() {
function typeWriter(element, msg, speed, index = 0) {
if (index < msg.length) {
$(element).html($(element).html() + msg.charAt(index++));
setTimeout(function() {
typeWriter(element, msg, speed, index);
}, speed);
}
}
$('.intro').fadeIn(function() {
const greet = new Promise(function(resolve, reject) {
typeWriter('#sayHello', "Hello !!", 200);
resolve();
});
greet.then(function() {
typeWriter('#myName', "I'm learning programming", 200);
});
});
});
.intro {
text-align: center;
display: none;
font-family: 'Amaranth', sans-serif;
}
.cursor {
display: inline-block;
width: 10px;
height: inherit !important;
}
.cursor>span {
display: inline-block;
position: relative;
top: 2px;
width: 3px;
height: 26px;
margin: 0 0 0 0px;
background-color: #000;
animation: blink 1s step-end infinite;
}
#keyframes blink {
from,
to {
opacity: 1;
}
50% {
opacity: 0;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="intro">
<h1 class="title"><span id="sayHello"></span><span class="cursor"><span></span></span>
</h1>
<h1 class="title"><span id="myName"></span><span class="cursor"><span></span></span>
</h1>
</div>
Here, I'm trying to print two lines of text inside two different <h1> tags. For that, I'm calling function typeWriter(...) twice, once for each <h1>. I'm trying to print two lines, one after completion of previous one, i.e., print Hello !! in first call and after it finishes then print I'm Learning Programming in second line, but it is not happening. The problem is they are executing together.
On further searching for the solution, I found this question JavaScript: execute async function one by one, and follow answer given by #DavidHedlund, but It doesn't work for me. Sorry, if I'm making any mistake.
Please take a look of the fiddle that I tried from #DavidHedlund answer. In this case, only Hello !! is printed.
$(document).ready(function() {
function typeWriter(element, msg, speed, index = 0) {
if (index < msg.length) {
$(element).html($(element).html() + msg.charAt(index++));
setTimeout(function() {
typeWriter(element, msg, speed, index);
}, speed);
}
}
$('.intro').fadeIn(function() {
function executeTasks() {
var tasks = Array.prototype.concat.apply([], arguments);
var task = tasks.shift();
task(function() {
if (tasks.length > 0)
executeTasks.apply(this, tasks);
});
}
function createTask(param) {
let element = param[0];
let msg = param[1];
let speed = param[2];
return function(callback) {
setTimeout(function() {
if (typeof callback == 'function') typeWriter(element, msg, speed);
}, 1);
}
}
var t1 = createTask(['#sayHello', "Hello !!", 200]);
var t2 = createTask(['#myName', "I'm Anshuman Gupta", 200]);
executeTasks(t1, t2);
});
});
.intro {
text-align: center;
display: none;
font-family: 'Amaranth', sans-serif;
}
.cursor {
display: inline-block;
width: 10px;
height: inherit !important;
}
.cursor>span {
display: inline-block;
position: relative;
top: 2px;
width: 3px;
height: 26px;
margin: 0 0 0 0px;
background-color: #000;
animation: blink 1s step-end infinite;
}
#keyframes blink {
from,
to {
opacity: 1;
}
50% {
opacity: 0;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="intro">
<h1 class="title"><span id="sayHello"></span><span class="cursor"><span></span></span>
</h1>
<h1 class="title"><span id="myName"></span><span class="cursor"><span></span></span>
</h1>
</div>
Thank you!!
So, whats happening here is, the typeWriter() method is using a setTimeout(), which works on a threaded model (that is setTimeout() will not block the thread, instead will return immediately). That is why, the typeWriter() method returns immediately, and therefore the corresponding promise resolves.
Try this code
$(document).ready(function() {
function typeWriter(element, msg, speed) {
return new Promise (function (resolve, reject) {
var recursive = function (element, msg, speed, index) {
if (index < msg.length) {
$(element).html($(element).html() + msg.charAt(index++));
setTimeout(function() {
recursive(element, msg, speed, index);
}, speed)
} else {
resolve();
}
}
recursive(element, msg, speed, 0)
})
}
$('.intro').fadeIn(function() {
typeWriter('#sayHello', "Hello !!", 200).then(function() {
return typeWriter('#myName', "I'm learning programming", 200);
});
});
})
Alternatively, you could use await if that seems simpler for you.
$(document).ready(function() {
function typeWriter(element, msg, speed, index = 0) {
return new Promise((resolve, reject) => {
if (index < msg.length) {
$(element).html($(element).html() + msg.charAt(index++));
setTimeout(function() {
typeWriter(element, msg, speed, index).then(resolve).catch(reject);
}, speed);
} else {
resolve();
}
});
}
async function typeStuff() {
console.log("Hi");
await typeWriter('#sayHello', "Hello !!", 200);
await typeWriter('#myName', "I'm learning programming", 200);
}
$('.intro').fadeIn(function() {
typeStuff();
});
});
.intro {
text-align: center;
display: none;
font-family: 'Amaranth', sans-serif;
}
.cursor {
display: inline-block;
width: 10px;
height: inherit !important;
}
.cursor>span {
display: inline-block;
position: relative;
top: 2px;
width: 3px;
height: 26px;
margin: 0 0 0 0px;
background-color: #000;
animation: blink 1s step-end infinite;
}
#keyframes blink {
from,
to {
opacity: 1;
}
50% {
opacity: 0;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="intro">
<h1 class="title"><span id="sayHello"></span><span class="cursor"><span></span></span>
</h1>
<h1 class="title"><span id="myName"></span><span class="cursor"><span></span></span>
</h1>
</div>
Explanation: in your code, you called resolve immediately after calling typeWriter. The issue is that typeWriter does not "block," meaning it sets a timeout to execute code in the future and immediately returns. You can avoid this my making typeWriter a promise. Then, you can either use await (which is cleaner but less supported by browsers) or typeWriter(...).then(function() { /* Do more stuff */ }) (they are essentially equivalent).
The problem is you do not wait for the recursion function to finish and then call resolve.
const greet = new Promise(function(resolve, reject) {
typeWriter('#sayHello', "Hello !!", 200);
resolve();
});
greet.then(function() {
typeWriter('#myName', "I'm learning programming", 200);
});
Try this:
const timeout = (speed) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, speed);
});
}
$(document).ready(function() {
async function typeWriter(element, msg, speed, index = 0) {
if (index < msg.length) {
$(element).html($(element).html() + msg.charAt(index++));
await timeout(speed);
await typeWriter(element, msg, speed, index);
}
}
$('.intro').fadeIn(function() {
const greet = new Promise(async function(resolve, reject) {
await typeWriter('#sayHello', "Hello !!", 200);
resolve();
});
greet.then(function() {
typeWriter('#myName', "I'm learning programming", 200);
});
});
});
Here's the code, but instead of it completely disappears, is there some way to make it go 0.5 opacity? Help on this would be much appreciated.
$(function () {
var timer;
var fadeInBuffer = false;
$(document).mousemove(function () {
if (!fadeInBuffer) {
if (timer) {
console.log("clearTimer");
clearTimeout(timer);
timer = 0;
}
console.log("fadeIn");
$('.fade-object').fadeIn();
$('html').css({
cursor: ''
});
} else {
fadeInBuffer = false;
}
timer = setTimeout(function () {
console.log("fadeout");
$('.fade-object').fadeOut()
$('html').css({
cursor: 'none'
});
fadeInBuffer = true;
}, 2000)
});
});
You can use fadeTo(). Hope this helps.
$(function () {
var timer;
var fadeInBuffer = false;
$(document).mousemove(function () {
if (!fadeInBuffer) {
if (timer) {
clearTimeout(timer);
timer = 0;
}
$('.fade-object').fadeTo('slow', 1);
$('html').css({
cursor: ''
});
} else {
fadeInBuffer = false;
}
timer = setTimeout(function () {
$('.fade-object').fadeTo('slow', 0.5)
$('html').css({
cursor: 'none'
});
fadeInBuffer = true;
}, 2000)
});
});
.fade-object{
height: 300px;
background: red;
width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="fade-object"></div>
** UPDATED **
Try using setInterval instead of setTimeout, and vary from 10 to 0 to disapear and from 0 to 10 to reapear (according to filenames).
Do this by changing trhough custom png cursors with alfas from 0 to 100 in 10 phases.
Here are some images I prepared: , , , , , , , , , , << last one is 0%
Remember that your cursor (mouse pointer) WON'T change its custom image IF it is NOT moving **, so .. you will need to translate cursor at least 10px programatically while iterating trhough the 10 images.
** UPDATE 2 **
Here you can feel the idea.
//codepen.io/jjyepez/pen/xEQAXZ
PS (forget about translating cursor .. it is not necessary whatsoever)
I have below my JAVASCRIPT code which change between 2 words every 2.5 seconds and I want to add fading to the transition between the words in the array it uses. I know that I need to use Jquery but how do I implement it in this recursive function? Any ideas?
var text = ["first", "second"];
var counter = 0;
var elem = document.getElementById("changeText");
setInterval(change, 2500);
function change() {
elem.innerHTML = text[counter];
counter++;
if (counter >= text.length) {
counter = 0;
}
}
.banner-right h2 {
font-size: 50px;
font-weight: 300;
color: #ffffff;
margin: 15px 0 45px 0;
}
<h2 id="changeText">Data Scientist</h2>
Since you are using Native JavaScript you could use CSS transitions and classList.
Something like:
CSS
#changeText {
opacity: 1;
transition: opacity 0.5s;
}
.hide {
opacity: 0 !important;
}
JavaScript
function change() {
elem.classList.add('hide');
setTimeout(function () {
elem.innerHTML = text[counter];
elem.classList.remove('hide');
counter++;
if (counter >= text.length) {
counter = 0;
}
}, 500);
}
Demo:
var text = ["first", "second"];
var counter = 0;
var elem = document.getElementById("changeText");
setInterval(change, 2500);
function change() {
elem.classList.add('hide');
setTimeout(function () {
elem.innerHTML = text[counter];
elem.classList.remove('hide');
counter++;
if (counter >= text.length) {
counter = 0;
}
}, 500);
}
#changeText {
opacity: 1;
transition: opacity 0.5s;
}
.hide {
opacity: 0 !important;
}
<h2 id="changeText">Data Scientist</h2>
Note: I used !important in the CSS because opacity: 1; when applied with a ID selector has priority over a class selector.
Replace this part:
elem.innerHTML = text[counter];
With:
$(elem)
.fadeOut(400)
.html(text[counter])
.delay(400)
.fadeIn(400);
How can I change this script from jQuery to JavaScript? I have little experience with JavaScript and I don't know how to change it myself.
Script:
var rotate = function() {$("#Top")
.delay(1000).queue(function() {
$(this).css({
"background-color": "red"
});
$(this).dequeue();
})
.delay(3000).queue(function() {
$(this).css({
"background-color": "green"
});
$(this).dequeue();
})
.delay(500).queue(function(next) {
$(this).css({
"background-color": "blue"
});
$(this).dequeue();
next();
})
.queue(rotate);
};
rotate();
Html
<div id="Top"></div>
Original: http://jsfiddle.net/h4KL7/1/
John Resig is the guy who wrote jQuery and here is a blurb about How JavaScript Timers Work.
I know it is not perfect and could use setInterval() and clearInterval() to be more efficient, but this is a start DEMO
var rotate = function () {
var el = document.getElementById('Top');
setTimeout(function () {
el.style.backgroundColor = 'red';
setTimeout(function () {
el.style.backgroundColor = 'green';
setTimeout(function () {
el.style.backgroundColor = 'blue';
rotate();
}, 500);
}, 3000);
}, 1000);
}
Update: Added an array to reference timeout IDs to ensure that duplicates are not created in case time gets out of sync.
var rotate = function () {
var el = document.getElementById('Top');
var timers = new Array(3);
function red(el) {
el.style.backgroundColor = 'red';
timers[0] = setTimeout(function () { green(el); }, 1000);
clearTimeout(timers[2]);
}
function green(el) {
el.style.backgroundColor = 'green';
timers[1] = setTimeout(function () { blue(el); }, 3000);
clearTimeout(timers[0]);
}
function blue(el) {
el.style.backgroundColor = 'blue';
timers[2] = setTimeout(function () { red(el); }, 500);
clearTimeout(timers[1]);
}
red(el);
};
rotate();
The title of your post should be: "How can I change this from jQuery to CSS" ;-)
#-webkit-keyframes rainbow {
0% { background: #FFABAB; }
20% { background: #FFDAAB; }
40% { background: #DDFFAB; }
60% { background: #ABE4FF; }
80% { background: #D9ABFF; }
100% { background: #FFABAB; }
}
.top {
min-height: 200px;
-webkit-animation: rainbow 10s infinite steps(1);
}
If you want to have smooth transition between your background color just omit the steps(1) in the animation shorthand property.
Check this out!
I have a jsfiddle that allows the user to click on a square and the square expands. What I want to do is allow a separate div to appear once a div is clicked. For example, if the first div is clicked, I want the transition to happen and then text to appear over the green.
Here is the javascript I am using:
$('div').on('click', function (e) {
if ($(this).hasClass('clicked')) {
setTimeout(function (div) {
return function () { div.css('z-index', '') ; } ;
} ($(this)), 1000) ;
}
else {
$(this).css('z-index', 400) ;
}
$(this).toggleClass('clicked') ;
});
http://jsfiddle.net/eD56Y/11/
Here's a fiddle: http://jsfiddle.net/UawH4/
You can add a div with append() and remove it when you collapse the box with remove().
$('div').on('click', function (e) {
if ($(this).hasClass('clicked')) {
setTimeout(function (div) {
return function () { div.css('z-index', '') ; } ;
} ($(this)), 1000) ;
$('#addedDiv').remove();
}
else {
$(this).css('z-index', 400) ;
$(this).append('<div id="addedDiv">Here is some text</div>');
}
$(this).toggleClass('clicked') ;
});
If you use this code
$('div').on('click', function (e) {
if ($(this).hasClass('clicked')) {
setTimeout(function (div) {
return function () { div.css('z-index', '') ; } ;
} ($(this)), 1000) ;
$( ".first_box" ).empty();
}
else {
$(this).css('z-index', 400) ;
}
$(this).toggleClass('clicked') ;
$('<p>Text</p>').appendTo('.first_box');
});
The content <p>text></p> will appear in the div .first_box if clicked (and so if it gets bigger)
I am assuming the text is outside the rest of the divs.
You can try this.
fiddle Link
HTML
<section class="overlay-text"><h3>Some Text</h3></section>
<div class="first_box"></div>
<div class="second_box"></div>
<div class="third_box"></div>
<div class="fourth_box"></div>
JS
$('div').on('click', function (e) {
if ($(this).hasClass('clicked')) {
setTimeout(function (div) {
return function () { div.css('z-index', '') ; } ;
} ($(this)), 1000) ;
$('.overlay-text').hide();
}
else {
$(this).css('z-index', 400) ;
setTimeout(function(){$('.overlay-text').show();},1000);
}
$(this).toggleClass('clicked') ;
});
Added CSS
.overlay-text {
position:absolute;
display:none;
text-align:center;
width: 289px !important ;
height: 289px !important ;
margin-top: 0 !important ;
margin-left: 0 !important ;
z-index:500;
pointer-events:none;
}
h3{color:white;}
You can add a "show" class to content div and it will transition in the content with opacity 0 to 1:
$('div').on('click', function (e) {
if ($(this).hasClass('clicked')) {
setTimeout(function (div) {
return function () { div.css('z-index', '') ; } ;
} ($(this)), 1000) ;
}
else {
$(this).css('z-index', 400) ;
}
$(this).toggleClass('clicked') ;
//make sure to show the content in the clicked div.
$(this).find('.content').toggleClass('show');
});
And the CSS changes:
.content {
opacity: 0;
}
.content.show {
opacity: 1;
}
Edit: To keep colors of expanded content: Just add extra css classes to keep the content background color once clicked. See updated fiddle:
.first_box.clicked {
background-color: green;
}
.second_box.clicked {
background-color: blue;
}
.third_box.clicked {
background-color: red;
}
.fourth_box.clicked {
background-color: yellow;
}