I have three headings in my html. On page load I want to change the color of these headings one by one and it should start again with the first one after the last heading. I have tried setTimeout function of JS but cant get the result which I want.
It should work like this:
- "Text 1" – Green color for 10 seconds
- "Text 2" – Green color for 15 Seconds
- "Text 3" – Green color for 18 seconds
After "Text 3", it should again start with "Text 1"
Below is my code.
<body onload="startAuto()">
<h1 id="first">Text 1</h1>
<h1 id="second">Text 2</h1>
<h1 id="third">Text 3</h1>
</body>
I have used the following JavaScript its working first time but when it reaches to Text 3 it doesn't go back to Text 1.
function startAuto() {
function first() {
document.getElementById('first').style.color = "#32A067";
}
function second() {
setTimeout(function() {
document.getElementById('first').style.color = "#333";
document.getElementById('second').style.color = "#32A067";
}, 13000);
}
second();
function third() {
setTimeout(function() {
document.getElementById('first').style.color = "#333";
document.getElementById('second').style.color = "#333";
document.getElementById('third').style.color = "#32A067";
}, 26000);
}
third();
}
I have three headings in my html. On page load I want to change the color of these headings one by one and it should start again with the first one after the last heading. I have tried setTimeout function of JS but cant get the result which I want.
It should work like this:
- "Text 1" – Green color for 10 seconds
- "Text 2" – Green color for 15 Seconds
- "Text 3" – Green color for 18 seconds
After "Text 3", it should again start with "Text 1"
Below is my code.
<body onload="startAuto()">
<h1 id="first">Text 1</h1>
<h1 id="second">Text 2</h1>
<h1 id="third">Text 3</h1>
</body>
I have used the following JavaScript its working first time but when it reaches to Text 3 it doesn't go back to Text 1.
function startAuto() {
function first() {
document.getElementById('first').style.color = "#32A067";
}
function second() {
setTimeout(function() {
document.getElementById('first').style.color = "#333";
document.getElementById('second').style.color = "#32A067";
}, 13000);
}
second();
function third() {
setTimeout(function() {
document.getElementById('first').style.color = "#333";
document.getElementById('second').style.color = "#333";
document.getElementById('third').style.color = "#32A067";
}, 26000);
}
third();
}
Share
Improve this question
edited Apr 9, 2020 at 14:08
Mr. Polywhirl
48.9k12 gold badges94 silver badges145 bronze badges
asked Apr 9, 2020 at 13:27
Faisal ShaniFaisal Shani
8201 gold badge23 silver badges52 bronze badges
3
- if you need any more explanation about my answer, don't hesitate – Quantumass Commented Apr 9, 2020 at 14:10
- Check out my solution, Im sure, you will like it ;) – Elman Huseynov Commented Apr 9, 2020 at 14:42
- thanks all. I have also posted my own version of solution. – Faisal Shani Commented Apr 9, 2020 at 15:32
4 Answers
Reset to default 3Thanks for all these answers but I have found the easiest and cleanest solution myself. Just settimeout function in the previous one, in a circular fashion. Its more nicer and clear. Below is the code snippet.
<body>
<h1 id="first">Text 1</h1>
<h1 id="second">Text 2</h1>
<h1 id="third">Text 3</h1>
</body>
<script>
first();
function first()
{
document.getElementById('third').style.color="#333";
document.getElementById('first').style.color="#32A067";
setTimeout(second,10000);
}
function second()
{
document.getElementById('first').style.color="#333";
document.getElementById('second').style.color="#32A067";
setTimeout(third,15000);
}
function third()
{
document.getElementById('second').style.color="#333";
document.getElementById('first').style.color="#32A067";
setTimeout(first,18000);
}
</script>
You have to use a circular array and timeout to sleep and recall the function
listElements
contains all the elements you want to highlight and their highlight time
startAutoIndex
will be increment each time the function is called so it will start with element id first
var startAutoIndex = 0
function startAuto() {
let listElements = [
{id: "first", timer: 10000},
{id: "second", timer: 13000},
{id: "third", timer: 26000}
]
function colorHeader(currentIndex) {
for (let index = 0; index < listElements.length; index++) {
const element = listElements[index]
if (currentIndex != index)
document.getElementById(element.id).style.color = '#333'
else {
document.getElementById(element.id).style.color = '#32A067'
}
}
}
let currentIndex =
((startAutoIndex % listElements.length) + listElements.length) %
listElements.length
colorHeader(currentIndex)
setTimeout(startAuto, listElements[currentIndex].timer)
startAutoIndex = currentIndex + 1
}
You can use setTimeout together with promises to achive result you want. Check out my snippet:
var first = document.getElementById('first');
var second = document.getElementById('second');
var third = document.getElementById('third');
const promiseTimeout = (delay, element, newColor) =>
{
return new Promise((resolve, reject) => {
setTimeout(() => {
element.style.color = newColor;
resolve() // when this fires, .then gets called
}, delay)
});
}
function start(){
first.style.color = "green";
promiseTimeout(10000, first, "#333")
.then(() => {
return second.style.color = "green";
})
.then(() => {
return promiseTimeout(15000, second, "#333")
})
.then(() => {
third.style.color = "green";
return promiseTimeout(18000, third, "#333")
})
.then(() => start());
}
start();
<h1 id="first">Text 1</h1>
<h1 id="second">Text 2</h1>
<h1 id="third">Text 3</h1>
<script src="https://cdnjs.cloudflare./ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You can wrap the main timer inside an interval, and each highlight event as a separate timeout.
I would also add a class to the elements you want to query for, or just select all h1
elements.
You could also provided a fixed timeout, and it will calculate the timeouts between elements for you.
window.startAuto = () => {
start({
selector : '.highlighter',
timeouts : [ 1000, 2000, 1000 ], // or, for a fixed timout: 1000
callback : (el, index, activeIndex) => {
el.classList.toggle('active', index === activeIndex);
}
});
};
const defaultOptions = {
selector : '',
timeouts : [],
initialDelay : 0
};
const start = (options) => {
let opts = Object.assign({}, defaultOptions, options);
opts.elements = Array.from(document.querySelectorAll(opts.selector));
let interval = 0;
if (!Array.isArray(opts.timeouts)) {
opts.timeouts = fillArray(opts.timeouts, opts.elements.length);
}
interval = opts.timeouts.reduce((t, x) => t + x, 0);
opts.timeouts = normalizeTimeouts(opts.timeouts);
setTimeout(() => {
update(opts);
setInterval(update, interval, opts);
}, opts.initialDelay);
};
const normalizeTimeouts = (timeouts) => {
return timeouts.reduce((results, timeout, index, all) => {
return results.concat(timeout + all.slice(0, index).reduce((t, x) => t + x, 0));
}, [0]);
};
const update = (opts) => {
opts.timeouts.slice(0, opts.timeouts.length -1).forEach((timeout, index) => {
setTimeout(() => {
opts.elements.forEach((element, i) => {
return opts.callback.call(element, element, i, index);
});
}, timeout);
})
};
const fillArray = (value, count) => new Array(count).fill(value);
.active {
color: green;
}
<body onload="startAuto()">
<h1 class="highlighter" id="first">Text 1</h1>
<h1 class="highlighter" id="second">Text 2</h1>
<h1 class="highlighter" id="third">Text 3</h1>
</body>
Here is a super-dynamic; reusable class.
document.addEventListener('DOMContentLoaded', () => main());
const main = () => {
let looper = new Looper({
selector : '.highlighter',
timeouts : [ 1000, 2000, 1000 ], // or, for a fixed timout: 1000
callback : (el, index, activeIndex) => {
el.classList.toggle('active', index === activeIndex);
},
initialDelay : 1000,
autoStart : true
})
document.querySelector('#stop-btn').addEventListener('click', (e) => {
looper.stop();
});
document.querySelector('#restart-btn').addEventListener('click', (e) => {
looper.stop();
looper.start();
});
}
class Looper {
constructor(options) {
let opts = Object.assign({}, Looper.defaultOptions, options);
this.elements = Array.from(document.querySelectorAll(opts.selector));
if (!Array.isArray(opts.timeouts)) {
opts.timeouts = this.__fillArray(opts.timeouts, this.elements.length);
}
this.interval = opts.timeouts.reduce((t, x) => t + x, 0);
this.timeouts = this.__normalizeTimeouts(opts.timeouts);
this.initialDelay = opts.initialDelay;
this.autoStart = opts.autoStart;
this.callback = opts.callback;
this.__startupId = null;
this.__processId = null;
this.__subprocessIds = this.__fillArray(null, this.elements.length);
if (this.autoStart === true) this.start();
}
start() {
if (this.callback == null) {
throw new Error('callback function is undefined');
}
if (this.__processId == null) {
this.__startupId = setTimeout(() => {
this.__update();
this.__processId = setInterval(() => {
this.__update();
}, this.interval);
}, this.initialDelay);
}
}
stop() {
this.__subprocessIds.forEach((id, index) => {
if (id != null) {
clearTimeout(id);
this.__subprocessIds[index] = null;
}
});
if (this.__processId != null) {
clearInterval(this.__processId);
this.__processId = null;
}
if (this.__startupId != null) {
clearTimeout(this.__startupId);
this.__startupId = null;
}
}
__update() {
let self = this;
self.timeouts.slice(0, this.timeouts.length -1).forEach((timeout, index) => {
self.__subprocessIds[index] = setTimeout(() => {
self.elements.forEach((element, i) => {
return self.callback.call(element, element, i, index);
});
}, timeout);
})
}
__normalizeTimeouts(timeouts) {
return timeouts.reduce((results, timeout, index, all) => {
return results.concat(timeout + all.slice(0, index).reduce((t, x) => t + x, 0));
}, [0]);
}
__fillArray(value, count) {
return new Array(count).fill(value);
}
}
Looper.defaultOptions = {
selector : '',
timeouts : [],
initialDelay : 0,
autoStart : false
}
.active {
color: green;
}
<div>
<h2 class="highlighter" id="first">Text 1</h2>
<h2 class="highlighter" id="second">Text 2</h2>
<h2 class="highlighter" id="third">Text 3</h2>
</div>
<button id="stop-btn">Stop</button>
<button id="restart-btn">Restart</button>