Javascript: getelementsbyid inside of class that is changing (active) - javascript

This is my HTML code:
<div class="foo active">
<div id="bar">
Hello world!
</div>
</div>
Hello world!
The div class active is always changing so i first need to get into the class foo active
How can I get to change "Hello world!"?
var targetDiv = document.getElementByClassName("foo active")[0].getElementsById("bar");
is not working.
I know when the code is like this:
<div id="foo">
<div class="bar">
Hello world!
</div>
</div>
I just need to:
var targetDiv = document.getElementById("foo").getElementsByClassName("bar")[0];

You just need to target the ID of "bar".
document.getElementById("bar").innerHTML = "new text";

If you want to access an element with an id in HTML, you do not have to use:
var targetDiv = document.getElementByClassName("foo")[0].getElementsById("bar");
You can simply do this:
var targetDiv = document.getElementsById("bar");
Also, You need something to run the code. Example if you click a button the text changes or if you want the text to change as soon as the DOM content loads you can add the DOMContentLoaded event listener.
Try this code:
<div class="foo">
<div id="bar">
Hello world!
</div>
<button onClick = "changeText()">Change Text!</button>
changeText = () => {
const targetVar = document.getElementById("bar");
targetVar.innerHTML = "Something else!";
}

To provide some context as to why this is happening, getElementById and getElementsByClassName return an Element and an array of Elements respectively. The Element object has a series of functions available to call, including (but not limited to) getElementsByClassName. However, the getElementById function is not available on Elements, only on the Document object itself, meaning that you can't call it in the way you were attempting to in your first example.
To circumvent this, you can either find the element by ID straight away and work from there
var targetDiv = document.getElementById("foo")
or you can use querySelector and querySelectorAll
const targetDiv = document.querySelector(".foo.active #bar")
// The result you want
const targetDiv = document.querySelector(".foo.active #bar")
console.log(targetDiv)
// An example of a result not filtered by the active class
const exampleDiv = document.querySelectorAll(".foo #bar")
console.log(exampleDiv)
<div class="foo active">
<div id="bar">
Hello world!
</div>
</div>
<div class="foo inactive">
<div id="bar">
Hello world!
</div>
</div>
Note that ideally there is only one element with a given ID on a page as IDs are intended to be unique. With that being said, my example isn't best practice, but it sounds like in your example there may be multiple elements with the same ID.

Related

How can I get the path to a specific DOM element iterating a HTML collection?

This is the issue: I want to have nested divs with paragraphs inside with different texts.
I want to be able to get the paragraph that contains certain word, for example "mate" I did the below HTML structure trying to obtain an HTML collection and iterate it, and then using javascript, try to use the includes method to get the paragraph than contains that word, and finally, try to find a way to get the full path from the uppermost div to this p.
<div class="grandpa">
<div class="parent1">
<div class="son1">
<p>I like oranges</p>
</div>
<div class="son2">
<p>yeeeey</p>
<p>wohoo it's saturday</p>
</div>
<div class="son3"></div>
</div>
<div class="parent2"></div>
<div class="parent3">
<div class="son1">
<p>your team mate has been killed!</p>
<p>I should stop playing COD</p>
</div>
<div class="son2"></div>
</div>
</div>
I actually don't know how to achieve it, but at least I wanted to get an HTML collection to iterate, but I'm not being able to get it.... When I use this:
const nodes = document.querySelector('.grandpa');
console.log(typeof nodes);
I don't get an HTML collection, instead if I console.log typeof nodes variable it says it is an object..
How can I iterate this DOM tree, capture the element that contais the word "mate", and obtain (this is what I really want to achieve) the path to it?
Thanks!
You can loop through every element, remove all children elements, then check whether the textContent includes the string you are looking for:
const allElements = document.body.querySelectorAll('*');
const lookFor = "mate";
var elem;
for (let i = 0; i < allElements.length; i++) {
const cur = allElements[i].cloneNode(true); //doesn't mess up the original element when removing children
while (cur.lastElementChild) {
cur.removeChild(cur.lastElementChild);
}
if (cur.textContent.includes(lookFor)) {
elem = cur;
break;
}
}
console.log(elem);
<div class="grandpa">
<div class="parent1">
<div class="son1">
<p>I like oranges</p>
</div>
<div class="son2">
<p>yeeeey</p>
<p>wohoo it's saturday</p>
</div>
<div class="son3"></div>
</div>
<div class="parent2"></div>
<div class="parent3">
<div class="son1">
<p>your team mate has been killed!</p>
<p>I should stop playing COD</p>
</div>
<div class="son2"></div>
</div>
</div>

JS and querySelectorAll

A querySelectorAll question, most likely a silly one, but I don't see the solution.
I have something like the following
<div id="main_0"> ... </div>
<div id="main_1"> ... </div>
<div id="main_1_minor"> ... </div>
<div id="main_2"> ... </div>
<div id="main_2_minor"> ... </div>
.
.
I wish to select all and only those div's without minor.
I tried
var pattern = new RegExp('^main_\\d');
var elSelected = document.querySelectorAll('div[id^=main_]');
elSelected.filter(elt => pattern.test(elt.id)));
but clearly it is not enough. I am not sure how to formulate by RegEx that the id value has to terminate with a digit. I tried something like RegExp('^main_\\d$'); but I did not get it right.
You can use the :not() selector with the "attribute ends with" selector.
"div:not([id$=minor])"
If it should also verify that the id starts with main_, then you can add that too as you show in your question.
"div[id^=main_]:not([id$=minor])"
So this says "select all div elements where the id starts with main_ and does not end with minor".
If minor is not necessarily at the end, then you can use id*=minor for "contains" instead.
document.querySelectorAll("div[id^=main_]:not([id$=minor])")
.forEach(el => el.style.color = "red");
<div id="main_0"> main </div>
<div id="main_1"> main </div>
<div id="main_1_minor"> main ends with minor </div>
<div id="main_2"> main </div>
<div id="main_2_minor"> main ends with minor </div>
The filter won't work for NodeList, cast to array first. Also if you already selected all main divs the simplest regex would be enough.
var pattern = new RegExp(/\d+$/);
var elSelected = Array.prototype.slice.call(document.querySelectorAll('div[id^=main_]'));
elSelected.filter(elt => pattern.test(elt.id)).forEach(function(elt){
elt.style.backgroundColor = "yellow";
});
<div id="main_0">main_0</div>
<div id="main_1">main_1</div>
<div id="main_1_minor">main_1_minor</div>
<div id="main_2">main_2</div>
<div id="main_0_minor">main_0_minor</div>

jQuery select another element with certain class in same parent

let say i have this div
<div id='parent'>
<button id='button'></button>
<div id='child'>
<div id='grandchild' class='lookAtMe'>
Some JSON text
</div>
</div>
</div>
I wanted to give the #button an on click event that returned the text at #lookAtMe div, specific to the div whom it shares parent/grandparent (in this case, the #parent div)
I tried using:
$("#button").on("click",function(){
var ReturnedText = $(this).parent(".lookAtMe").text();
console.log(RetrunedText);
});
But the console log would retruned (empty string).
Where did i do wrong? please help. Thankyou very much.
Because there is n o parent with that class. You need find().
Actually you need to write
var ReturnedText = $(this).parent().find(".lookAtMe").text();
$("#button").on("click",function(){
var ReturnedText = $(this).parent().find(".lookAtMe").text();
console.log(ReturnedText);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='parent'>
<button id='button'></button>
<div id='child'>
<div id='grandchild' class='lookAtMe'>
Some JSON text
</div>
</div>
</div>

jQuery ID Return is undefined although HTML ID is defined

I'm trying to retrieve the ID of one element, store it as a variable and then use that ID value to interact with other elements in that section with the same ID.
<div class="mainContent">
<div class="articleContent">
<h1>header1</h1>
<p class="articlePara" id="one">para1</p>
</div>
<div class="articleFooter" id="one" onclick="readMore()">
</div>
</div>
<div class="mainContent">
<div class="articleContent">
<h1>header2</h1>
<p class="articlePara" id="two">para2</p>
</div>
<div class="articleFooter" id="two" onclick="readMore()">
</div>
</div>
And then the JS/jQuery
function readMore() {
var subID = event.target.id;
var newTarget = document.getElementById(subID).getElementsByClassName("articlePara");
alert(newTarget.id);
}
At this point I'm only trying to display the ID of the selected element but it is returning undefined and in most cases people seem to notice that jQuery is getting confused because of the differences between DOM variables and jQuery ones.
jsfiddle: https://jsfiddle.net/dr0f2nu3/
To be completely clear, I want to be able to click on one element, retrieve the ID and then select an element in the family of that clicked element using that ID value.
just remove the getElementsByClassName("articlePara"); in end of the newTarget .already you are call the element with id alert the element of the id is same with target.id
function readMore() {
var subID = event.target.id;
var newTarget = $('[id='+subID+'][class="articlePara"]')
console.log(newTarget.attr('id'));
console.log(newTarget.length);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="mainContent">
<div class="articleContent">
<h1>header</h1>
<p class="articlePara" id="one"></p>
</div>
<div class="articleFooter" id="one" onclick="readMore()">click
</div>
</div>
As you have read before, you should keep your id's unique, and you should avoid using onclick in html, but you could do it like this.
With querySelector you get the element and then with parentElement you can retrieve the parent of that element.
function readMore(el) {
var articleFooterId = el.id;
var articlePara = document.querySelector(".articleContent #"+articleFooterId);
var articleContent = articlePara.parentElement;
console.log('articleFooter', articleFooterId);
console.log('articlePara', articlePara);
console.log('articleContent', articleContent);
}
In your html you can return the 'this' object back to the function by doing readMore(this).
<div class="mainContent">
<div class="articleContent">
<h1>header1</h1>
<p class="articlePara" id="one">para1</p>
</div>
<div class="articleFooter" id="one" onclick="readMore(this)">footertext</div>
</div>
<div class="mainContent">
<div class="articleContent">
<h1>header2</h1>
<p class="articlePara" id="two">para2</p>
</div>
<div class="articleFooter" id="two" onclick="readMore(this)">footertext</div>
</div>
jsfiddle
if you're using Jquery:
$(function () {
$('div.articleFooter').click(function () {
var para = $(this).prev().find('p.articlePara').text();
alert('T:' + para);
});
})
$('.articleFooter').click(function() {
var b=subId; //can be any
var a="p[id="+b+"]"+"[class='articlePara']";
$(a).something;
});
You have forgotten to pass in event as parameter in your onclick= call in html.
In your javascript, you need to include event in the parenthesis as well.
window.readMore = function(event) {...}
if you write document.getElementById(subID).getElementsByClassName("articlePara"); That's saying you want to get your clicked element's CHILD elements that have class equal to articlePara . There is none. So you get undefined.
If you want to find all element with a ID one and a class articlePara, it can be done easily with jQuery:
newtarget = $("#one.articlePara");
You can insert a line: debugger; in your onclick handler function to trigger the browser's debugging tool and inspect the values of variables. Then you will know whether you are getting what you want.

Get Nth class of an element having multiple class with out using .attr("class") in jquery

In a div with two classes, the first inner div
<div class="datacheck">
<div class="classic_div_data customdataid_305">
some values come here
</div>
<div class="optiondiv">
</div>
</div>
I need to get a substring (here the number 305) from the second class(customdataid_305) of the first inner div. For this need to get the classes.
I wrote in jquery and succeed
var xyz= $($(".datacheck").find("div")[0]).attr("class").split(" ")[1]
from which I gets the class.
Is there any simpler approach for this.
I am searching for something like this $(element).class() probably returns an array of classes
There's nothing that gives you an array of classes, although the native DOM classList is close. But I don't think classList will make things much simpler.
I'd do this:
var xyz = $(".datacheck .classic_div_data").attr("class").match(/\bcustomdataid_(\d+)\b/);
xyz = xyz && xyz[1];
The regex extracts the numeric portion of the class, without being fragile (sensitive to whether the class is the first or second in the list of classes, for instance).
Example:
var xyz = $(".datacheck .classic_div_data").attr("class").match(/\bcustomdataid_(\d+)\b/);
xyz = xyz && xyz[1];
console.log("xyz = '" + xyz + "'");
<div class="datacheck">
<div class="classic_div_data customdataid_305">
some values come here
</div>
<div class="optiondiv">
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
If you can change the HTML, though, I wouldn't use a class for this at all, I'd us a data-* attribute instead:
<div class="classic_div_data" data-custom-id="305">
then
var xyz = $(".datacheck [data-custom-id]").attr("data-custom-id");
Example:
var xyz = $(".datacheck [data-custom-id]").attr("data-custom-id");
console.log("xyz = '" + xyz + "'");
<div class="datacheck">
<div class="classic_div_data" data-custom-id="305">
some values come here
</div>
<div class="optiondiv">
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
One of the major problems you have with your current design is that if the order of the classes changes, or someone adds another class, your logic breaks. You're also getting a DOMElement from a jQuery object which you turn back in to a jQuery object again.
It would be a much better approach to use data-* attributes to store your custom data, like this:
$('.classic_div_data').click(function() {
console.log($(this).data('customdataid'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="datacheck">
<div class="classic_div_data" data-customdataid="305">
some values come here
</div>
<div class="optiondiv"></div>
</div>
<div class="datacheck">
<div class="classic_div_data" data-customdataid="205">
some more values come here
</div>
<div class="optiondiv"></div>
</div>
You can get the nth class easily from the classList of element object,
var x = $(".datacheck").find("div").get(0);
var nthClass = x.classList[1]
var res = nthClass.replace("customdataid_", "");
console.log(res); //305
You can use regex in .match() to finding last digit in class.
var digit = $(".datacheck > :first").attr("class").match(/[\d]+$/g)[0];
console.log(digit);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="datacheck">
<div class="classic_div_data customdataid_305">some values come here</div>
<div class="optiondiv"></div>
</div>

Categories