Jquery selector next element - javascript

Is there is a way to select every next element (nested or not) ?
Example :
<div class="div1">
<span class="span2">span1</span>
<div class="div2">
<span class="span2">span2</span>
</div>
<span id="current_span">current span></span>
<span class="span2">span3</span>
<div class="div2">
<span class="span2">span4</span>
</div>
</div>
I would like to do something like it :
$("#current_span").[select_every_next_item_with_span2_class].hide();
span3 / span4 hidden
And
$("#current_span").[select_every_prev_item_with_span2_class].show();
span1 / span2 visible

You could do this with jQuery's nextAll() and prevAll() functions.
For your code, this would be:
$("#current_span").nextAll().hide();
$("#current_span").prevAll().hide();
And as always, you can traverse the items in the list from the functions if you wish to do something separate with specific ones (i.e. use the each() function).
EDIT:
If you want to select the child elements of the siblings as well, you can do:
$("#current_span").nextAll().children().andSelf().hide();
This selects both the siblings and the children of the siblings.
I also added a code snippet to show you how this can work with your code. Click on currentspan1 to toggle the top two elements and currentspan2 to toggle the bottom two.
$("#current_span1").click(function(){
$(this).prevAll().toggle();
});
$("#current_span2").click(function(){
$(this).nextAll().toggle();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="div1">
<span class="span2">span1</span>
<div class="div2">
<span class="span2">span2</span>
</div>
<span id="current_span1">current span1</span> <br>
<span id="current_span2">current span2</span> <br>
<span class="span2">span3</span>
<div class="div2">
<span class="span2">span4</span>
</div>
</div>

You can use nextAll() to get all next siblings and then traverse each one for the elements you need.
$("#current_span").nextAll().each(function () {
if ($(this).is(".span2")) {
$(this).hide();
}
$(this).find(".span2").hide();
});
$("#current_span").prevAll().each(function () {
if ($(this).is(".span2")) {
$(this).show();
}
$(this).find(".span2").show();
});
Fiddle example https://jsfiddle.net/tq3ubLap/

To retrieve all the previous/next .span2 elements, regardless of their relationship to the current .span2 you could use index('.span2') to get their index within the scope of the document. From there you can use slice() to retrieve the required elements. Try this:
$('.span2').click(function() {
var $spans = $('.span2');
var index = $(this).index('.span2');
var $prev = $spans.slice(0, index);
var $next = $spans.slice(index + 1);
// for demo purposes only
$('.span2').removeClass('next prev');
$prev.addClass('prev');
$next.addClass('next');
});
.prev {
background-color: #C00;
color: #FFF;
}
.next {
background-color: #CC0;
color: #333;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="div1">
<span class="span2">span1</span>
<div class="div2">
<span class="span2">span2</span>
</div>
<span id="current_span">current span></span>
<span class="span2">span3</span>
<div class="div2">
<span class="span2">span4</span>
</div>
</div>

Related

How to access child of parent in jQuery

Trying to get the child of a parent through a child accessor. Basically trying to get the .block__id through the add__block class.
HTML
<div class="col-12">
<span class="block__id">{{$block->id}}</span>
{{$block->title}}
<span class="add__block">+</span>
</div>
jQuery
$(".add__block").click(function(){
$(this).parent().find(function(){
var id = $(".block__id").text();
});
console.log(id);
});
Currently I get id not defined.
Your logic is almost correct, but the issue is that you're providing a function to find() whereas you simply need to use a selector string:
$(".add__block").click(function() {
var id = $(this).parent().find(".block__id").text();
console.log(id);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-12">
<span class="block__id">Block #1</span>
Block title
<span class="add__block">+</span>
</div>
<div class="col-12">
<span class="block__id">Block #2</span>
Block title
<span class="add__block">+</span>
</div>
I'm not very familiar with jQuery, but with vanilla Javascript this is very easy:
const blocks = document.querySelectorAll('.add__block');
for (const block of blocks) {
block.addEventListener('click', (e) => {
console.log(e.target.previousElementSibling.textContent)
})
}
<div class="col-12">
<span class="block__id">{{$block->id}}</span>
{{$block->title}}
<span class="add__block">+</span>
</div>
Another alternative is just looking for the sibling with prev method, which might be slightly faster than going to parent and then search from there.
$('.add__block').click(function(){
var id = $(this).prev('.block__id').text();
console.log(id);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-12">
<span class="block__id">Block #1</span>
Block title
<span class="add__block">+</span>
</div>
<div class="col-12">
<span class="block__id">Block #2</span>
Block title
<span class="add__block">+</span>
</div>
Can you try like below:
$(".add__block").click(function(){
var id = $(".block__id").text();
console.log(id);
});
On click you can find the parent of the .add__block element and find the relevant .block__id within the parent as follows,
$(".add__block").click(function(){
console.log($(this).parent().find(".block__id").text(););
});
$('.add_block').prevAll('span')

Check for number of html element then run a function

I have three different scenario where the span element presents.
No child span element:
<div class="text" contenteditable="true" id="example">
<div class="outside">Type here</div>
</div>
One child span element:
<div class="text" contenteditable="true" id="example">
<div class="outside">Type here <span class="inside"> please.</span></div>
</div>
Multiple child span element with same class name
<div class="text" contenteditable="true" id="example">
<div class="outside">Type here<span class="inside"> please </span> thanks</div>
<div class="outside">Name <span class="inside"> please.</span> thanks.</div>
</div>
I want to run the following function:
var len = $('span.inside').get(0).nextSibling.length;
console.log(len);
Because the span class can be present once or multiple times, or not at all, I want to check for the presence of the span. Then based on the number of times the span element is there, I would need to run the function for all the span element.
How would I achieve this?
var length = $('span.inside').length;
if (length > 0) {
$('span.inside').each(function() {
var len = $(this).get(0).nextSibling.length;
console.log(len);
})
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="text" contenteditable="true" id="example">
<div class="outside">Type here<span class="inside"> please </span> thanks</div>
<div class="outside">Name <span class="inside"> please.</span> thanks.</div>
</div>
Use class and get length.
For many span use .each() to iterate over
I want to check for the presence of the span.
You can achieve this by checking the length property of the selector:
var $spans = $('span.inside');
var numberOfSpans = $spans.length;
Based on the number of times the span element is there, I would need to run the function for all the span element
This is a simple if statement, then you can use each() to loop over the elements in a selector:
if (numberOfSpans > 5) { // 5 just an example
$spans.each(function() {
// do something with the span here...
});
}

Removing sibling div when another span element contains specific text

I am trying to remove div with class=".basket__item-cell.basket__item-qty" only when hidden-sku is equal to "020-01119".
I've tried different approaches using .each(function) or .next() but could not get my head around it. In order to illustrate the example I've added the code bellow.
Please note that I can not add any id's or classes and the order of the rows may vary.
(function($) {
$('.hidden-sku').filter(function() {
return $(this).text().indexOf("020-01119") !== false;
}).closest(".basket__item-cell.basket__item-name").next(".basket__item-cell.basket__item-qty").remove();
})(jQuery)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="basket__item-data basket__item-data--right">
<div class="basket__item-cell basket__item-name">
<h2 class="product-name">One </h2>
<span class="hidden-sku">020-01119</span>
</div>
<div class="basket__item-cell basket__item-price">
<span class="cart-price"><span class="price"><span class="currency"></span>18</span>
</span>
</div>
<div class="basket__item-cell basket__item-qty">
<div class="input-combobox main-input-combobox input-combobox__with-qty" data-label="Qty" data-range-min="1" data-range-max="12">1
</div>
</div>
</div>
<div class="basket__item-data basket__item-data--right">
<div class="basket__item-cell basket__item-name">
<h2 class="product-name">Two </h2>
<span class="hidden-sku">020-01117</span>
</div>
<div class="basket__item-cell basket__item-price">
<span class="cart-price"><span class="price"><span class="currency"></span>18</span>
</span>
</div>
<div class="basket__item-cell basket__item-qty">
<div class="input-combobox main-input-combobox input-combobox__with-qty" data-label="Qty" data-range-min="1" data-range-max="12">2
</div>
</div>
</div>
<div class="basket__item-data basket__item-data--right">
<div class="basket__item-cell basket__item-name">
<h2 class="product-name">Three </h2>
<span class="hidden-sku">020-01118</span>
</div>
<div class="basket__item-cell basket__item-price">
<span class="cart-price"><span class="price"><span class="currency"></span>18</span>
</span>
</div>
<div class="basket__item-cell basket__item-qty">
<div class="input-combobox main-input-combobox input-combobox__with-qty" data-label="Qty" data-range-min="1" data-range-max="12">3
</div>
</div>
</div>
This will do the job and arguably it's easier to understand what it's doing at glance.
I am also assuming the SKU is always going to be 020-01119 and never just containing that string? If that's not the case just put the indexOf back into the if condition.
(function($) {
$('.basket__item-data').each(function () {
var sku = $('.hidden-sku', this);
if (sku.text() === '020-01119') {
$('.basket__item-cell.basket__item-qty', this).remove();
}
});
})(jQuery);
Watch out how you check the presence of string using indexOf():
(function($) {
$('.hidden-sku').filter(function() {
return $(this).text().indexOf("020-01119") > -1;
}).closest(".basket__item-cell.basket__item-name").next(".basket__item-cell.basket__item-qty").remove();
})(jQuery)
.closest(".basket__item-cell.basket__item-name")
.next(".basket__item-cell.basket__item-qty")
.remove();
.next() gets just the very next DOM node, then compares it with the class(es) you've specified.
In your case, you have -price between -name and -qty
<div class="basket__item-cell basket__item-name">
<div class="basket__item-cell basket__item-price">
<div class="basket__item-cell basket__item-qty">
so it gets -name, then the next, which is -price and says, is this -qty, which it isn't, so gives you no matches for .remove().
Here are some ideas to replace the .next():
// Use nextAll()
.closest(".basket__item-cell.basket__item-name")
.nextAll(".basket__item-cell.basket__item-qty")
.remove();
// Use nextAll().first() if you there might be more
.closest(".basket__item-cell.basket__item-name")
.nextAll(".basket__item-cell.basket__item-qty")
.first()
.remove();
// use .siblings
.closest(".basket__item-cell.basket__item-name")
.siblings(".basket__item-cell.basket__item-qty")
.remove();
// Go up to parent, then down
// Most likely to work if the structure changes
.closest(".basket__item-cell.basket__item-name")
.parent()
.find(".basket__item-cell.basket__item-qty")
.remove();
// Go up to parent in one step, then down
// Most likely to work if the structure changes
.closest(".basket__item-data")
.find(".basket__item-cell.basket__item-qty")
.remove();

jQuery for each identical parent div toggle nested divs if more than 3 using :nth-child

I have 2 identical parent divs with different content. If parent div has more than 3 child divs, at the end of the div should be displayed "show more" text that would slide all remaining hidden divs. I am new to JavaScript and jQuery and I couldn't completely understand selectors. Here is my code:
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
</div>
<span class="showhide">Show-hide</span>
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
</div>
<span class="showhide">Show-hide</span>
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>
<span class="showhide">Show-hide</span>
the result should display like this:
1
2
3
show-hide
1
2
1
2
3
show-hide
Here is the script:
$('.parent div:nth-child(n+4)').hide();
var l = $('.parent div').length;
if (l > 3) {
$('.showhide').show();
} else {
$('.showhide').hide();
}
$(".showhide").click(function() {
$this.find(".parent div:nth-child(n+4)").toggle('slide');
});
Only the first part of the code works. It hides divs more than 3 in each parent div. But the hiding text and toggle don't work.
I have tried multiple variations, like placing the span inside parent div, changing selectors to .closest, also tried to use :gt() instead of :nth-child but none worked.
You can do like this,
$(".parent").each(function() {
$(this).find(".child:gt(2)").hide();
});
$(".showhide").click(function() {
$(this).prev().find(".child:gt(2)").slideToggle();
});
Fiddle
.gt() selector will return the elements whose index is greater than the specified parameter
If you want to change the text after toggling, use this code,
$(".parent").each(function() {
$(this).find(".child:gt(2)").hide();
});
$(".showhide").click(function() {
var obj = this;
$(this).prev().find(".child:gt(2)").slideToggle(function() {
if ($(this).is(":visible"))
$(obj).text("hide");
else
$(obj).text("show more");
});
});
Edited Fiddle
Note that, you need to use the call back function of slideToggle to change the text, since slideToggle is asynchronous.
Final Fiddle
You can hide it with css:
.parent div:nth-child(n+4) {
display: none;
}
and use jquery to toggle the class to make it visible/hidden.
$('.parent').filter(function(){
return $(this).children().length <= 2;
}).next('.showhide').hide();
$('.showhide').click(function() {
$(this).text(function(i, txt) {
console.log(txt);
return txt === "Show" ? "Hide" : "Show";
});
$(this).prev('.parent').find('div:hidden, div.show').toggleClass('show').stop().slideToggle();
});
span {
cursor: pointer;
}
.parent div:nth-child(n+4) {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
</div>
<span class="showhide">Show</span>
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
</div>
<span class="showhide">Show</span>
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>
<span class="showhide">Show</span>

Javascript:: Select sibling(s) object(s) with querySelector

Title is pretty much self explanatory...
Here is my code :
<div id=player>
<div class="button hand">►</div>
<div class=time>00:00/00:00</div>
<div class="timeline hand"><span class="now hand"></span></div>
</div>
I want to be able to get the <span class="now hand"></span> which is in between <div class="timeline hand"></div> via querySelector
var now=document.querySelector('#player>_____________.now.hand');
I'm also thinking if there is more convenient way to pick object from the relative id by children(s) or sibling(s) number instead of using id or class name.
You use a standard descendant selector (a space between #player and .now.hand):
var text = document.querySelector("#player .now.hand").innerHTML;
var p = document.createElement('p');
p.innerHTML = "Text is '" + text + "'";
document.body.appendChild(p);
<div id=player>
<div class="button hand">►</div>
<div class=time>00:00/00:00</div>
<div class="timeline hand"><span class="now hand">text in now hand</span></div>
</div>
I'm also thinking if there is more convenient way to pick object from the relative id by children(s) or sibling(s) number instead of using id or class name.
If this is in an event handler (or anywhere else you start out with a reference to some element), yes, you can use parentNode to find a parent (or repeatedly to find an ancestor), you can use querySelector on an element to only look within it, etc.
So for example:
document.body.addEventListener("click", function(e) {
var targetClass = e.target.className;
if (/\bbutton\b/.test(targetClass) && /\bhand\b/.test(targetClass)) {
alert(e.target.parentNode.querySelector(".now.hand").innerHTML);
}
}, false);
.button.hand {
color: blue;
font-weight: bold;
}
.now.hand {
color: green;
}
<div>
<div class="button hand">Click me</div>
<div class=time>00:00/00:00</div>
<div class="timeline hand"><span class="now hand">First hand</span></div>
</div>
<div>
<div class="button hand">Click me</div>
<div class=time>00:00/00:00</div>
<div class="timeline hand"><span class="now hand">Second hand</span></div>
</div>
<div>
<div class="button hand">Click me</div>
<div class=time>00:00/00:00</div>
<div class="timeline hand"><span class="now hand">Third hand</span></div>
</div>
Your span does not have any siblings. The easiest way to select it here would be document.querySelector('.now.hand') (Did you mean to apply two classes to the span? If not, connect them w/ a hyphen to use one class)
If you want to specify the span that is a descendant of the player, this would work:
js
document.querySelector('#player span.now.hand')
Learning to use CSS selectors will help here.

Categories

Resources