Get the last element in HTML structure - javascript

Can I access the last div with the + content only with css & child combinators? I would like to style it.
<body>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
+
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
with :last child i can't reach so deep into the tree.

The selector div:(not(:has(div)) will match any DIV that doesn't have another DIV nested inside it.
:has(selector) matches an element whose contents include an element that matches selector. Putting this in :not() reverses the condition.
This is a relatively new CSS selector, and it's not yet supported by Firefox as of version 108. See the compatibility table.
div:not(:has(div)) {
color: red;
}
<body>
a
<div>
b
<div>
c
<div>
d
<div>
e
<div>
f
<div>
g
<div>
h
<div>
i
<div>
j
<div>
+
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

Related

How to read text "LE 88" from the following HTML using Javascript

How to read text "LE 88" from the following HTML using Javascript. the text LE is not constant, it keeps on changing. It neither contains ID's, nor class names.
<body>
<div id="Record">
<div>
<div>Grade A </div>
</div>
<div>19-04-2022
</div>
<div>
<div>Subject H1
</div>
<div>
<div>LE 88
</div>
</div>
</div>
<div>
</div>
</div>
</body>
You can iterate the dom div and check for the children. In this case the div with text does not have any child. So use children and check for the textContent. If the matching text is found do the required operation
document.querySelectorAll('div').forEach((curr) => {
const child = curr.children;
if (child.length === 0 && curr.textContent.trim() === 'Marks 88') {
curr.textContent = 'Marks 88 changed'
}
})
<div>
<div>
<div>Grade A </div>
</div>
<div>19-04-2022</div>
<div>
<div>Subject H1</div>
<div>
<div>Marks 88</div>
</div>
</div>
<div>
</div>
</div>

How to add attribute to all titles on page?

I would like to find all elements which contains title on page and add new attribute to all of them.
Example:
<div title='something 1'></div>
<p>Test<div title='something 2'></div></p>
<div>
<div>
<div>
<div title='something 3'></div>
</div>
</div>
</div>
How it should look like after page load:
<div title='something 1' rel='tooltip'></div>
<p>Test<div title='something 2' rel='tooltip'></div></p>
<div>
<div>
<div>
<div title='something 3' rel='tooltip'></div>
</div>
</div>
</div>
Previously I did it manually which is bad solution for me
$('#collection_map > div > div > button').attr('rel', 'tooltip');
Try this code:-
$('div[title]').each(function() {
$(this).attr('rel', 'tooltip');
});
You don't even need jQuery for this. Here is a working example in plain JavaScript.
var elems = document.querySelectorAll('[title]')
elems.forEach(elem => elem.setAttribute('rel', 'tooltip'))
<div title='something 1'></div>
<p>Test<div title='something 2'></div></p>
<div>
<div>
<div>
<div title='something 3'></div>
</div>
</div>
</div>
Get all elements which have attribute title and then loop over it to add new attribute rel to each object.
paragraph tag cannot have block elements like div nested in it. See - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/p
Paragraphs are block-level elements, and notably will automatically
close if another block-level element is parsed before the closing </p>
tag.
$('[title]').attr('rel', 'tooltip');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div title='something 1'></div>
<p>Test
<div title='something 2'></div>
</p>
<div>
<div>
<div>
<div title='something 3'></div>
</div>
</div>
</div>

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

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.

jQuery to iterate through class elements, grab text, insert elsewhere

I need to programmatically extract titles within a webpage, inject anchor links right above those titles and then inject navigation links near the top of the page that will link to those anchors within the same page.
I need jQuery to select all headings with the class of 'iphorm-group-title’ and extract the text.
Above each heading, excluding the first heading, an anchor tag needs to be injected so that a visitor can link to that section of the page.
The text of each heading, excluding the first heading, needs to be injected before the first heading and linked to all the anchor tags that were injected in the previous step.
This form is generated by a plugin or I would just edit the HTML.
For reference, the page is located at:
http://mountpleasantmagazine.com/BestOfBallot/
Here is an example of the HTML as of now.
<div>
<div>
<div class="iphorm-group-title">VOTER INFO</div>
</div>
<div>
<div class="iphorm-group-title">SHOPPING & GOODS</div>
</div>
<div>
<div class="iphorm-group-title">FOOD & DRINK</div>
</div>
<div>
<div class="iphorm-group-title">ENTERTAINMENT & LEISURE</div>
</div>
</div>
Here is some JS that will grab the elements and loop through the text, which is the point where I'm stuck.
jQuery('.iphorm-group-title').each(function () {
console.log(jQuery(this).text());
});
Here is how the HTML is expected to look after injecting the code.
<div>
<div>
SHOPPING & GOODS | FOOD & DRINK | <a href="#entertainmentleisure">ENTERTAINMENT & LEISURE</ a>
</div>
<div>
<div class="iphorm-group-title">VOTER INFO</div>
</div>
<div>
<a name="shoppinggoods"></a>
<div class="iphorm-group-title">SHOPPING & GOODS</div>
</div>
<div>
<a name="fooddrink"></a>
<div class="iphorm-group-title">FOOD & DRINK</div>
</div>
<div>
<a name="entertainmentleisure"></a>
<div class="iphorm-group-title">ENTERTAINMENT & LEISURE</div>
</div>
</div>
I just made a code snippet for you hope so it's the exact what you needed.
var listElement=jQuery("<div id='menuList'></div>").insertBefore(".iphorm-elements");
jQuery(".iphorm-elements .iphorm-group-wrap:not(:first-child)")
.each(function() {
if (jQuery(this)
.not(".iphorm-group-wrap:first")) {
var heading = jQuery(this)
.find(".iphorm-group-title");
var headingName = heading.text()
.split(' ')
.join('')
.replace('&', '');
var lowerHeading = headingName.toLowerCase();
var anchorUrl = [lowerHeading.slice(0, 0), lowerHeading.slice(0)].join('');
var anchorText = heading.text();
var anchorLink=jQuery('<a name="' + anchorUrl + '"></a>')
.insertBefore(heading);
var anchorLink2=jQuery('' + anchorText + '' +"<span> | </span>")
.insertBefore(heading);
jQuery(listElement).append(anchorLink2);
}
});
jQuery("#menuList span:last-child").remove();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="iphorm-elements">
<div class="iphorm-group-wrap">
<div class="iphorm-group-title-description-wrap">
<div class="iphorm-group-title">VOTER INFO</div>
</div>
</div>
<div class="iphorm-group-wrap">
<div class="iphorm-group-title-description-wrap">
<div class="iphorm-group-title">SHOPPING & GOODS</div>
</div>
</div>
<div class="iphorm-group-wrap">
<div class="iphorm-group-title-description-wrap">
<div class="iphorm-group-title">FOOD & DRINK</div>
</div>
</div>
<div class="iphorm-group-wrap">
<div class="iphorm-group-title-description-wrap">
<div class="iphorm-group-title">FOOD & DRINK</div>
</div>
</div>
<div class="iphorm-group-wrap">
<div class="iphorm-group-title-description-wrap">
<div class="iphorm-group-title">ENTERTAINMENT & LEISURE</div>
</div>
</div>
</div>

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