Removing sibling div when another span element contains specific text - javascript

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();

Related

Remove next element using jQuery

I have the below HTML
<div name="taskNotificationsDiv">
<div class="notificationCard">
<span class="taskNotificationClose">x</span>
Test
</div>
<hr>
<div class="notificationCard">
<span class="taskNotificationClose">x</span>
Test
</div>
<hr>
<div class="notificationCard">
<span class="taskNotificationClose">x</span>
Test
</div>
<hr>
</div>
And I have the below script which when x is clicked removes the container from the parent.
$(".taskNotificationClose").click(function (){
this.parentNode.parentNode
.removeChild(this.parentNode);
return false;
});
What I am looking for is also removing the hr which is below the div container..Can someone please have a look and let me know how it can be done.
Here's the fiddle [Fiddle][1]
I tried with the below code to find nearest hr and remove it from the parent but it's throwing an error
var $hr = $(this).next('hr');
this.parentNode.parentNode.removeChild($hr);
Thanks
[1]: https://jsfiddle.net/so3k2hpq/
You can use .next() function. A better approach to solve the problem with JQuery:
$(".taskNotificationClose").click(function (){
$(this).parent().next("hr").remove();
$(this).parent().remove();
return false;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div name="taskNotificationsDiv">
<div class="notificationCard" style="color:red;">
<span class="taskNotificationClose">x</span>
Test
</div>
<hr>
<div class="notificationCard" style="color:blue;">
<span class="taskNotificationClose">x</span>
Test
</div>
<hr>
<div class="notificationCard" style="color:green;">
<span class="taskNotificationClose">x</span>
Test
</div>
<hr>
</div>
You can move 'hr' tag inside each div. It will solve your problem.
JQuery .next(element) can do this
$(".taskNotificationClose").click(function (){
$(this).parent().next("hr").remove();
$(this).parent().remove();
return false;
});
The reason for your earlier error, is that you removed the first sibling first before calling .next()

Link simillary name classes so that when one is clicked the other is given a class

Basically, I'm asking for a way to optimize this code. I'd like to cut it down to a few lines because it does the same thing for every click bind.
$("#arch-of-triumph-button").click(function(){
$("#arch-of-triumph-info").addClass("active-info")
});
$("#romanian-athenaeum-button").click(function(){
$("#romanian-athenaeum-info").addClass("active-info")
});
$("#palace-of-parliament-button").click(function(){
$("#palace-of-parliament-info").addClass("active-info")
});
Is there a way to maybe store "arch-of-triumph", "romanian-athenaeum", "palace-of-parliament" into an array and pull them out into a click bind? I'm thinking some concatenation maybe?
$("+landmarkName+-button").click(function(){
$("+landmarkName+-info").addClass("active-info")
});
Is something like this even possible?
Thanks in advance for all your answers.
EDIT: Here's the full HTML.
<div class="landmark-wrapper">
<div class="page-content landmark">
<div class="heading span-after">
<span>Arch of Triumph</span>
</div>
<div class="landmark-button" id="arch-of-triumph-button"></div>
</div>
</div>
<div class="landmark-wrapper">
<div class="page-content landmark">
<div class="heading span-after">
<span>Romanian Athenaeum</span>
</div>
<div class="landmark-button" id="romanian-athenaeum-button"></div>
</div>
</div>
----------------------------------------------------------
<div class="landmarks-info-wrapper">
<div class="landmark-info" id="arch-of-triumph-info">
<div class="info-landmark section">
<span class="landmark-title">Arch of Triumph</span>
<span class="landmark-coord">44°28′1.99″N 26°4′41.06″E</span>
</div>
</div>
<div class="landmark-info" id="romanian-athenaeum-info">
<div class="info-landmark section">
<span class="landmark-title">The Romanian Athenaeum</span>
<span class="landmark-coord">44.4413°N 26.0973°E</span>
</div>
</div>
Assuming you're not able to modify your HTML markup (in which case with use of CSS classes would be cleaner), a solution to your question would be as shown below:
// Assign same click handler to all buttons
$("#arch-of-triumph-button, #romanian-athenaeum-button, #palace-of-parliament-button")
.click(function() {
// Extract id of clicked button
const id = $(this).attr("id");
// Obtain corresponding info selector from clicked button id by replacing
// last occurrence of "button" pattern with info.
const infoSelector = "#" + id.replace(/button$/gi, "info");
// Add active-info class to selected info element
$(infoSelector).addClass("active-info");
});
Because each .landmark-button looks to be in the same order as its related .landmark-info, you can put both collections into an array, and then when one is clicked, just find the element with the same index in the other array:
const buttons = [...$('.landmark-button')];
const infos = [...$('.landmark-info')];
$(".landmark-button").click(function() {
const i = buttons.indexOf(this);
$(infos[i]).addClass('active-info');
});
This does not rely on IDs at all - feel free to completely remove those from your HTML to declutter, because they don't serve any purpose now that they aren't being used as selectors.
Live snippet:
const buttons = [...$('.landmark-button')];
const infos = [...$('.landmark-info')];
$(".landmark-button").click(function() {
const i = buttons.indexOf(this);
$(infos[i]).addClass('active-info');
});
.active-info {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="landmark-wrapper">
<div class="page-content landmark">
<div class="heading span-after">
<span>Arch of Triumph</span>
</div>
<div class="landmark-button" id="arch-of-triumph-button">click</div>
</div>
</div>
<div class="landmark-wrapper">
<div class="page-content landmark">
<div class="heading span-after">
<span>Romanian Athenaeum</span>
</div>
<div class="landmark-button" id="romanian-athenaeum-button">click</div>
</div>
</div>
----------------------------------------------------------
<div class="landmarks-info-wrapper">
<div class="landmark-info" id="arch-of-triumph-info">
<div class="info-landmark section">
<span class="landmark-title">Arch of Triumph</span>
<span class="landmark-coord">44°28′1.99″N 26°4′41.06″E</span>
</div>
</div>
<div class="landmark-info" id="romanian-athenaeum-info">
<div class="info-landmark section">
<span class="landmark-title">The Romanian Athenaeum</span>
<span class="landmark-coord">44.4413°N 26.0973°E</span>
</div>
</div>
Older answer, without knowing the HTML: You can extract the ID of the clicked button, slice off the button part of it, and then select it concatenated with -info:
$(".landmark-button").click(function() {
const infoSel = this.id.slice(0, this.id.length - 6) + 'info';
$(infoSel).addClass('active-info');
});
A much more elegant solution would probably be possible given the HTML, though.

Using class tree to delete specific HTML elements

How can I use vanilla JS to find and delete elements with a specific class X where the parent has class Y?
Example. Given
<div class="likes noise1">
<div class="count noise2">
42
</div>
</div>
<div class="retweets noise3">
<div class="count noise4">
7
</div>
</div>
<div class="messages noise5">
<div class="count noise6">
2
</div>
</div>
I would like to delete the first two ".count" elements (the childs of ".likes" and ".retweets"). The messages div however should be left untouched.
I have tried using querySelectorAll which return a frozen NodeList and iterating it, without success.
You can loop through all the elements to check the Element.className property of the Node.parentNode to remove the element like the following way:
document.querySelectorAll('.count').forEach(function(el){
var classN = el.parentNode.className
if(classN.includes('likes') || classN.includes('retweets'))
el.remove();
});
<div class="likes">
<div class="count">
42
</div>
</div>
<div class="retweets">
<div class="count">
7
</div>
</div>
<div class="messages">
<div class="count">
2
</div>
</div>
OR: You can simply simply specify both the classes as part of the selector, in which case you do not need to check the parentNode as the selector will give you only the elements inside the parents:
document.querySelectorAll('.likes > .count, .retweets > .count').forEach(function(el){
el.parentNode.remove();
});
<div class="likes">
<div class="count">
42
</div>
</div>
<div class="retweets">
<div class="count">
7
</div>
</div>
<div class="messages">
<div class="count">
2
</div>
</div>
Another alternative, further to those already given is to keep an array of the css selector you'll need to find your targets. From there, it's just a simple matter of using querySelector so that the result is still live, albeit in a loop.
"use strict";
function byId(id){return document.getElementById(id)}
window.addEventListener('load', onWindowLoaded, false);
function onWindowLoaded(evt)
{
var tgtSelectors = [ '.likes > .count', '.retweets > .count' ];
tgtSelectors.forEach(removeBySelector);
}
function removeBySelector(curSelector)
{
var tgt = document.querySelector(curSelector);
while (tgt != undefined)
{
tgt.remove();
tgt = document.querySelector(curSelector);
}
}
<div class="likes">
<div class="count">42</div>
</div>
<div class="retweets">
<div class="count">7</div>
</div>
<div class="messages">
<div class="count">2</div>
</div>

How to check if inner <div> has text

what I'm trying to do is to check if my inner <div> has a text for example Ended and then remove if it has a text. I have multiple <div> with the same class name. I tried using .filter(). I would like to remove the div container_one that contains the found element.
Here is my HTML:
var $filstatus = $('.status').filter(function() {
return $(this).text() == 'Ended';
});
$filstatus.remove();
<div class="main_container">
<div class="container_one">
<div class="inner_container">
<div class="status">Ended</div>
</div>
</div>
<div class="container_one">
<div class="inner_container">
<div class="status">On going</div>
</div>
</div>
<div class="container_one">
<div class="inner_container">
<div class="status">Ended</div>
</div>
</div>
</div>
Thank you for the help!
I would use the jQuery's selector by content
combined with .closest(). This might be the shortest way:
$('.status:contains("Ended")', $('.main_container')).closest('.container_one').remove();
First ('.status:contains("Ended")') will select all elements that have a class status, contain the text "Ended" and are children of main_container (not needed but is recommended to speed up selection of elements on complex pages).
Then the method .closest('container_one') will climb up the parents tree for each of the elements from the previous step and select the first parent element with class 'container_one'.
At last it will remove all elements found.
Note: all those methods work both with single element and collections of elements, so no need of any for/foreach.
Working JSFiddle Demo
Pure JavaScript solution with forEach:
var div = document.querySelectorAll('.container_one');
div.forEach(function(el){
var target = el.querySelector('.status');
if(target.textContent == 'Ended'){
el.remove();
};
})
<div class="main_container">
<div class="container_one">
<div class="inner_container">
<div class="status">Ended</div>
</div>
</div>
<div class="container_one">
<div class="inner_container">
<div class="status">On going</div>
</div>
</div>
<div class="container_one">
<div class="inner_container">
<div class="status">Ended</div>
</div>
</div>
</div>
Try this
$filstatus.parent().parent().remove();
filter will return an array , then use each to loop over that and delete the element. In this case it will remove that specific div but the parent div will still be in dom
var $filstatus = $('.status').filter(function() {
return $(this).text().trim() === 'Ended';
});
$filstatus.each(function(index, elem) {
$(elem).remove();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="main_container">
<div class="container_one">
<div class="inner_container">
<div class="status">Ended</div>
</div>
</div>
<div class="container_one">
<div class="inner_container">
<div class="status">On going</div>
</div>
</div>
<div class="container_one">
<div class="inner_container">
<div class="status">Ended</div>
</div>
</div>
</div>
If you want to remove .container_one whose inner child has the text Ended, try
const ended = $('.status').filter((index, element) => $(element).text() === 'Ended')
ended.parents('.container_one').remove()
Since you want to remove the closest ansistor with class .container_one, you will need to use closest
$filstatus.closest(".container_one").remove();
Check this: https://jsfiddle.net/n3d5fwqj/1/
https://api.jquery.com/closest/
Try using this if you don't need $filstatus in other places
$('.status').each(function(){
if ($(this).text() == "Ended"){
$(this).parent().parent().remove();
}
})
I see your problem is you are able to remove the child div status but what you want is to remove the entire parent div with class container_one
you can use $.each for that and use closest(class_name) to remove the parent including its child
$.each($('.status'), function(idx, div) {
if ($(this).text() == 'Ended') {
$(this).closest('.container_one').remove();
}
});
Demo
or you can continue your filter and just add .closest('.container_one') to your jquery selector
var $filstatus = $('.status').filter(function() {
return $(this).text() == 'Ended';
});
$filstatus.closest('.container_one').remove();
Demo

Jquery multiple selectors and multiple contains

Can I search a div with multiple selectors each with a contains in one jquery string? It needs to be a AND not OR search .
$('.row .people:contains("James") .tags:contains("episode")')
The above selection should return the first div from below.
<div class="row">
<span class="people">James</span>
<span class="tags">episode</span>
</div>
<div class="row">
<span class="people">Bill</span>
<span class="tags">episode</span>
</div>
<div class="row">
<span class="people">James</span>
<span class="tags">podcast</span>
</div>
You can use jQuery's .has() to check if an element contains certain descendants. You can nest :contains within your .has() statement.
That'll allow you to check if .row contains a span with certain text.
Then you can add a second .has() statement to check that it has both spans with the matched text.
Note that in your example HTML, doing the check the way you describe is overcomplicating things because you could just do .row:first-child, but assuming you really do need to check things this way, this is the way to go.
Example:
$('.row').has('.people:contains("James")').has('.tags:contains("episode")').addClass('highlighted');
.row.highlighted {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">
<span class="people">James</span>
<span class="tags">episode</span>
</div>
<div class="row">
<span class="people">Bill</span>
<span class="tags">episode</span>
</div>
<div class="row">
<span class="people">James</span>
<span class="tags">podcast</span>
</div>
Someone posted an answer that worked, but then deleted it. Using the "~" tilde selector allowed for me to do the selection in one string so I can build the string based off of multiple contains with multiple selectors.
$('.row .people:contains("James") ~ .tags:contains("episode")').parents('.row').addClass('highlighted');
.row.highlighted {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">
<span class="people">James</span>
<span class="tags">episode</span>
</div>
<div class="row">
<span class="people">Bill</span>
<span class="tags">episode</span>
</div>
<div class="row">
<span class="people">James</span>
<span class="tags">podcast</span>
</div>
You could use the jQuery .has() function however in the example code that you have you are missing a comma between the two selectors.
Should be.....
$('.row .people:contains("James"), .tags:contains("episode")');

Categories

Resources