How to get div elements between a range of numbers? - javascript

I want to get elements between a range of numbers, let's say between 10 and 15 from these:
<div class="1">....</div>
<div class="2">....</div>
<div class="3">....</div>
...
...
...
<div class="20">....</div>
Desired Output:
<div class="10">....</div>
<div class="11">....</div>
<div class="12">....</div>
<div class="13">....</div>
<div class="14">....</div>
<div class="15">....</div>

While the JS solution is probably better, mainly because it's more flexible, I want to mention the CSS solution, even though it has more limitations.
#parent {
display: inline-block;
}
div {
border: 1px solid #333;
padding: 5px;
}
div div {
width: 50px;
}
div:nth-child(n+10):nth-child(-n+15) { /* From the 10th child up to the 15th child */
background-color: green;
}
<div id="parent">
<div>01</div>
<div>02</div>
<div>03</div>
<div>04</div>
<div>05</div>
<div>06</div>
<div>07</div>
<div>08</div>
<div>09</div>
<div>10</div>
<div>11</div>
<div>12</div>
<div>13</div>
<div>14</div>
<div>15</div>
<div>16</div>
<div>17</div>
<div>18</div>
<div>19</div>
<div>20</div>
</div>
By combining two nth-child selectors you can specify a range of elements.
You can use this selector in JS as well
document.querySelectorAll('div:nth-child(n+10):nth-child(-n+15)');
The downside is that it will work well only if all the elements are siblings and the only children of the parent element.

Just use slice will be sufficient.
[...document.getElementsByTagName("div")].slice(10,5)

[...document.querySelectorAll('div')]
.filter((e) => Number(e.classList.value) >= 10)
.filter((e) => Number(e.classList.value) <= 15)
.map((e) => console.log(e.outerHTML))
// <div class="10">....</div>
// <div class="11">....</div>
// <div class="12">....</div>
// <div class="13">....</div>
// <div class="14">....</div>
// <div class="15">....</div>

The following example only works with this specific case where the classes are numbered. This is not a common scenario. Most would use unique IDs and then common Classes for grouping.
$(function() {
function selectBetween(start, finish) {
var selects = [];
for (start; start <= finish; start++) {
selects.push("." + start);
}
return $(selects.join(", "));
}
var myDivs = selectBetween(10, 15);
console.log(myDivs.length);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="1">....</div>
<div class="2">....</div>
<div class="3">....</div>
<div class="4">....</div>
<div class="5">....</div>
<div class="6">....</div>
<div class="7">....</div>
<div class="8">....</div>
<div class="9">....</div>
<div class="10">....</div>
<div class="11">....</div>
<div class="12">....</div>
<div class="13">....</div>
<div class="14">....</div>
<div class="15">....</div>
<div class="16">....</div>
<div class="17">....</div>
<div class="18">....</div>
<div class="19">....</div>
<div class="20">....</div>
Console will show 6.

Just map over an array of length of a number of elements required and use getElementsByClassName method to get the required elements between the range.
const getElements = (min, max) => {
// construct an array of length of number of elements b/w min & max
// and then map the required elements with the className selector
return [...new Array((max - min) + 1)]
.map((_, index) => document.getElementsByClassName(index + min));
}
console.log(getElements(10, 15));
<div class="0">0</div>
<div class="1">1</div>
<div class="2">2</div>
<div class="3">3</div>
<div class="4">4</div>
<div class="5">5</div>
<div class="6">6</div>
<div class="7">7</div>
<div class="8">8</div>
<div class="9">9</div>
<div class="10">10</div>
<div class="11">11</div>
<div class="12">12</div>
<div class="13">13</div>
<div class="14">14</div>
<div class="15">15</div>
<div class="16">16</div>
<div class="17">17</div>
<div class="18">18</div>
<div class="19">19</div>
<div class="20">20</div>

In order to get required output, first I would fetch all divs on the page,
convert resulting nodelist into arrays so that I can apply arrays' filter
method and then I would populate another div with outer HTML of the filtered
arrays.
Here, I have created an arrow function which does filtering using parameters
to make filter reusable. The code reads as under:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Get Div Elements from n number to n number</title>
<script>
window.onload = ()=>{
// get all divs on this page
let allDivs = document.querySelectorAll('div')
// arrow function to get required divs where
// start is int, stop is int and divs is nodelist
const getDivsBetween = (start, stop, divs)=>{
// convert nodelist to JavaScript array
let theDivs = Array.from(divs)
// filter the array
let retVal = theDivs.filter((element)=>{
// convert className to integer for checking
// whether className is between the values
let className = parseInt(element.className)
// return selected element
if (className >= start && className <=stop) return element
})
return retVal // return array containing filtered elements
}
// get required divs
let outPutDivs = getDivsBetween(10, 15, allDivs)
// get div where output will go
let theOutputDiv = document.getElementById('output')
// populate output div with filtered divs outer html
// to get required output
outPutDivs.map((element)=>{
let thisDiv = document.createElement('div')
thisDiv.append(element.outerHTML)
theOutputDiv.append(thisDiv)
})
}
</script>
</head>
<body>
<div>Here are original divs</div>
<div id="originals">
<div class="1">....</div>
<div class="2">....</div>
<div class="3">....</div>
<div class="4">....</div>
<div class="5">....</div>
<div class="6">....</div>
<div class="7">....</div>
<div class="8">....</div>
<div class="9">....</div>
<div class="10">....</div>
<div class="11">....</div>
<div class="12">....</div>
<div class="13">....</div>
<div class="14">....</div>
<div class="15">....</div>
<div class="16">....</div>
<div class="17">....</div>
<div class="18">....</div>
<div class="19">....</div>
<div class="20">....</div>
</div>
<hr>
<div>Here is required output</div>
<div id="output"></div>
</body>
</html>

Related

How to reorder elements by JavaScript

Let's say I got 6 divs, and their current order is 1 to 6, how do I reorder them to make it become 612345?
I've tried to store them into a variable and use getElementsByClassName, then use the slice method and the insertAdjacentElement method but it couldn't work...
const btn = document.querySelector('.reorder');
const elm = document.getElementsByClassName('items');
const lastIndexOfElm = elm.length -1
function reorder() {
let newElm = [...elm].slice(0, lastIndexOfElm);
elm[lastIndexOfElm].insertAdjacentElement('afterend', newElm);
}
btn.addEventListener('click', reorder)
<button class="reorder">Reorder</button>
<div class="items">1</div>
<div class="items">2</div>
<div class="items">3</div>
<div class="items">4</div>
<div class="items">5</div>
<div class="items">6</div>
if you want to move the last item of ".items" to the first item, this code may help you.
const btn = document.querySelector('.reorder');
const elm = document.getElementsByClassName('items');
const lastIndexOfElm = elm.length -1
function reorder() {
let lastElm = elm[lastIndexOfElm];
elm[lastIndexOfElm].remove();
document.body.insertBefore(lastElm, elm[0]);
}
btn.addEventListener('click', reorder)
<button class="reorder">Reorder</button>
<div class="items">1</div>
<div class="items">2</div>
<div class="items">3</div>
<div class="items">4</div>
<div class="items">5</div>
<div class="items">6</div>
It may or may not work for your situation, but another possibility is putting them all in a flexbox and using the CSS order property to change the ordering:
<div style="display: flex;">
<div style="order: -1">1</div> <!-- first -->
<div style="order: 10">2</div> <!-- last -->
<div>3</div>
<div>4</div>
</div>
Then in Javascript you only need to adjust the CSS style's order property to change the ordering dynamically.

Remove elements with same data-id

I have a pattern like that:
<section>
<div data-id="39"></div>
<div data-id="31"></div>
<div data-id="57"></div>
<div data-id="10"></div>
<div data-id="27"></div>
<div data-id="5"></div>
<div data-id="89"></div>
</section>
That contains some data that are live updated via AJAX. Sometimes, it may happen to receive from the server a data updated with the same id of another one in the section, and since it's the same id, I need to remove the old data to avoid multiple datas and keep just the updated one.
For example, I receive an update with data-id 27 and I insert at the top:
<section>
<div data-id="27"></div>
<div data-id="39"></div>
<div data-id="31"></div>
<div data-id="57"></div>
<div data-id="10"></div>
<div data-id="27"></div>
<div data-id="5"></div>
<div data-id="89"></div>
</section>
After inserted it, how can I do a check that if 27 is already available in the section (so the last iteration), remove it from the section? Basically removing all the data with the same id and keep just the one at the top.
Not very inspired at the moment but with the amount of info you game us i made this example with jquery. It can be done also just with plain javaScript if needed
$('div').each(function() {
dataId = $(this).data('id');
otherDataId = $(this).siblings().data('id');
if (otherDataId === dataId) {
$(this).hide()
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section>
<div data-id="27">27</div>
<div data-id="39">1</div>
<div data-id="31">2</div>
<div data-id="57">3</div>
<div data-id="10">4</div>
<div data-id="27">27</div>
<div data-id="5">5</div>
<div data-id="89">6</div>
</section>
You could also try creating a function to remove the element with the specific data-id value you want like this:
const removeItems = (number) => {
let elements = document.querySelectorAll(`div[data-id="${number}"]`);
elements.forEach((e) => { e.remove() });
};
And then to remove elements with data-id=27 you can do: removeItems(27);.
Take a look:
const removeItems = (number) => {
let elements = document.querySelectorAll(`div[data-id="${number}"]`);
elements.forEach((e) => { e.remove() });
};
removeItems(27);
<section>
<div data-id="27">27</div>
<div data-id="39">39</div>
<div data-id="31">31</div>
<div data-id="57">57</div>
<div data-id="10">10</div>
<div data-id="27">27</div>
<div data-id="5">5</div>
<div data-id="89">89</div>
</section>
document.querySelector(`[data-id=${myDataId}]`).remove();

Sort nested divs alphabetically

I have the following div layout:
<div class="container">
<div class="entry">
<div class="title">World</div>
<div class="description">text1</div>
</div>
<div class="entry">
<div class="title">hello</div>
<div class="description">text2</div>
</div>
<div class="entry">
<div class="title">Lorem</div>
<div class="description">text3</div>
</div>
</div>
I want to sort the entry divs alphabetically by the content of the child title div.
What I've tried so far
This will sort it alphabetically:
var alphabeticallyOrderedDivs = $('.title').sort(function(a, b) {
return String.prototype.localeCompare.call($(a).text().toLowerCase(), $(b).text().toLowerCase());
});
var container = $(".container");
container.detach().empty().append(alphabeticallyOrderedDivs);
$('body').append(container);
But it will strip the description divs. Try jsFiddle demo.
How can I sort the divs alphabetically without stripping anything?
Your logic is correct, but the issue is you're sorting the .title elements. Instead you need to sort the .entry elements, and then find the .title within the current .entry and perform the comparison on their text values. Try this:
var alphabeticallyOrderedDivs = $('.entry').sort(function(a, b) {
var $aTitle = $(a).find('.title'), $bTitle = $(b).find('.title');
return String.prototype.localeCompare.call($aTitle.text().toLowerCase(), $bTitle.text().toLowerCase());
});
var container = $(".container");
container.detach().empty().append(alphabeticallyOrderedDivs);
$('body').append(container);
.entry {
border: 1px solid #CCC;
padding: 5px;
margin: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<div class="container">
<div class="entry">
<div class="title">World</div>
<div class="description">text1</div>
</div>
<div class="entry">
<div class="title">hello</div>
<div class="description">text2</div>
</div>
<div class="entry">
<div class="title">Lorem</div>
<div class="description">text3</div>
</div>
</div>
How can I sort the divs alphabetically without stripping anything?
By sorting the right elements?
Why are you sorting .title, if as you stated the .entry elements are what you actually want to sort?
var alphabeticallyOrderedDivs = $('.entry').sort(function(a, b) {
return String.prototype.localeCompare.call(
$(a).find('.title').text().toLowerCase(),
$(b).find('.title').text().toLowerCase());
});
http://jsfiddle.net/yapu9a6m/1/
You just have to take the parent element with you when you sort. Then you go searching the child element after which you want to sort:
var alphabeticallyOrderedDivs = $('.entry').sort(function(a, b) {
return String.prototype.localeCompare.call($(a).find("div.title").text().toLowerCase(), $(b).find("div.title").text().toLowerCase());
});
You're sorting the titles, you should be sorting the entries.
So 1 tiny change:
var alphabeticallyOrderedDivs = $('.entry').sort(function(a, b) {
return String.prototype.localeCompare.call($(a).text().toLowerCase(), $(b).text().toLowerCase());
});
See updated fiddle

Select every first unique element by grouping

I have a list of elements which have alternating classes. The occurrences of the classes are random and can occur once or many times in a row.
I am looking a way to select every first occurrence of an element (marked with a -). Preferably, I'd like to do this in CSS but I can work with a JavaScript solution as well.
<div class="type-1"></div> -
<div class="type-1"></div>
<div class="type-1"></div>
<div class="type-2"></div> -
<div class="type-1"></div> -
<div class="type-1"></div>
<div class="type-2"></div> -
<div class="type-2"></div>
<div class="type-1"></div> -
...
Just like this: https://jsfiddle.net/aq8nw21f/
This code uses the CSS adjacent sibling selector, as well as :first-of-type to get the edge case of the first item in the list.
#container > div:first-of-type, .type-1 + .type-2, .type-2 + .type-1 {
color: red;
}
<div id="container">
<span>If you used :first-child, the div below this would not highlight.</span>
<div class="type-1">Yes</div>
<div class="type-1">No</div>
<div class="type-1">No</div>
<div class="type-2">Yes</div>
<div class="type-1">Yes</div>
<div class="type-1">No</div>
<div class="type-2">Yes</div>
<div class="type-2">No</div>
<div class="type-1">Yes</div>
</div>
And a less spectacular JS solution than the CSS one of TW80000:
var els = Array.from(document.querySelectorAll('div[class^="type-"]'));
console.log(els.filter(function(el, index) {
return index === 0 || !el.classList.contains(els[index - 1].classList.item(0));
}));
<div class="type-1">1</div>
<div class="type-1">2</div>
<div class="type-1">3</div>
<div class="type-2">4</div>
<div class="type-1">5</div>
<div class="type-1">6</div>
<div class="type-2">7</div>
<div class="type-2">8</div>
<div class="type-1">9</div>

wrap more than one nodes with div

How can i wrap exactly half of the div's with another div using jquery or javascript
I have this
<div class="post">1</div>
<div class="post">2</div>
<div class="post">3</div>
<div class="post">4</div>
<div class="post">5</div>
<div class="post">6</div>
I want this
<div class="wrap">
<div class="post">1</div>
<div class="post">2</div>
<div class="post">3</div>
</div>
<div class="wrap">
<div class="post">4</div>
<div class="post">5</div>
<div class="post">6</div>
</div>
Try using this:
var posts = $('.post'),
postCount = posts.length,
postHalf = Math.round(postCount/2),
wrapHTML = '<div class="wrap"></div>';
posts.slice(0, postHalf).wrapAll(wrapHTML); // .slice(0, 3)
posts.slice(postHalf, postCount).wrapAll(wrapHTML); // .slice(3, 6)
This selects all .post, gets the number of elements found then halves that value to get the splitting point. It then uses .slice() to select a specific range of elements and .wrapAll() to wrap each selection in <div class="wrap"></div>.
Here it is working: http://jsfiddle.net/ekzrb/

Categories