Get an element with specific parent - javascript

I want to get an element that it's parent has a specific id in javascript. For example if we have an html code like this
<div id="1">
<p name="para"> first div </p>
<a> </a>
</div>
<div id="2">
<p name="para"> second div </p>
<a> </a>
</div>
<div id="3">
<p name="para"> third div </p>
<a> </a>
</div>
I tried this but it did not work.
document.getElementById('1').getElementByName("para").innerHTML = "";

Use a queryselector:
document.querySelector('#1 > [name=para]').innerHTML = "";
Side note: Id's shouldn't start with a number. This could cause issues.
Note: Using characters except ASCII letters, digits, '_', '-' and '.' may cause compatibility problems, as they weren't allowed in HTML 4. Though this restriction has been lifted in HTML 5, an ID should start with a letter for compatibility.
A simple way to fix the id problem would be to prefix the id with something that isn't a number such as an underscore (You will also need to change the html to use an underscore as well):
document.querySelector('#_1 > [name=para]').innerHTML = "";

document.getElementById("2").childNodes[1].innerHTML;

You can use querySelector, but with a unicode as ids shouldn't start with numbers.
document.querySelector('#\\33 > p[name="para"]').innerHTML = 'Foo';
document.querySelector('#\\33 > p[name="para"]').innerHTML = 'Foo';
<div id="1">
<p name="para"> first div </p>
<a> </a>
</div>
<div id="2">
<p name="para"> second div </p>
<a> </a>
</div>
<div id="3">
<p name="para"> third div </p>
<a> </a>
</div>

Just another way to do it. Note that using querySelector is preferred way of doing it as the other answers showed.
const el = document.getElementById('1').childNodes;
const para = [...el]
.filter(item => item.nodeType === document.ELEMENT_NODE)
.filter(item => item.tagName === 'P');
console.log(para[0]);
<div id="1">
<p name="para"> first div </p>
<a> </a>
</div>
<div id="2">
<p name="para"> second div </p>
<a> </a>
</div>
<div id="3">
<p name="para"> third div </p>
<a> </a>
</div>

Related

how to target the element above my show more button

i want to target the element above my show more button, so when i click the button more text appears i don't want to target it by class name or id
here is my code
<div class="ccontainer" id="ccontainer">
<p id="context"> content </p>
<div class="img" id="cntimgcon" >
<img src="images\image2.jpg" id="cntimgp1">
</div>
<p id="context"> content </p>
</div>
<Button id="showmore" onclick=" this.parentElement.style.maxHeight = 'none'"> show more </button>
Don't refer to the IDs that can get cumbersome. Instead give your show more button a class to refer to. That will give you the ability to add many to the same page without needing to adjust/track the IDs.
This is a basic example that toggles a class on the content div that will show the full div. Obviously the details are up to your specific needs.
Using previousElementSibling allows you to refer to the previous element.
document.addEventListener("click",function(e){
let btn = e.target;
if(btn.className.indexOf("showmore") > -1){
btn.previousElementSibling.classList.toggle("active");
}
});
.ccontainer{
height:50px;
overflow:hidden;
border:1px solid #000;
margin:10px 0;
padding:10px;
}
.ccontainer.active{
height:auto;
}
<div class="ccontainer">
<p id="context"> content </p>
<div class="img" id="cntimgcon" >
<img src="images\image2.jpg" id="cntimgp1">
</div>
<p id="context"> content </p>
</div>
<Button class="showmore"> show more </button>
<div class="ccontainer">
<p id="context"> content3 </p>
<div class="img" id="cntimgcon" >
<img src="images\image2.jpg" id="cntimgp1">
</div>
<p id="context"> content4 </p>
</div>
<Button class="showmore"> show more </button>
When using jQuery you can use:
$(this).prev(); // $(this) is equal to the button
// or very specific
$(this).prev(".container");
Using vanilla JS you could use something like
onclick="this.previousSibling"
not sure if vanilla js has a way of selecting a previous node by identifier.
Any whitespace or comment block is also considered a previousSibling, so be careful with that.
html
<div>
<div class="ccontainer" id="ccontainer">
<p id="context"> content </p>
<div class="img" id="cntimgcon" >
<img src="images\image2.jpg" id="cntimgp1">
</div>
<p id="context"> content </p>
</div>
<Button id="showmore" onclick="hideParent(this)"> show more </button>
</div>
js
function hideParent(elm){
console.log(elm.previousElementSibling.innerHTML )
}
see https://jsfiddle.net/rkqnmv0w/
If your using only vanila JS you can access the previous element with the previousElementSibling property.
Example:
var showMoreButton = document.getElementById('showmore');
var previousElement = showMoreButton.previousElementSibling;

add data- attributes by reading values from DOM

I have the below html structure and I'm trying to get the text of h tags and add as a data- attribute in the corresponding tags:
<div class="content">
<div class="body">
<h1>foo</h1>
<p>para-test1</p>
<p>para-test2</p>
<div class="link">
anchor1
anchor2
anchor3
</div>
</div>
</div>
<div class="content">
<div class="body">
<h1>bar</h1>
<p>para-test3</p>
<div class="link">
anchor4
</div>
</div>
</div>
So 'foo' should be set as a data attribute value for anchor 1,2,3 elements and
'bar' should be set as a data attribute value for anchor 4. Something like this:
<a data-custom="foo" href="#">anchor1</a>
<a data-custom="foo" href="#"">anchor2</a>
<a data-custom="foo" href="#">anchor3</a>
<a data-custom="bar" href="#">anchor4</a>
I tried to iterate over the elements and I'm struck at the second loop.
$(".content .body").each(function() {
$(this).find(".link").attr("data-hN", $(this).next(":header").text());
});
You have an extra double quote two times in your HTML. But, fixing that and foregoing JQuery (which is overkill for such a trivial task), see comments inline below:
// Loop over the links
document.querySelectorAll("div.link > a").forEach(function(item){
// Set the current link data-custom attribute to the nearest
// .body ancestor and the first heading element within that text
item.dataset.custom = item.closest(".body").querySelector(":first-child").textContent;
console.log(item);
});
<div class="content">
<div class="body">
<h1>foo</h1>
<p>para-test1</p>
<p>para-test2</p>
<div class="link">
anchor1
anchor2
anchor3
</div>
</div>
</div>
<div class="content">
<div class="body">
<h1>bar</h1>
<p>para-test3</p>
<div class="link">
anchor4
</div>
</div>
</div>

How to use a CSS selector that gets all matching elements except those inside a specific child?

Assume an HTML structure as shown:
<div id="container">
<div class="A">
<div id="excludedElement">
<p>
<span class="MyClass">1</span>
<span class="MyClass">2</span>
<span class="MyClass">3</span>
</p>
</div>
</div>
<div class="B">
<p>
<span class="MyClass">4</span>
<span class="MyClass">5</span>
<span class="MyClass">6</span>
</p>
</div>
</div>
I want all elements inside of the "container" div that have the class "MyClass" except for those inside of the "excludedElement" div. In this case, the result contains only the spans 4, 5, and 6.
My current solution is to first get all elements with "MyClass", then get all elements inside of excludedElement with "MyClass". For each element in the first list, we check if it's in the second, and skip over it if so. This is O(n^2) running time, so I'd like to avoid this. Psuedocode for reference:
const allElements = container.querySelectorAll('.MyClass');
const excludedElements = container.querySelectorAll('#excludedElement .MyClass');
var result = [];
for (const element in allElements)
{
if (!excludedElements.Contains(element))
{
result.Add(element);
}
}
Is there a way to craft a CSS selector in querySelectorAll() that can retrieve this particular set of elements?
One way is to temporarily remove excludedElement from the tree, query for "MyClass", then replace the excludedElement, but I want to avoid modifying the DOM.
If the structure is predictable and already known:
container.querySelectorAll('div:not(#excludedElement) > p .MyClass');
If the structure is not known and you're okay with adding classes in order to avoid O(n^2):
const excludes = [...container.querySelectorAll('#excludedElement .MyClass')];
excludes.forEach(element => element.classList.add('excluded'));
const filteredMyClass = [...container.querySelectorAll('.MyClass:not(.excluded)')];
You can select all .MyClass descendants, then .filter the collection by whether the current item being iterated over has a #excludedElement ancestor with .closest:
const classes = [...container.querySelectorAll('.MyClass')]
.filter(span => !span.closest('#excludedElement'));
for (const span of classes) {
span.style.backgroundColor = 'yellow';
}
<div id="container">
<div class="A">
<div id="excludedElement">
<p>
<span class="MyClass">1</span>
<span class="MyClass">2</span>
<span class="MyClass">3</span>
</p>
</div>
</div>
<div class="B">
<p>
<span class="MyClass">4</span>
<span class="MyClass">5</span>
<span class="MyClass">6</span>
</p>
</div>
</div>
Unless you know in advance the exact sort of structure of the descendants of #container, I don't think there's an elegant way to do this with a single query string; :not accepts simple selectors only.
Just for informational purposes, a silly and repetitive method that you shouldn't use would be to use the query string:
:scope > .MyClass,
:scope > *:not(#excludedElement) > .MyClass,
:scope > *:not(#excludedElement) > *:not(#excludedElement) > .MyClass
...
const selector = `
:scope > .MyClass,
:scope > *:not(#excludedElement) > .MyClass,
:scope > *:not(#excludedElement) > *:not(#excludedElement) > .MyClass
`;
const classes = container.querySelectorAll(selector);
for (const span of classes) {
span.style.backgroundColor = 'yellow';
}
<div id="container">
<div class="A">
<div id="excludedElement">
<p>
<span class="MyClass">1</span>
<span class="MyClass">2</span>
<span class="MyClass">3</span>
</p>
</div>
</div>
<div class="B">
<p>
<span class="MyClass">4</span>
<span class="MyClass">5</span>
<span class="MyClass">6</span>
</p>
</div>
</div>
I have this....
const Excludes = [...container.querySelectorAll('#excludedElement .MyClass')]
, noExcludes = [...container.querySelectorAll('.MyClass')].filter(el=>(!Excludes.includes(el)))
;
noExcludes.forEach(element => element.style.backgroundColor = 'lightgreen');
<div id="container">
<div class="A">
<div id="excludedElement">
<p>
<span class="MyClass">1</span>
<span class="MyClass">2</span>
<span class="MyClass">3</span>
</p>
</div>
</div>
<div class="B">
<p>
<span class="MyClass">4</span>
<span class="MyClass">5</span>
<span class="MyClass">6</span>
</p>
</div>
</div>
You can use this precise selector in .querySelectorAll():
:not(#excludedElement) > p > .MyClass
Working Example:
const includedSpans = [... document.querySelectorAll(':not(#excludedElement) > p > .MyClass')];
includedSpans.forEach((includedSpan) => console.log(includedSpan.textContent));
<div id="container">
<div class="A">
<div id="excludedElement">
<p>
<span class="MyClass">1</span>
<span class="MyClass">2</span>
<span class="MyClass">3</span>
</p>
</div>
</div>
<div class="B">
<p>
<span class="MyClass">4</span>
<span class="MyClass">5</span>
<span class="MyClass">6</span>
</p>
</div>
</div>

put multi div and another multi div

I want to put a div in another div using js. I found a solution can do this but just put 1 div in div. Below html is my situation.
For example:
<body>
<div>
<span class="outer_part">
</span>
<div class="inner_part">1
</div>
</div>
<div>
<span class="outer_part">
</span>
<div class="inner_part">2
</div>
</div>
<div>
<span class="outer_part">
</span>
<div class="inner_part">3
</div>
</div>
</body>
Result:
<body>
<div>
<span class="outer_part">
<div class="inner_part">1</div>
</span>
</div>
<div>
<span class="outer_part">
<div class="inner_part">2</div>
</span>
</div>
<div>
<span class="outer_part">
<div class="inner_part">3</div>
</span>
</div>
</body>
I found solution but not work
<script>
$('.inner_part').appendTo('span.outer_part');
</script>
Your problem is that you appending all the .inner_part elements to all the .outer_part elements, but you only need to do a portion of that.
You can use each() to loop over all the .inner_parts, and attach each to its previous sibling, which is the .outer_part.
// loop over all inner parts
$('.inner_part').each(function() {
var innerPart = $(this);
var outerPart = innerPart.prev(); // inner part's previous sibling is the outer part
innerPart.appendTo(outerPart);
});
Or, shorter:
$('.inner_part').each(function() {
$(this).appendTo($(this).prev());
});
Get element by the ID, then add html inside of it to add a div in this case or anything you want.
document.getElementById('div1').innerHTML += '<div class="inner_part">1</div>';
<div id="div1"></div>

Help with hiding DIV tags, based on text content, using Greasemonkey

I am looking for a way to write a Greasemonkey script which will take the following snippet of code and only show the code blocks consisting of <div class="A" where both "passtest" and "State1" are present.
<div class="A">
<div class="B">
<a href="/link1">
<img class="imgClass" src="http://link.com/img.img" title="imgTitle"/>
</a>
</div>
<div class="C">
<span class="sc1">passtest</span>
<br/>
<em class="ec1">City1, State1</em>
</div>
</div>
<div class="A">
<div class="B">
<a href="/link1">
<img class="imgClass" src="http://link.com/img.img" title="imgTitle"/>
</a>
</div>
<div class="C">
<span class="sc1">failtest </span>
<br/>
<em class="ec1">City1, State1 </em>
</div>
</div>
<div class="A">
<div class="B">
<a href="/link1">
<img class="imgClass" src="http://link.com/img.img" title="imgTitle"/>
</a>
</div>
<div class="C">
<span class="sc1">passtest </span>
<br/>
<em class="ec1">City2, State2 </em>
</div>
</div>
I found this from Dive Into Greasemonkey:
var allDivs, thisDiv;
allDivs = document.evaluate("//div[#class='sponsoredlink']", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for (var i = 0; i < allDivs.snapshotLength; i++) {
thisDiv = allDivs.snapshotItem(i);
// do something with thisDiv
}
I am looking at this code as the starting point for what I want to do. But, I am just a user, not a coder.
I understand the logic I need is:
For each div where class="a" which does contain the text "passtest" and also does not contain "state1" do not display that div.
Here's a script that does that, using jQuery. The hard part is choosing the selectors.
// ==UserScript==
// #name Show State1 passes only.
// #include http://YOUR_SITE/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js
// ==/UserScript==
$("div.A") .hide ()
.has ("span.sc1:contains('passtest')")
.has ("em.ec1:contains('State1')")
.show ();
Note that :contains() is case-sensitive.
See the code in action at jsFiddle.

Categories