Select every first unique element by grouping - javascript

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>

Related

Using Xpath how to select multiple parent classes of an element that has a specific innerText?

Using Puppeteer I need to select the hour and the minutes to schedule a post from a widget
The HTML code of the widget is this:
<div class="vdatetime-time-picker">
<div class="vdatetime-time-picker__list vdatetime-time-picker__list--hours">
<div class="vdatetime-time-picker__item vdatetime-time-picker__item--selected">00</div>
<div class="vdatetime-time-picker__item">01</div>
<div class="vdatetime-time-picker__item">02</div>
<div class="vdatetime-time-picker__item">03</div>
<div class="vdatetime-time-picker__item">04</div>
<div class="vdatetime-time-picker__item">05</div>
<div class="vdatetime-time-picker__item">06</div>
<div class="vdatetime-time-picker__item">07</div>
<div class="vdatetime-time-picker__item">08</div>
<div class="vdatetime-time-picker__item">09</div>
<div class="vdatetime-time-picker__item">10</div>
<div class="vdatetime-time-picker__item">11</div>
<div class="vdatetime-time-picker__item">12</div>
<div class="vdatetime-time-picker__item">13</div>
<div class="vdatetime-time-picker__item">14</div>
<div class="vdatetime-time-picker__item">15</div>
<div class="vdatetime-time-picker__item">16</div>
<div class="vdatetime-time-picker__item">17</div>
<div class="vdatetime-time-picker__item">18</div>
<div class="vdatetime-time-picker__item">19</div>
<div class="vdatetime-time-picker__item">20</div>
<div class="vdatetime-time-picker__item">21</div>
<div class="vdatetime-time-picker__item">22</div>
<div class="vdatetime-time-picker__item">23</div>
</div>
<div class="vdatetime-time-picker__list vdatetime-time-picker__list--minutes">
<div class="vdatetime-time-picker__item">00</div>
<div class="vdatetime-time-picker__item">05</div>
<div class="vdatetime-time-picker__item">10</div>
<div class="vdatetime-time-picker__item">15</div>
<div class="vdatetime-time-picker__item">20</div>
<div class="vdatetime-time-picker__item">25</div>
<div class="vdatetime-time-picker__item">30</div>
<div class="vdatetime-time-picker__item">35</div>
<div class="vdatetime-time-picker__item vdatetime-time-picker__item--selected">40</div>
<div class="vdatetime-time-picker__item">45</div>
<div class="vdatetime-time-picker__item">50</div>
<div class="vdatetime-time-picker__item">55</div>
</div>
</div>
Let's say I need to select 15:15.
I know with Xpath I can select the inner text with
const xpathHour = "//div[text()='15']";
the problem is that when selecting the minutes, being a multiple of 5, it would select the hour (again) because is the first element Puppeteer would find with the text of 15.
Their parent elements are different so how can I get in Xpath the same result as this one?
document.querySelector('.vdatetime-time-picker__list--hours .vdatetime-time-picker__item').innerText === "15"
You're probably looking for:
const xpathMinute = "(//div[text()='15'])[2]";
That is the second div with "15" text.
() are important, because [] operator has higher precedence.

jQuery .after function for several elements

How to use "after" for several elements?
Initial position:
<div id="parent_div">
<div id="smth">data0</div>
<div id="this_to_move">data1</div>
<div id="this_to_move">data2</div>
<div id="this_to_move">data3</div>
<div id="smth">data4</div>
<div id="this_element_to_use">data5</div>
<div id="smth">data6</div>
</div>
The resultant:
<div id="parent_div">
<div id="smth">data0</div>
<div id="smth">data4</div>
<div id="this_element_to_use">data5</div>
<div id="this_to_move">data1</div>
<div id="this_to_move">data2</div>
<div id="this_to_move">data3</div>
<div id="smth">data6</div>
</div>
What is the most elegant way to do it using jQuery?
You need to switch to classes instead of ids as you won't be able to do something this way otherwise (ids should be unique to an element):
$('.this_to_move').insertAfter('.this_element_to_use');
Fiddle: https://jsfiddle.net/sLonnLqz/

Wrap two divs with different class

I've these divs
<div class="col_1_6"></div>
<div class="col_1_4"></div>
<div class="col_1_6"></div>
<div class="col_1_4"></div>
<div class="col_1_4"></div>
<div class="col_1_6"></div>
I want whatever the order of the divs, wrap col_1_4 and col_1_6 in a div called row_content
<div class="row_content">
<div class="col_1_6"></div>
<div class="col_1_4"></div>
</div>
<div class="row_content">
<div class="col_1_4"></div>
<div class="col_1_6"></div>
</div>
I already try this :
$('.col_1_6, .col_1_4').wrapAll('<div class="row"></div>')
But it wrap all the divs not each two divs.
Thanks for the help.
You can select all your divs and then do a for loop that increment by 2 every iteration.
With the index of the loop, you can then use .slice on the jQuery element and that wrap your divs.
var $divs = $('.col_1_6, .col_1_4');
for(var i = 0; i < $divs.length; i+=2){
$divs.slice(i, i+2).wrapAll('<div class="row"></div>');
console.log($divs);
}
.row{
background: red;
margin : 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="col_1_6">1</div>
<div class="col_1_4">2</div>
<div class="col_1_6">3</div>
<div class="col_1_4">4</div>
<div class="col_1_4">5</div>
<div class="col_1_6">6</div>
I've found this method which works
$(".col_1_6").each(function(index) {
$(this).next(".col_1_4").andSelf().wrapAll("<div class='row' />")
});
but this only work if all div are in this order .col_1_6 > .col_1_4 and not .col_1_4 > col_1_6 as in your html
http://jsfiddle.net/mrjx9dav/11/
Another not-so-pretty solution that wraps every 2 divs that has the class starting with col_1.
$('div[class^="col_1"]').each(function(ind) {
ind%2 === 0 && ($(this).add($(this).next()).wrapAll('<div class="row"></div>'));
});
-Demo-

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/

Is there a way to wrapAll() but ignore one element?

If you have the following code:
<div class="parent">
<div class="1"></div>
<div class="2"></div>
<div class="3"></div>
<div class="4"></div>
<div class="5"></div>
</div>
How can I wrap a new div around div with class 2,3,4,5 so it looks like this:
<div class="parent">
<div class="1"></div>
<div class="sub">
<div class="2"></div>
<div class="3"></div>
<div class="4"></div>
<div class="5"></div>
</div>
</div>
wrapAll on the parent would wrap everything with a new div, is there a way to make it ignore the first div?
Use gt(0) to select all but the first one div(direct descendant) and wrapAll. This will select all divs with index greater than 0 present under .parent div.
$('.parent > div:gt(0)').wrapAll('<div class="sub">');
Fiddle
See :gt()
Output:
<div class="parent">
<div class="1">1</div>
<div class="sub">
<div class="2">2</div>
<div class="3">3</div>
<div class="4">4</div>
<div class="5">5</div>
</div>
</div>
Use the not() filter or the :not() selector.
$('.parent div').not('.1').wrapAll('<div class="sub">');
Or alternatively:
$('.parent div:not(.1)').wrapAll('<div class="sub">');
You can also use div:first-child in place of .1 if you always want to ignore the first element.
If the element you want to keep out is not necessarily the first, you could use:
$(".parent div").not("div.1").wrapAll("<div class='sub'>");
Although, this will re-order your divs so that the wrap comes first, and the unwrapped element comes last. Not a problem when it's the first element, but if it's the third, for example, the output would be:
<div class='sub'>
<div class="1"></div>
<div class="2"></div>
<div class="4"></div>
<div class="5"></div>
</div>
<div class="3"></div>
Example:
http://jsfiddle.net/tomtheman5/3TL4M/
edit: Just saw #Corion's answer... This is essentially the same, but with some more information. I'll leave it up.

Categories