I am writing a GreaseMonkey script that goes through a page with various elements and each element has text and a button. It uses document.getElementsByClassName to find the parent elements, and it has a for loop to do something to each parent element. In this loop, I need to select a child node with a specific class and find its text value (innerHTML). I can't figure out how to select the child with a specific class of this element.
You'll want to grab the currently iterated element and use querySelector()
For example:
var elements = document.getElementsByClassName('class');
for (var i = 0, len = elements.length; i < len; i++) {
var child = elements[i].querySelector('.class_of_desired_element');
//do stuff with child
}
Note the dot before the class name in querySelector as it works similar to jQuery.
Try querySelectorAll(), which you can use to find elements within the current element.
var parent = document.getElementsByClassName('parentClass'),
parent[0].querySelectorAll('.childClass');
Depending on exactly what you are looking to do, you could also skip selecting the parent, if you don't explicitly need a reference to it.
document.querySelectorAll('.parentClass .childClass');
https://developer.mozilla.org/en-US/docs/Web/API/Element.querySelectorAll
You can use
var yourelement = document.getElementsByClass("");
var i = yourelement.nextSibling;
var e = i.nextSibling;
and keep getting the nextSibling of the element till you get it.
However, like #teddy said in the comments, I would suggest you use jQuery. It has a MUCH easier way to do it:
var value = $('.parentClass .childClass').html();
Related
I want to know if it is possible to go to a site and retrieve the text of an element
i think something like
a = page("www.site.com")
b = a.getElementByClass("name")
console.log(b.text)
this is possible?
Yes. It's called the innerText property. See https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText
That depends,
If you want to get the innerText of the elements, then
let elements = document.getElementsByClassName("YourClassName");
for(let i=0;i<elements.length; i++){
/*doSOmething*/
console.log(elements[i].innerText);
}
Many elements may have same className. So, if you want to access some specific Element, then you should either know the index of the element or you need to use id for the element.
let element = document.getElementById("YourElementId");
/*doSOmething*/
console.log(element.innerText);
I am trying to click on a specific descendent of an element. I have done gotten the ancestor by ng-class because it does not have an id.
yes = document.querySelectorAll('[ng-controller = "inventoryController"]')
Now that I have the ancestor I want, I want to get the descendent. Once again, they element does not have an id, so I use ng-src to get it.
yes2 = document.querySelectorAll('[ng-src = "link.com/link/here"]')
So How would I use this code to click on the descendent? something like this?
yes[1].yes2[0].click
First, use querySelector() to get a specific element; querySelectorAll() returns a list of all the matches.
Second, use the result of the first call instead of document to only select its descendants.
yes = document.querySelector('[ng-controller = "inventoryController"]');
yes2 = yes.querySelector('[ng-src = "link.com/link/here"]');
You can also just combine the selectors.
yes2 = document.querySelector('[ng-controller="inventoryController"] [ng-src="link.com/link/here"]');
I'm trying to move away from jQuery and to plain JavaScript, and I'm having trouble understanding how to do something. I want to have a very flexible script that will allow for multiple buttons to toggle the same menu. At first, I had this working with:
// function to add active classes on a menu and it's associated button
function toggle_menu() {
var active_class = "is-active";
var target_menu = this.dataset.menu;
var button_class_list = this.classList;
var menu_class_list = document.querySelector("[data-menu=" + target_menu + "]").classList;
button_class_list.toggle(active_class);
menu_class_list.toggle(active_class);
}
// fire toggle_menu when any menu-button is clicked
document.querySelector(".menu-button").addEventListener("click", toggle_menu);
But after thinking about it, I realized that this could allow for the menu and the buttons to get out of sync. So now my plan is to sync all instances of the buttons and the menus, such as that when you click one button, all buttons with the same [data-menu] get toggled to the same state.
But I'm confused as to how to go about this. I thought if I where to do something like
document.querySelector("[data-menu=" + target_menu + "]").toggleClass("is-active");
it would work fine, but turns out that's only affecting the first instances of a matching element, not all matching elements.
How can I change this so that all elements on the page with the same data-menu attribute always keep their is-active classes in sync?
Try something like:
var selected = document.querySelectorAll("[data-menu=" + target_menu + "]");
Array.from(selected).forEach(function(item){
item.classList.toggle("is-active");
}));
Please check querySelectorAll
Returns a list of the elements within the document (using depth-first
pre-order traversal of the document's nodes) that match the specified
group of selectors. The object returned is a NodeList.
You wanna use querySelectorAll:
var elems = document.querySelectorAll("[data-menu=" + target_menu + "]");
for (var i = 0; i < elems.length; ++i) {
elems[i].toggleClass("is-active");
}
This is the same as querySelector, but it returns all instances instead of just the first
How to cloneNode and then convert that nodeName, cuz I want the attributes copied and children deeply (https://developer.mozilla.org/en-US/docs/Web/API/Node.cloneNode?redirectlocale=en-US&redirectslug=DOM%2FNode.cloneNode)
so like: i have a span with a bunch of attributes and children. i want the same thing but i want it a div
much thanks
after i manage to clone and change to div i want to replace the span with it. also is there a way to clone all event listeners on it?
the following doesn't handle text children which are directly under the original span element, but otherwise should work fine.
mutantClone = document.createElement("div");
for (var i=0; i<original.childNodes.length; i++){
var child = original.childNodes[i];
var childClone = child.cloneNode(true);
mutantClone.appendChild(childClone);
}
I have a long list of image elements, each with it's own ID. I've already set it up so that when you click on one image, it will toggle a class "foo".
What I'd like to do is set it up so that when you click on another image, the first image's class "foo" will be removed. I'd like to do this with pure javascript if possible. Thanks.
Here's a fiddle: http://jsfiddle.net/q3aRC/
function clicked($id) {
document.getElementById($id).classList.toggle('foo');
}
I'd suggest, given that you're already using the classList api:
function clicked($id) {
// get all the elements with the class-name of 'foo':
var others = document.querySelectorAll('.foo');
// if there *are* any elements with that class-name:
if (others.length){
// iterate through that collection, removing the class-name:
for (var i = 0, len = others.length; i < len; i++){
others[i].classList.remove('foo');
}
}
/* add the class-name back (if it already had the class-name
we removed it in the previous section): */
document.getElementById($id).classList.add('foo');
}
JS Fiddle demo.
References:
document.querySelectorAll().
element.classList.
I would add a common class to all images and remove the foo class from all of them. Then I would add the class to the specific image
function clicked(id){
var images = document.getElementsByClassName('images');
for (var i = 0; i < images.length; ++i) {
images[i].classList.remove('foo');
}
document.getElementById(id).classList.add('foo');
}
Since you are already using classList I assume you're only catering to browsers new enough for addEventListener(), so I'd suggest removing all of the onclick attributes and doing something like this:
document.addEventListener('click',function(e){
if (e.target.tagName === "IMG") {
var imgs = document.getElementsByTagName('IMG');
for (var i = 0; i < imgs.length; i++)
if (imgs[i] != e.target)
imgs[i].classList.remove('foo');
e.target.classList.toggle('foo');
}
}, false);
Demo: http://jsfiddle.net/q3aRC/3/
That is, bind a single click handler to the document (or you could bind to a parent element of the images if they share a common parent), and then on click test if the clicked item is one of the elements you care about (i.e., an img) and go from there... The JS ends up about the same length, but the html ends up shorter and neater. You could actually remove the id attribute too if you weren't using it for anything other than your original clicked() function.
I used getElementsByTagName() just to show you yet another way of doing it, but getElementsByClassName() or querySelectorAll() (as in the other answers) are probably better options. But that's an easy switch to make.