I have 2 groups of parent containers, both with 5 children each -- 4 paragraphs and 2 buttons per container.
When the button in each container is clicked, a class is added to the paragraph element, one at a time. After the last paragraph child element is reached, the first paragraph child gets the class added to it again.
Below are the code. When the last paragraph is reached, I want the class added immediately to the first paragraph -- but the counter won't reset.
If you check the console.log, both counter and j go to 4, which it shouldnt. After both counter and j reaches 3, it should reset back to 0. My parameters are probably way off.
var container = document.querySelectorAll(".container");
var button = document.querySelectorAll("button");
var p = document.querySelectorAll("p");
var click = function(i) {
var counter = -1;
button[i].addEventListener("click", function() {
counter++;
console.log(counter);
for (j = 0; j < p.length / 2 + 1; j++) {
console.log(i, j);
this.parentNode.children[j].classList.remove("active");
if (j === counter) {
this.parentNode.children[j].classList.add("active");
}
if (counter === p.length / 2) {
counter = -1;
}
}
});
}
for (i = 0; i < button.length; i++) {
click(i);
}
.active {
background-color: red;
}
<div class="container">
<p>Test1</p>
<p>Test2</p>
<p>Test3</p>
<p>Test4</p>
<button>click</button>
</div>
<div class="container">
<p>Test1</p>
<p>Test2</p>
<p>Test3</p>
<p>Test4</p>
<button>click</button>
</div>
It's enough to add a modulus 4 op immediately after the increment:
counter %= 4;
Because the number of paragraphs may change you can compute their number on the fly:
var maxParagrapgh = button[i].parentNode.querySelectorAll('p').length;
And so the increment is:
counter = (counter + 1) % maxParagrapgh;
The running snippet:
window.addEventListener('DOMContentLoaded', function(e) {
var container = document.querySelectorAll(".container");
var button = document.querySelectorAll("button");
var p = document.querySelectorAll("p");
var click = function(i){
var counter = -1;
var maxParagrapgh = button[i].parentNode.querySelectorAll('p').length;
button[i].addEventListener("click", function(){
counter = (counter + 1) % maxParagrapgh;
// console.log(counter);
for(j=0;j<p.length/2+1;j++){
// console.log(i, j);
this.parentNode.children[j].classList.remove("active");
if(j === counter){
this.parentNode.children[j].classList.add("active");
}
if(counter === p.length/2){
counter = -1;
}
}
});
}
for(i=0;i<button.length;i++){
click(i);
}
})
.active {
background-color: red;
}
<div class="container">
<p>Test1</p>
<p>Test2</p>
<p>Test3</p>
<p>Test4</p>
<button>click</button>
</div>
<div class="container">
<p>Test1</p>
<p>Test2</p>
<p>Test3</p>
<p>Test4</p>
<button>click</button>
</div>
Related
I am working on an HTML page where I want function typewriter to be executed first and then for a loop to start that prints '.', to make it look like a loading screen.
This is the code I am using:
var y = 0
var i = 0;
var txt = '//Welcome To My Playground!';
var speed = 100;
function typeWriter() {
if (i < txt.length) {
document.getElementById("typing").innerHTML += txt.charAt(i);
i++;
setTimeout(typeWriter, speed);
}
y = 1;
}
while (y == 1) {
var span = document.getElementById('myspan');
var int = setInterval(function() {
if ((span.innerHTML += '.').length == 11)
span.innerHTML = '';
}, 200);
}
window.onload = typeWriter;
<div class="main d-none d-lg-block">
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-1">Hi,<br>I'm Shalaj<span id="myspan"></span>
</h1>
<h1 id="typing" class="display-5" style="margin-top:30px;"></h1>
<h1 class="display-5" style="margin-top:100px;">
Prototyping = ["Arduino", "Raspberry Pi"]
<br> Languages = ["HTML", "CSS", "PYTHON", "C++"]
</h1>
</div>
</div>
</div>
The function typewriter() is getting executed but the code following it doesn't start, I assume this is because the value of y is not being set as 1. Could someone help me out here?
Thanks
Perhaps you could create another function that is called where y is being set:
var i = 0;
var txt = '//Welcome To My Playground!';
var speed = 100;
function typeWriter() {
if (i < txt.length) {
document.getElementById("typing").innerHTML += txt.charAt(i);
i++;
setTimeout(typeWriter, speed);
} else {
typeEllipses();
}
}
function typeEllipses() {
var span = document.getElementById('myspan');
var int = setInterval(function() {
if ((span.innerHTML += '.').length == 11)
span.innerHTML = '';
}, 200);
}
window.onload = typeWriter;
<div class="main d-none d-lg-block">
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-1">Hi,<br>I'm Shalaj<span id="myspan"></span>
</h1>
<h1 id="typing" class="display-5" style="margin-top:30px;"></h1>
<h1 class="display-5" style="margin-top:100px;">
Prototyping = ["Arduino", "Raspberry Pi"]
<br> Languages = ["HTML", "CSS", "PYTHON", "C++"]
</h1>
</div>
</div>
</div>
You can see what is happening if you change
while(statement) {
//code
}
to
do{
//code
}while(statement)
The do...while loop only executes once. That's because it's being run one time on execution, at the time that y == 0. The while loop the way you have it never fires at all because the one time its statement is interpreted, y == 0.
If you want to call it every time typeWriter() is called, you already have a recursive loop for that function, so just put the while code in its own function and call it from inside there.
var y = 0
var i = 0;
var txt = '//Welcome To My Playground!';
var speed = 100;
function typeWriter() {
if (i < txt.length) {
document.getElementById("typing").innerHTML += txt.charAt(i);
i++;
setTimeout(typeWriter, speed);
}
console.log(y)
y = 1;
}
do{
console.log("test")
/*var span = document.getElementById('myspan');
var int = setInterval(function() {
if ((span.innerHTML += '.').length == 11)
span.innerHTML = '';
}, 200);*/
}while (y == 1)
window.onload = typeWriter;
<div id="typing"></div>
Hey try this No Need For Loop
If you use while loop of infinite it will crash.
so just use setInterval and clear the interval once theed for the loading is done clear the interval using clearInterval()
var y = 0
var i = 0;
var txt = '//Welcome To My Playground!';
var speed = 100;
function typeWriter() {
if (i < txt.length) {
document.getElementById("typing").innerHTML += txt.charAt(i);
i++;
setTimeout(typeWriter, speed);
}
y = 1;
}
var span = document.getElementById('myspan');
var interval = setInterval(function () {
if ((span.innerHTML += '.').length == 11)
span.innerHTML = '';
}, 200);
window.onload = typeWriter;
<div class="main d-none d-lg-block">
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-1">Hi,<br>I'm Shalaj<span id="myspan"></span>
</h1>
<h1 id="typing" class="display-5" style="margin-top:30px;"></h1>
<h1 class="display-5" style="margin-top:100px;">
Prototyping = ["Arduino", "Raspberry Pi"]
<br>
Languages = ["HTML", "CSS", "PYTHON", "C++"]
</h1>
</div>
</div>
</div>
Try this instead,
var i = 0;
var txt = "//Welcome To My Playground!";
var speed = 100;
var loading;
function typeWriter() {
if (i < txt.length) {
document.getElementById("typing").innerHTML += txt.charAt(i);
i++;
setTimeout(typeWriter, speed);
} else {
var span = document.getElementById("myspan");
var loading = setInterval(function () {
span.innerHTML = span.innerHTML.length == 11 ? "" : span.innerHTML;
span.innerHTML += ".";
}, speed);
// clearInterval(loading); // to stop loading dots
}
}
I am using next and prev buttons so one question will be shown at a time, however, once next or prev buttons are disabled, the other button doesn't work anymore either. Here's my code:
var showing = [1, 0, 0, 0];
var questions = ['q0', 'q1', 'q2', 'q3'];
function next() {
var qElems = [];
for (var i = 0; i < questions.length; i++) {
qElems.push(document.getElementById(questions[i]));
}
for (var i = 0; i <= showing.length; i++) {
if (showing[i] == 1) {
showing[i] = 0;
if (i == showing.length - 1) {
document.getElementById("next").disabled = true;
} else {
console.log(i);
qElems[i + 1].style.display = 'block';
qElems[i].style.display = 'none';
showing[i + 1] = 1;
}
break;
}
}
}
function prev() {
var qElems = [];
for (var i = 0; i < questions.length; i++) {
qElems.push(document.getElementById(questions[i]));
}
for (var i = 0; i <= showing.length; i++) {
if (showing[i] == 1) {
showing[i] = 0;
if (i == showing.length - 4) {
document.getElementById("prev").disabled = true;
} else {
qElems[i - 1].style.display = 'block';
qElems[i].style.display = 'none';
showing[i - 1] = 1;
}
break;
}
}
}
I think you want this simplified script
I had to guess the HTML, but there is only one function.
window.addEventListener("load", function() {
let showing = 0;
const questions = document.querySelectorAll(".q");
questions[showing].style.display = "block";
const next = document.getElementById("next");
const prev = document.getElementById("prev");
document.getElementById("nav").addEventListener("click", function(e) {
var but = e.target, dir;
if (but.id === "prev") dir = -1;
else if (but.id === "next") dir = 1;
else return; // not a button
questions[showing].style.display = "none"; // hide current
showing += dir; // up or down
next.disabled = showing === questions.length-1;
if (showing <= 0) showing = 0;
prev.disabled = showing === 0
questions[showing].style.display = "block";
})
})
.q { display:none }
<div class="q" id="q0">Question 0</div>
<hr/>
<div class="q" id="q1">Question 1</div>
<hr/>
<div class="q" id="q2">Question 2</div>
<hr/>
<div class="q" id="q3">Question 3</div>
<hr/>
<div id="nav">
<button type="button" id="prev" disabled>Prev</button>
<button type="button" id="next">Next</button>
</div>
Since this is a quiet interesting java script task, Im doing my own solution.
Hope this matches the requirement.
I have created 4 divs of which first one is only displayed at first. Remaining divs are placed hidden. On clicking next, the divs are displayed according to index. Once the last and first indexes are interpreted, the respective next and previous buttons are enabled and disabled.
var showing = [1, 0, 0, 0];
var questions = ['q0', 'q1', 'q2', 'q3'];
var qElems = [];
function initialize() {
for (var i = 0; i < questions.length; i++) {
qElems.push(document.getElementById(questions[i]));
}
}
function updatevisibilitystatus(showindex, hideindex) {
qElems[showindex].style.display = 'block';
qElems[hideindex].style.display = 'none';
showing[showindex] = 1;
}
function next() {
for (var i = 0; i <= showing.length; i++) {
if (showing[i] == 1) {
showing[i] = 0;
if (i == showing.length - 2) {
document.getElementById("next").disabled = true;
}
updatevisibilitystatus(i + 1, i);
document.getElementById("prev").disabled = false;
break;
}
}
}
function prev() {
for (var i = 0; i <= showing.length; i++) {
if (showing[i] == 1) {
showing[i] = 0;
if (i == 1) {
document.getElementById("prev").disabled = true;
}
updatevisibilitystatus(i - 1, i);
document.getElementById("next").disabled = false;
break;
}
}
}
<body onload="initialize()">
<div id="q0" style="display: block;">Q0</div>
<div id="q1" style="display: none;">Q1</div>
<div id="q2" style="display: none;">Q2</div>
<div id="q3" style="display: none;">Q3</div>
<button id="prev" disabled onclick="prev()">Prev</button>
<button id="next" onclick="next()">Next</button>
</body>
I have a setTimeout inside the a for loop, but it not behaving as i anticipated.
I have a bunch of banners in a page that are loading all at once. I am removing their parent's div html and storing it in an array. Then I would like for each parent to receive its corresponding html every 5 seconds. This only needs to happen once on ready state.
Here's my code...
function oneBanner() {
var divs = $('.banner-slide'),
imgs = [];
for ( var j = 0; j < divs.length; j++ ) {
imgs.push( $('.banner-slide:nth-child(' + (j+1) + ')') );
}
for ( var k = 0; k < imgs.length; k++ ) {
var url = $(imgs[k]).html();
$(imgs[k]).html('');
setTimeout(function(y) {
console.log(k * 5000);
$(imgs[k]).html(url);
}, k * 5000, k);
}
}
oneBanner();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div class="banner-slide">
<img src="http://www.placecage.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://fillmurray.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://stevensegallery.com/150/150" >
</div>
As you can see the images do not get printed on the screen one at a time every 5 seconds - which I thought I was doing.
Thank you for any help.
Serge
It will be better to simplify your code while you don't need any of variables/arrays outside this function .. you can just use jquery .each()
try This
function oneBanner() {
var divs = $('.banner-slide');
divs.each(function(i){ // loop through .banner-slide divs
var ThisIt = $(this); // define this outside setTimout function
setTimeout(function(){
divs.hide(); // hide all .banner-slide divs
ThisIt.show(); // show just this one
} , 5000 * i); // time * the i -- i is the index of the div
});
}
see the code in action
function oneBanner() {
var divs = $('.banner-slide');
divs.each(function(i){
var ThisIt = $(this);
setTimeout(function(){
divs.hide();
ThisIt.show();
} , 5000 * i);
});
}
oneBanner();
.banner-slide:not(:first){
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="banner-slide">
<img src="http://www.placecage.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://fillmurray.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://stevensegallery.com/150/150" >
</div>
Note: by using setTimeout() you'll show each image for 5 seconds and the code will stop looping
Update up to the OP comment
function oneBanner() {
var divs = $('.banner-slide'),
htmlArray = [];
divs.each(function(i){
var ThisIt = $(this); // get this outside the setTimout
htmlArray.push(ThisIt.html()); // push the inner html to the array
ThisIt.html(''); // emty this div
setTimeout(function(){
$(ThisIt).html(htmlArray[i]); // add html again with setTimeout every 5 second to its parent div
} , 5000 * i);
});
}
oneBanner();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="banner-slide">
<img src="http://www.placecage.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://fillmurray.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://stevensegallery.com/150/150" >
</div>
one word: closure
function oneBanner() {
var divs = $('.banner-slide'),
imgs = [];
for ( var j = 0; j < divs.length; j++ ) {
imgs.push( $('.banner-slide:nth-child(' + (j+1) + ')') );
}
imgs.forEach(($img,k)=>{
var url = $img.html();
$img.html('');
setTimeout(function(y) {
$img.html(url);
}, k * 5000, k);
})
}
oneBanner();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div class="banner-slide">
<img src="http://www.placecage.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://fillmurray.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://stevensegallery.com/150/150" >
</div>
You are referencing the wrong variable inside of your setTimeout. Replace 'y' with 'k'
function oneBanner() {
var divs = $('.banner-slide'),
imgs = [];
for ( var j = 0; j < divs.length; j++ ) {
imgs.push( $('.banner-slide:nth-child(' + (j+1) + ')') );
}
for ( var k = 0; k < imgs.length; k++ ) {
var url = $(imgs[k]).html();
$(imgs[k]).html('');
setTimeout(function(k) {
console.log(k * 5000);
$(imgs[k]).html(url);
}, k * 5000, k);
}
}
oneBanner();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div class="banner-slide">
<img src="http://www.placecage.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://fillmurray.com/150/150" >
</div>
<div class="banner-slide">
<img src="http://stevensegallery.com/150/150" >
</div>
Let's say I have the following input field:
<input id="inputField" type="number" value="">
and some divs such as:
<div id="1000"></div>
<div id="1200"></div>
<div id="1500"></div>
<div id="1900"></div>
...
When the user enters a number in the input field, I want my code to go to the nearest div id to that number.
e.g: If user enters 1300 then show div with id = "1200".
What's the most efficient way to implement that in javascript considering there will be a large number of divs?
Right now I'm doing:
<script>
function myFunction()
{
var x = document.getElementById("inputField").value;
if(x >= 1750 && x <= 1900)
{
window.location.hash = '#1800';
}
}
</script>
One way is to wrap all your divs with number ids in another div if you can (and give it some id, say 'numbers'); this allows you to find all the divs in your javascript file.
Javascript:
// Get all the divs with numbers, if they are children of div, id="numbers"
let children = document.getElementById('numbers').children;
let array = [];
for (i = 0; i < children.length; i++) {
// Append the integer of the id of every child to an array
array.push(parseInt(children[i].id));
}
// However you are getting your input number goes here
let number = 1300 // Replace
currentNumber = array[0]
for (const value of array){
if (Math.abs(number - value) < Math.abs(number - currentNumber)){
currentNumber = value;
}
}
// You say you want your code to go to the nearest div,
// I don't know what you mean by go to, but here is the div of the closest number
let target = document.getElementById(currentNumber.toString());
Let me know if there's more I can add to help.
Demo
function closestNum() {
let children = document.getElementById('numbers').children;
let array = [];
for (i = 0; i < children.length; i++) {
array.push(parseInt(children[i].id));
}
let number = document.getElementById('inputnum').value;
currentNumber = array[0]
for (const value of array) {
if (Math.abs(number - value) < Math.abs(number - currentNumber)) {
currentNumber = value;
}
}
let target = document.getElementById(currentNumber.toString());
document.getElementById('target').innerHTML = target.innerHTML;
}
<div id="numbers">
<div id="1000">1000</div>
<div id="2000">2000</div>
<div id="3000">3000</div>
<div id="4000">4000</div>
<div id="5000">5000</div>
</div>
<br />
<input type="text" id="inputnum" placeholder="Input Number" onchange="closestNum()" />
<br />
<br /> Target:
<div id="target"></div>
With some optimization this shall be ok-
var element;
document.addEventListener("change",
function(evt){
if(element && element.classList){
element.classList.remove("selected", false);
element.classList.add("unselected", true);
}
var listOfDivs =
document.querySelectorAll(".unselected");
var val = evt.target.value;
var leastAbs=listOfDivs[0].id;
for(let anIndex=0, len=listOfDivs.length;anIndex<len;anIndex++){
if(Math.abs(listOfDivs[anIndex].id-val)<leastAbs){
leastAbs = Math.abs(listOfDivs[anIndex].id-val);
element = listOfDivs[anIndex];
}
}
element.classList.remove("unselected");
element.classList.add("selected");
});
.selected{
background-color:red;
}
.unselected{
background-color:yellow;
}
.unselected, .selected{
width:100%;
height:50px;
}
<input id="inputField" type="number" value="">
<div id="1000" class='unselected'>1</div>
<div id="1200" class='unselected'>2</div>
<div id="1500" class='unselected'>3</div>
<div id="1900" class='unselected'>4</div>
This may work for you. Loops through each div and compared it to your inputted ID. Tracks closest one, hides all divs, then displays the closest.
document.getElementById("inputField").addEventListener("change", function(){
var divs = document.getElementsByTagName("div");
var closestDiv = -1;
var inputId = document.getElementById("inputField").value;
for(var i=0; i<divs.length; i++)
{
if(Math.abs(inputId - closestDiv) > Math.abs(inputId - divs[i].id) || closestDiv == -1)
{
closestDiv = divs[i].id;
for (var x = 0; x < divs.length; x++) {
divs[x].style.display = 'none';
}
divs[i].style.display = "block";
}
}
});
See it Live: jsfiddle.net
I'm trying to select next 3 items(nextElementSiblings) for every click on 'next' button. Items length is 14. Its working fine till item 12. After item 12 its checking for next 3 items but there were only 2 left(thirteen 13, thirteen 14) in loop. So its unable to select last 2 items. How can I change the condition here when items left less than 3 at the end of the loop. And disable the onclick function on 'next' button as it reached till end. And enable it after clicking on 'prev' button.
var next = document.getElementById("next"),
list = document.getElementById("list");
var li = list.getElementsByTagName("DIV");
for (var i = 0; i < li.length; i++) {
li[i].style.display = "0px solid transparent";
}
for (var i = 0; i < 3; i++) {
li[i].style.border = "1px solid red";
}
var nextfun = (function(){
var nextitems = 4;
var prevItems = 1;
return function(){
nextitems = nextitems + 2;
prevItems = nextitems - 3;
for (var i = 0; i < nextitems; i++) {
li[i].style.border = "1px solid red";
if(nextitems >= li.length){
li[i].style.border = "1px solid red";
//nextitems = 2;
break;
//this.pointerEvents = "none";
}
}
for (var i = 0; i < prevItems; i++) {
li[i].style.border = "0px solid transparent";
if(prevItems <= li.length){
prevItems = nextitems - 3;
li[i].style.border = "1px solid transparent";
}
}
return ++nextitems;
//return --prevItems;
}
})();
<div id="list">
<div> one 1</div>
<div> two 2</div>
<div> three 3</div>
<div> four 4</div>
<div> five 5</div>
<div> six 6</div>
<div> seven 7</div>
<div> eight 8</div>
<div> nine 9 </div>
<div> ten 10</div>
<div> eleven 11</div>
<div> twelve 12</div>
<div> thirteen 13</div>
<div> fourteen 14</div>
</div>
<button id="prev" onclick="prevfun()">PREVIOUS 3</button>
<button id="next" onclick="nextfun()">NEXT 3</button>
I suggest to use only one variable for the start of the marked items and check if the item is in the inverval for marking red or not.
var next = document.getElementById("next"),
list = document.getElementById("list"),
li = list.getElementsByTagName("DIV"),
i,
nextfun = (function () {
var item = 3;
return function () {
for (var i = 0; i < li.length; i++) {
li[i].style.border = i >= item && i < item + 3 ? "1px solid red" : "0px solid transparent";
}
item += 3;
}
})();
for (i = 0; i < li.length; i++) {
li[i].style.border = "0px solid transparent";
}
for (var i = 0; i < 3; i++) {
li[i].style.border = "1px solid red";
}
<div id="list"><div> one 1</div><div> two 2</div><div> three 3</div><div> four 4</div><div> five 5</div><div> six 6</div><div> seven 7</div><div> eight 8</div> <div> nine 9 </div><div> ten 10</div><div> eleven 11</div><div> twelve 12</div><div> thirteen 13</div><div> fourteen 14</div></div>
<button id="prev" onclick="prevfun()">PREVIOUS 3</button>
<button id="next" onclick="nextfun()">NEXT 3</button>
A slightly better version with encapsulation for the buttons.
function Button(count) {
function setBorder() {
var i,
li = list.getElementsByTagName("DIV"),
l = li.length;
document.getElementById('prev').disabled = index <= 0;
document.getElementById('next').disabled = index + count >= l;
for (i = 0; i < l; i++) {
li[i].style.border = i >= index && i < index + 3 ? "1px solid red" : "0px solid transparent";
}
}
var index = 0;
this.next = function () {
index += count;
setBorder();
};
this.prev = function () {
index -= count;
setBorder();
};
setBorder();
}
var button = new Button(3);
<div id="list"><div> one 1</div><div> two 2</div><div> three 3</div><div> four 4</div><div> five 5</div><div> six 6</div><div> seven 7</div><div> eight 8</div> <div> nine 9 </div><div> ten 10</div><div> eleven 11</div><div> twelve 12</div><div> thirteen 13</div><div> fourteen 14</div></div>
<button id="prev" onclick="button.prev()">PREVIOUS 3</button>
<button id="next" onclick="button.next()">NEXT 3</button>
Just separate a function that will render your selection and set if the buttons are disabled or not. On your nextfun and prevfun functions, just increment or decrement your currentIndex variable.
var next = document.getElementById("next"),
prev = document.getElementById("prev"),
list = document.getElementById("list");
var li = list.getElementsByTagName("DIV");
var currentIndex = 0, amount = 3, len = li.length;
var selectItems = function() {
// render the borders
for (var i=0; i < len; i++) {
li[i].style.border = (i >= currentIndex && i < currentIndex + amount) ?
"1px solid red": "1px solid transparent";
}
// set the disabled property of the buttons
prev.disabled = currentIndex - amount < 0;
next.disabled = currentIndex + amount > len;
// uncomment below if you want to stop if next don't have
// 3 items
// next.disabled = currentIndex + (amount * 2) > len;
};
// decrement the currentIndex by amount and render
var prevfun = function() {
currentIndex-=amount;
selectItems();
};
// increment the currentIndex by amount and render
var nextfun = function() {
currentIndex+=amount;
selectItems();
};
selectItems();
<div id="list">
<div> one 1</div>
<div> two 2</div>
<div> three 3</div>
<div> four 4</div>
<div> five 5</div>
<div> six 6</div>
<div> seven 7</div>
<div> eight 8</div>
<div> nine 9 </div>
<div> ten 10</div>
<div> eleven 11</div>
<div> twelve 12</div>
<div> thirteen 13</div>
<div> fourteen 14</div>
</div>
<button id="prev" onclick="prevfun()">PREVIOUS 3</button>
<button id="next" onclick="nextfun()">NEXT 3</button>
I think this is a fairly elegant solution to your problem, but it seems you have some unnecessary code in your script, I've left it just in case you omitted some functionality.
var next = document.getElementById("next"),
list = document.getElementById("list"),
li = list.getElementsByTagName("DIV");
// not sure why you have this?
for (var i = 0; i < li.length; i++) {
li[i].style.display = "0px solid transparent";
}
// this can be achieved with only css
for (var i = 0; i < 3; i++) {
li[i].style.border = "1px solid red";
}
var min = 0;
var len = li.length;
var nextfun = function() {
min = min + 3;
max = ((min + 3) > len ? li.length : min + 3);
var decrement = ((min + 3) < len ? 3 : len - min);
if (min < len) {
// add borders
for (var i = min; i < max; i++) {
li[i].style.border = "1px solid red";
}
// remove borders
for (var i = min - 3; i < max - decrement; i++) {
li[i].style.border = "0";
}
}
}
One possible solution for this problem would be the snippet below:
var listItems = document.getElementById('list').getElementsByTagName("div");
var highlightedListItemPosition = 0;
highlightListItems();
function highlightNextThreeListItems() {
if (highlightedListItemPosition < listItems.length) {
highlightedListItemPosition += 3;
highlightListItems();
}
}
function highlighPreviusThreeListItems() {
if (highlightedListItemPosition > 0) {
highlightedListItemPosition -= 3;
highlightListItems();
}
}
function unhighlightAllListItems() {
for (var i = 0; i < listItems.length; i++) {
listItems[i].style.border = "0px solid transparent";
}
}
function highlightListItems() {
unhighlightAllListItems();
var loopLimit;
if ((listItems.length - highlightedListItemPosition) >= 3) {
loopLimit = highlightedListItemPosition + 3;
} else {
loopLimit = highlightedListItemPosition + listItems.length - highlightedListItemPosition;
}
for (var i = highlightedListItemPosition; i < loopLimit; i++) {
listItems[i].style.border = "1px solid red";
}
}
<div id="list">
<div> one 1</div>
<div> two 2</div>
<div> three 3</div>
<div> four 4</div>
<div> five 5</div>
<div> six 6</div>
<div> seven 7</div>
<div> eight 8</div>
<div> nine 9 </div>
<div> ten 10</div>
<div> eleven 11</div>
<div> twelve 12</div>
<div> thirteen 13</div>
<div> fourteen 14</div>
</div>
<button id="prev" onclick="highlighPreviusThreeListItems()">PREVIOUS 3</button>
<button id="next" onclick="highlightNextThreeListItems()">NEXT 3</button>
maybe something like this (though not perfect)
const buttons = document.getElementById("buttons");
const lis = Array.from(document.getElementById("list").children);
let Chunk = {
slicingIndices: {
start: 0,
end: 0
},
current: '',
prev: ''
};
const getNextChunk = () => {
let {
start, end
} = Chunk.slicingIndices;
[start, end] = [end, end + 3];
const saved = Chunk.current;
const newChunk = lis.slice(start, end);
if (newChunk.length !== 3) return saved;
Chunk.current = newChunk;
Chunk.slicingIndices = {
start, end
};
return Chunk.current;
};
const getPrevChunk = () => {
let {
start, end
} = Chunk.slicingIndices;
[start, end] = [start - 3, end - 3];
const saved = Chunk.prev;
const newChunk = lis.slice(start, end);
if (newChunk.length !== 3) return saved;
Chunk.prev = newChunk;
Chunk.slicingIndices = {
start, end
};
return Chunk.prev;
};
const colorChunk = chunk => (
chunk.forEach(item => item.style.backgroundColor = 'cornflowerblue')
);
// have not implemented this stuff, sorry
const disableBtn = btn => btn.disabled = true;
const enableBtn = btn => btn.disabled = false;
const resetColorForAllItems = () => (
lis.forEach(item => item.style.backgroundColor = '#eee')
);
buttons.addEventListener('click', (e) => {
let chunk = e.target && e.target.id == "next" ? getNextChunk() : getPrevChunk();
resetColorForAllItems();
colorChunk(chunk);
});
colorChunk(getNextChunk());
.container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
ul {
padding: 0;
background-color: #eee;
list-style: none;
}
<div class="container">
<ul id="list">
<li>one 1</li>
<li>two 2</li>
<li>three 3</li>
<li>four 4</li>
<li>five 5</li>
<li>six 6</li>
<li>seven 7</li>
<li>eight 8</li>
<li>nine 9</li>
<li>ten 10</li>
<li>eleven 11</li>
<li>twelve 12</li>
<li>thirteen 13</li>
<li>fourteen 14</li>
</ul>
<div id="buttons">
<button id="prev">PREVIOUS 3</button>
<button id="next">NEXT 3</button>
</div>
</div>