DOM manipulation to produce unique list of element - javascript

Says I have DOM like below :
<div>
<span>a</span>
</div>
<div>
<span>c</span>
</div>
<div>
<span>b</span>
</div>
<div>
<span>a</span>
</div>
<div>
<span>b</span>
</div>
How to remove duplicated element above? I thought of foreach, text() and remove() but I don't know how to do the comparison.
$('div').foreach(function(){
// how to compare here?
$(this).find('span').text();
});

Related

Get the last element in HTML structure

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>

Javascript : how to append nodes from a Nodelist from getQuerySelectorAll to an html element?

I am trying to duplicate the content of the Html element .slideTrack by getting it from querySelectorAll and append the nodelist with a spread operator.
I think that a nodelist can't be append() directly to an element with the spread operator so in the documentation of Nodelist I tried to use the NodeList.item() that is returning a Node that I should pass to the append() method. I made a simple for loop but it is not working either. I don't understand why it is not working, any help ?
const allSlides = document.querySelectorAll(".citation");
const slideTrack = document.querySelector(".slideTrack");
//first trying directly with the spread operator
slideTrack.append(...allSlides);
//then trying with the item() method and a simple for loop
for (i=0;i<allSlides.length;i++) {
slideTrack.append(allSlides.item(i));
}
<div class="slideTrack">
<div class="citation">
<p class="text">test1</p>
</div>
<div class="citation">
<p class="text">test2</p>
</div>
<div class="citation">
<p class="text">test3</p>
</div>
<div class="citation">
<p class="text">test4</p>
</div>
<div class="citation">
<p class="text">test5</p>
</div>
</div>
append() appends the node to the new location, which removes it from the old location. It doesn't make a copy of the node.
If you want to leave the node in the old location, use .cloneNode(true) to make a copy of the node and its descendants.
const allSlides = document.querySelectorAll(".citation");
const slideTrack = document.querySelector(".slideTrack");
//then trying with the item() method and a simple for loop
for (i=0;i<allSlides.length;i++) {
slideTrack.append(allSlides[i].cloneNode(true));
}
<div class="slideTrack">
<div class="citation">
<p class="text">test1</p>
</div>
<div class="citation">
<p class="text">test2</p>
</div>
<div class="citation">
<p class="text">test3</p>
</div>
<div class="citation">
<p class="text">test4</p>
</div>
<div class="citation">
<p class="text">test5</p>
</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.

Removing div's and keep content

I'm trying to remove the following DIV's:
<div class="whatever_name">
<div class="whatever_name">
<h2>subtitle</h2>
<p>content<p>
</div>
</div>
and need the following output:
<h2>subtitle</h2>
<p>content<p>
Using jQuery, I can not use remove() because it clear the content too. With pure javascript, happens the same.
I have no idea how to accomplish this issue.
Any idea?
EDIT:
Not always the structure is the same. It can vary, i.e.:
<div class="whatever_name">
<div class="whatever_name">
<div class="whatever_name">
<h2>subtitle</h2>
<p>content<p>
</div>
</div>
</div>
Just need an iterator that can handle such task.
Use unwrap() method twice on the children element.
$('.content .post-12')
// get children elements, or use contents()
.children()
// use unwrap twice to unwrap two parents
.unwrap().unwrap()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="content">
<div class="post-12">
<h2>subtitle</h2>
<p>content</p>
</div>
</div>
UPDATE : With the updated content you just need to change the selector with your requirement.
$('div > div > h2,div > div > p').unwrap().unwrap()
// or use
// $('div > div:has(h2):has(p) > *')
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="whatever_name">
<div class="whatever_name">
<div class="whatever_name">
<h2>subtitle</h2>
<p>content
<p>
</div>
</div>
</div>

Remove outer element with jquery

<div>
<p>
<img>
</p>
<p></p>
<p></p>
</div>
How to remove the first <p></p> but not the childs (img)?
you can use .unwrap()
to unwrap the first p you have to specify the select as first() p also
$("p").first().contents().unwrap()
Working Demo:
$("p").first().contents().unwrap()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div>
<p>
<img>
</p>
<p>aaa
</p>
<p>
</p>
</div>

Categories

Resources