HTML JavaScript querySelector to find an element whose child has a specific data attribute - javascript

In my below HTML markup, I'd like to query the <div> that has a data-parent set to "true", and the contained child has data-child-gender set to "true" and inner html is "male".
<div id="grandparent">
<div id="parent1" data-parent="true">
<div id="child1" data-child-gender="false">
male
</div>
</div>
<div id="parent2" data-parent="true">
<div id="child2" data-child-gender="true">
female
</div>
</div>
<div id="parent3" data-parent="false">
<div id="child3" data-child-gender="true">
female
</div>
</div>
<div id="parent4" data-parent="true">
<div id="child4" data-child-gender="true">
male
</div>
</div>
</div>
Given the above scenario, the expected <div> is parent4.
What is the JavaScript querySelector to use?

First use querySelectorAll which will give an array. Then iterate over it and check and get element with required data attribute.
After that you can use use a if & check the content inside it
let k = document.querySelectorAll('[ data-parent=true]').forEach(function(item) {
let elem = item.querySelector('[data-child-gender=true]');
if (elem !== null && elem.innerHTML.trim() === 'male') {
console.log(item.id)
}
})
<div id="grandparent">
<div id="parent1" data-parent="true">
<div id="child1" data-child-gender="false">
male
</div>
</div>
<div id="parent2" data-parent="true">
<div id="child2" data-child-gender="true">
female
</div>
</div>
<div id="parent3" data-parent="false">
<div id="child3" data-child-gender="true">
female
</div>
</div>
<div id="parent4" data-parent="true">
<div id="child4" data-child-gender="true">
male
</div>
</div>
</div>

There isn't one querySelector you can use for this (as you can't use it to select specific text within elements). However, you can use .querySelector() with .filter() to get more specific results:
const true_children = [...document.querySelectorAll("[data-parent='true'] [data-child-gender='true']")];
const res = true_children.filter(({innerHTML:g}) => g.trim() === "male");
console.log(res);
<div id="grandparent">
<div id="parent1" data-parent="true">
<div id="child1" data-child-gender="false">
male
</div>
</div>
<div id="parent2" data-parent="true">
<div id="child2" data-child-gender="true">
female
</div>
</div>
<div id="parent3" data-parent="false">
<div id="child3" data-child-gender="true">
female
</div>
</div>
<div id="parent4" data-parent="true">
<div id="child4" data-child-gender="true">
male
</div>
</div>
</div>

The problem that the question describes, cannot be solved using query-selectors alone. This is because of following reasons:
The query selectors always works on descendants, so while evaluating that the child div has data-child-gender="true", there will be no way to return the parent element. The query-selector will return the child div.
There is no way to evaluate the inner text or contained text of an element in query-selector.
These two limitations can be worked around by using JavaScript, provided that you were going to use the query-selector in JS.
Something like the following snippet should work.
document.querySelectorAll('div[data-parent=true] div[data-child-gender=true]')
.filter(function(elem) {
return elem.innerText === 'male'; // filter the elements containing male string.
})[0].parentElement; // return the parent of matched element.
An equivalent logic could be derived for selenium too. Otherwise if this much logic is unacceptable, you can always use the much richer xpath selectors. xpath wouldn't have either of the limitations mentioned above.

Related

How to add and remove class dynamically to child div based on value in Jquery

if data value is matching with any div inside requestsampler class then dynamically add new class(sampleClass) to test class inside the matching container
js:
var data = **somevalue**;
data is dynamic value
html:
<div class="requestsampler">
<div class= "**somevalue**">
<div class="test"> // add new class <div class="test sample class">
//
</div>
</div>
<div class= "somevalue2">
<div class="test">
//
</div>
</div>
<div class= "somevalue3">
<div class="test">
//
</div>
</div>
</div>
tried not working:
$('.requestsampler').hasClass(data) {
$(.'requestsampler .`${data}` .test').addClass('sampleclass');
}
You could simply use Attribute Contains Prefix Selector [name|="value"] for more info please refer http://jqapi.com/#p=attribute-contains-prefix-selector.. below is the code for your example.
$(document).ready(()=>{
var data = "somevalue"; $('div[class|="'+data+'"]>.test').addClass("sampleclass");
})
.sampleclass{
background-color:red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="requestsampler">
<div class= "somevalue">
<div class="test"> // add new class <div class="test sample class">
//
</div>
</div>
<div class= "somevalue2">
<div class="test">
//
</div>
</div>
<div class= "somevalue3">
<div class="test">
//
</div>
</div>
</div>
you could try jquery elem.find() api. And also use className with string and numeric combination instead of symbols
i have changed the condition with element find length. Because hasClass() only perform on the selector element. So if you are using find() they will find the matched element.
And also your if condition does not make any sense, without condition is also working same
Updated
If you need first test element. use .eq(0) or else use different className for the first test element
var data = "somevalue";
if ($('.requestsampler').find(`.${data}`).length > 0) {
$('.requestsampler').find(`.${data}`).find('.test').eq(0).addClass('sampleclass');
}
.sampleclass {
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="requestsampler">
<div class="somevalue">
<div class="test"> // add new class
<div class="test sample class">
sample
</div>
</div>
<div class="somevalue2">
<div class="test">
//
</div>
</div>
<div class="somevalue3">
<div class="test">
//
</div>
</div>
</div>

how do I select an element from a list based on a child value of it's grandparent

this is the object I'm trying to select: $x('//div[contains(#class,"react-select__value-container")]')
** There are 10 of these **
this is the grandparent object: $x('//div[#class="chart-option"]/label[.="Layer"]/..') ** There is only one of these **
the parent is a simple //div[contains(#class, "react-select")]
So the code looks like this:
<div class="chart-option">
<label>Layer</label>
<div class="react-select css-2b097c-container">
<div class="react-select__value-container css-1hwfws3">
So I need the "value-container" who's grandparent has the child /label[.="Layer"]
But I can't for the life of me get the ordering right and relative syntax to get it. Is there a good tutorial for this? Any help is appreciated.
Try this xpath:
//div[#class="chart-option"][label="Layer"]/div[div[contains(#class,"react-select__value-container")]]
Explanation
//div[#class="chart-option"][label="Layer"]
Looking anywhere in the document, select div tags such that (1) the class is chart-option and (2) there is a child tag called label with the value Layer.
/div[div[contains(#class,"react-select__value-container")]]
Looking at each node in the previous result set above, select all child div tags such that that child div tag itself has a div tag that matches the class pattern you have given. (In other words, match based on the grandchild's class, but ultimately select the child div tag.)
Test Cases
Here are some more test cases that I used. You can test using an online xpath testing tool.
<div>
<div class="chart-option">
<label>nope</label>
<div class="react-select css-WRONG-container">
<div class="react-select__value-container css-WRONG">
</div>
</div>
</div>
<div class="chart-option">
<label>Layer</label>
<div class="react-select css-CORRECT-container">
<div class="react-select__value-container css-CORRECT">
</div>
</div>
</div>
<div class="chart-option">
<label>Not Layer</label>
<div class="react-select css-WRONG-container">
<div class="react-select__value-container css-WRONG">
</div>
</div>
</div>
<label>Layer</label>
<div class="react-select css-WRONG-container">
<div class="react-select__value-container css-WRONG">
</div>
</div>
<div class="chart-option">
<label>Layer</label>
<div class="WRONG-AGAIN">
<div class="WRONG-AGAIN">
</div>
</div>
</div>
</div>

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>

javascript - select a div within a particular div

The content of the divs is going to be populated with javascript json. Now, I know how to select a div in javascript:
var hsc = document.getElementByID("hsc");
But how would I refer to eg. the title but only in the hsc div.
<div id="hsc">
<div id="title"></div>
<div id="jobs"></div>
...
</div>
<div id="cc">
<div id="title"></div
<div id="jobs"></div>
</div>
On a separate note, wouldn't 'title' and 'jobs' be better classified as classes, and not ids?
This would work:
var hsc = document.querySelectorAll("#hsc > .title");
But you need to change to valid html and use unique IDs and classes instead:
<div id="hsc">
<div class="title"></div>
<div class="jobs"></div>
...
</div>
<div id="cc">
<div class="title"></div>
<div class="jobs"></div>
</div>
IDs must be unique in HTML.
Change them to classes, and then you can use querySelector() to target them:
document.querySelector('.hsc .title').style.color= 'blue';
document.querySelector('.cc .title').style.color= 'red';
<div class="hsc">
<div class="title">Make me blue!</div>
<div class="jobs">Jobs</div>
</div>
<div class="cc">
<div class="title">Make me red!</div>
<div class="jobs">More jobs</div>
</div>
Just try
<div id="hsc">
<div id="a" class="title"></div>
<div id="b" class="jobs"></div>
...
</div>
<div id="cc">
<div id="c" class="title"></div
<div id="d"class="jobs"></div>
</div>
Because your HTML code is invalid because the id is already taken.

How to limit jQuery searches to a certain area

Let's say I have the following.
<div class="foo">
<div>
some text
<div class="bar">
</div>
</div>
</div>
<div class="foo">
<div>
some text
<div class="bar">
some text
</div>
</div>
</div>
I want return all the divs of class "foo" that have "some text" inside the div class "bar." So the second would be returned, but not the second. How can I do that?
Try this
$("div.bar:contains('some text')").parents(".foo")
This will do it
$('.foo:has(.bar:not(:empty))')
Make sure there are no characters inside the .bar, even spaces or newlines.
http://jsfiddle.net/Nk4FB/

Categories

Resources