How to get child element by class name? - javascript

I'm trying to get the child span that has a class = 4. Here is an example element:
<div id="test">
<span class="one"></span>
<span class="two"></span>
<span class="three"></span>
<span class="four"></span>
</div>
The tools I have available are JS and YUI2. I can do something like this:
doc = document.getElementById('test');
notes = doc.getElementsByClassName('four');
//or
doc = YAHOO.util.Dom.get('#test');
notes = doc.getElementsByClassName('four');
These do not work in IE. I get an error that the object (doc) doesn't support this method or property (getElementsByClassName). I've tried a few examples of cross browser implementations of getElementsByClassName but I could not get them to work and still got that error.
I think what I need is a cross browser getElementsByClassName or I need to use doc.getElementsByTagName('span') and loop through until I find class 4. I'm not sure how to do that though.

Use querySelector and querySelectorAll
var testContainer = document.querySelector('#test');
var fourChildNode = testContainer.querySelector('.four');
IE9 and upper

Use doc.childNodes to iterate through each span, and then filter the one whose className equals 4:
var doc = document.getElementById("test");
var notes = null;
for (var i = 0; i < doc.childNodes.length; i++) {
if (doc.childNodes[i].className == "4") {
notes = doc.childNodes[i];
break;
}
}
​

The accepted answer only checks immediate children. Often times we're looking for any descendants with that class name.
Also, sometimes we want any child that contains a className.
For example: <div class="img square"></div> should match a search on className "img", even though it's exact className is not "img".
Here's a solution for both of these issues:
Find the first instance of a descendant element with the class className
function findFirstChildByClass(element, className) {
var foundElement = null, found;
function recurse(element, className, found) {
for (var i = 0; i < element.childNodes.length && !found; i++) {
var el = element.childNodes[i];
var classes = el.className != undefined? el.className.split(" ") : [];
for (var j = 0, jl = classes.length; j < jl; j++) {
if (classes[j] == className) {
found = true;
foundElement = element.childNodes[i];
break;
}
}
if(found)
break;
recurse(element.childNodes[i], className, found);
}
}
recurse(element, className, false);
return foundElement;
}

Use element.querySelector().
Lets assume:
'myElement' is the parent element you already have.
'sonClassName' is the class of the child you are looking for.
let child = myElement.querySelector('.sonClassName');
For more info, visit: https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector

Modern solution
const context = document.getElementById('context');
const selected = context.querySelectorAll(':scope > div');
documentation

You could try:
notes = doc.querySelectorAll('.4');
or
notes = doc.getElementsByTagName('*');
for (var i = 0; i < notes.length; i++) {
if (notes[i].getAttribute('class') == '4') {
}
}

To me it seems like you want the fourth span. If so, you can just do this:
document.getElementById("test").childNodes[3]
or
document.getElementById("test").getElementsByTagName("span")[3]
This last one ensures that there are not any hidden nodes that could mess it up.

Use the name of the id with the getElementById, no # sign before it. Then you can get the span child nodes using getElementsByTagName, and loop through them to find the one with the right class:
var doc = document.getElementById('test');
var c = doc.getElementsByTagName('span');
var e = null;
for (var i = 0; i < c.length; i++) {
if (c[i].className == '4') {
e = c[i];
break;
}
}
if (e != null) {
alert(e.innerHTML);
}
Demo: http://jsfiddle.net/Guffa/xB62U/

But be aware that old browsers doesn't support getElementsByClassName.
Then, you can do
function getElementsByClassName(c,el){
if(typeof el=='string'){el=document.getElementById(el);}
if(!el){el=document;}
if(el.getElementsByClassName){return el.getElementsByClassName(c);}
var arr=[],
allEls=el.getElementsByTagName('*');
for(var i=0;i<allEls.length;i++){
if(allEls[i].className.split(' ').indexOf(c)>-1){arr.push(allEls[i])}
}
return arr;
}
getElementsByClassName('4','test')[0];
It seems it works, but be aware that an HTML class
Must begin with a letter: A-Z or a-z
Can be followed by letters (A-Za-z), digits (0-9), hyphens ("-"), and underscores ("_")

In my opinion, each time you can, you should use Array and its methods. They are much, much faster then looping over the whole DOM / wrapper, or pushing stuff into empty array. Majority of solutions presented here you can call Naive as described here (great article btw):
https://medium.com/#chuckdries/traversing-the-dom-with-filter-map-and-arrow-functions-1417d326d2bc
My solution: (live preview on Codepen: https://codepen.io/Nikolaus91/pen/wEGEYe)
const wrapper = document.getElementById('test') // take a wrapper by ID -> fastest
const itemsArray = Array.from(wrapper.children) // make Array from his children
const pickOne = itemsArray.map(item => { // loop over his children using .map() --> see MDN for more
if(item.classList.contains('four')) // we place a test where we determine our choice
item.classList.add('the-chosen-one') // your code here
})

using querySelector
var doc=document.getElementById("test");
console.log(doc.querySelector('.two').innerHTML)
<div id="test">
<span class="one"></span>
<span class="two">two</span>
<span class="three"></span>
<span class="four"></span>
</div>
Using querySelectorAll
var doc=document.getElementById("test");
console.log(doc.querySelectorAll('*')[1].innerHTML)
<div id="test">
<span class="one"></span>
<span class="two">two</span>
<span class="three"></span>
<span class="four"></span>
</div>
using getElementsByTagNames
var doc=document.getElementById("test");
console.log(doc.getElementsByTagName("SPAN")[1].innerHTML);
<div id="test">
<span class="one"></span>
<span class="two">two</span>
<span class="three"></span>
<span class="four"></span>
</div>
<span>ss</span>
Using getElementsByClassName
var doc=document.getElementById("test");
console.log(doc.getElementsByClassName('two')[0].innerHTML)
<div id="test">
<span class="one"></span>
<span class="two">two</span>
<span class="three"></span>
<span class="four"></span>
</div>

I believe this would answer your question best
document.querySelector('* > span.four')
This will match the first child element (of any parent) it finds that is a span and also has a class "four" set to it
However since in your example you also had a parent element which you are able to retrieve by id, you could also use this instead
document.querySelector('#test > span.four')
If you have a parent element saved in a variable like in your example, and you wish to search the subtree of that element, using :scope, as Billizzard has mentioned already, is probably your best choice
doc.querySelector(':scope > span.four');
Little extra: If the child element you are looking for isn't a direct child descendent, but somewhere further down the subtree, you can actually just omit the > like so
document.querySelector('#test span.four')

The way i will do this using jquery is something like this..
var targetedchild = $("#test").children().find("span.four");

You can fetch the parent class by adding the line below. If you had an id, it would be easier with getElementById. Nonetheless,
var parentNode = document.getElementsByClassName("progress__container")[0];
Then you can use querySelectorAll on the parent <div> to fetch all matching divs with class .progress__marker
var progressNodes = progressContainer.querySelectorAll('.progress__marker');
querySelectorAll will fetch every div with the class of progress__marker

Another way
const result = [...(parentElement.children)].find(child => {
return child.classList.contains('some-class-name');
});
First we spread the elements of the NodeList to turn it into an Array so we can make use of the find() method. Lastly, find() will return to us the first element whose classList property contains the given class name.

Here is a relatively simple recursive solution. I think a breadth-first search is appropriate here. This will return the first element matching the class that is found.
function getDescendantWithClass(element, clName) {
var children = element.childNodes;
for (var i = 0; i < children.length; i++) {
if (children[i].className &&
children[i].className.split(' ').indexOf(clName) >= 0) {
return children[i];
}
}
for (var i = 0; i < children.length; i++) {
var match = getDescendantWithClass(children[i], clName);
if (match !== null) {
return match;
}
}
return null;
}

I know this question is a few years old and there have been a few answers to this but I thought I would add my solution just in case it helps anyone. It's in the same vein as the answer given by user2795540 and involves an array iterator.
If you're just wanting to get the first child that has the four class then you could use the find array iterator. Your browser will need to be able to support ES6 or you can use Babel to compile your JS into something all browsers will support. IE will not support this without a polyfill.
Using the same details you provided in your question it could look something like this:
const parentNode = document.getElementById('test');
const childNode = Array.from(parentNode.childNodes).find(({ className }) => className === 'four');
The above solution will return the node you want to target and store it in the childNode variable.
You can find out more about the find array iterator at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find

June 2018 update to ES6
const doc = document.getElementById('test');
let notes = null;
for (const value of doc) {
if (value.className === '4') {
notes = value;
break;
}
}

let notes = document.querySelector('#test .four')

YUI2 has a cross-browser implementation of getElementsByClassName.

Here is how I did it using the YUI selectors. Thanks to Hank Gay's suggestion.
notes = YAHOO.util.Dom.getElementsByClassName('four','span','test');
where four = classname, span = the element type/tag name, and test = the parent id.

Use YAHOO.util.Dom.getElementsByClassName() from here.

Related

Two blocks in getElementById [duplicate]

doStuff(document.getElementById("myCircle1" "myCircle2" "myCircle3" "myCircle4"));
This doesn't work, so do I need a comma or semi-colon to make this work?
document.getElementById() only supports one name at a time and only returns a single node not an array of nodes. You have several different options:
You could implement your own function that takes multiple ids and returns multiple elements.
You could use document.querySelectorAll() that allows you to specify multiple ids in a CSS selector string .
You could put a common class names on all those nodes and use document.getElementsByClassName() with a single class name.
Examples of each option:
doStuff(document.querySelectorAll("#myCircle1, #myCircle2, #myCircle3, #myCircle4"));
or:
// put a common class on each object
doStuff(document.getElementsByClassName("circles"));
or:
function getElementsById(ids) {
var idList = ids.split(" ");
var results = [], item;
for (var i = 0; i < idList.length; i++) {
item = document.getElementById(idList[i]);
if (item) {
results.push(item);
}
}
return(results);
}
doStuff(getElementsById("myCircle1 myCircle2 myCircle3 myCircle4"));
This will not work, getElementById will query only one element by time.
You can use document.querySelectorAll("#myCircle1, #myCircle2") for querying more then one element.
ES6 or newer
With the new version of the JavaScript, you can also convert the results into an array to easily transverse it.
Example:
const elementsList = document.querySelectorAll("#myCircle1, #myCircle2");
const elementsArray = [...elementsList];
// Now you can use cool array prototypes
elementsArray.forEach(element => {
console.log(element);
});
How to query a list of IDs in ES6
Another easy way if you have an array of IDs is to use the language to build your query, example:
const ids = ['myCircle1', 'myCircle2', 'myCircle3'];
const elements = document.querySelectorAll(ids.map(id => `#${id}`).join(', '));
No, it won't work.
document.getElementById() method accepts only one argument.
However, you may always set classes to the elements and use getElementsByClassName() instead. Another option for modern browsers is to use querySelectorAll() method:
document.querySelectorAll("#myCircle1, #myCircle2, #myCircle3, #myCircle4");
I suggest using ES5 array methods:
["myCircle1","myCircle2","myCircle3","myCircle4"] // Array of IDs
.map(document.getElementById, document) // Array of elements
.forEach(doStuff);
Then doStuff will be called once for each element, and will receive 3 arguments: the element, the index of the element inside the array of elements, and the array of elements.
getElementByID is exactly that - get an element by id.
Maybe you want to give those elements a circle class and getElementsByClassName
document.getElementById() only takes one argument. You can give them a class name and use getElementsByClassName() .
Dunno if something like this works in js, in PHP and Python which i use quite often it is possible.
Maybe just use for loop like:
function doStuff(){
for(i=1; i<=4; i++){
var i = document.getElementById("myCiricle"+i);
}
}
Vulgo has the right idea on this thread. I believe his solution is the easiest of the bunch, although his answer could have been a little more in-depth. Here is something that worked for me. I have provided an example.
<h1 id="hello1">Hello World</h1>
<h2 id="hello2">Random</h2>
<button id="click">Click To Hide</button>
<script>
document.getElementById('click').addEventListener('click', function(){
doStuff();
});
function doStuff() {
for(var i=1; i<=2; i++){
var el = document.getElementById("hello" + i);
el.style.display = 'none';
}
}
</script>
Obviously just change the integers in the for loop to account for however many elements you are targeting, which in this example was 2.
The best way to do it, is to define a function, and pass it a parameter of the ID's name that you want to grab from the DOM, then every time you want to grab an ID and store it inside an array, then you can call the function
<p id="testing">Demo test!</p>
function grabbingId(element){
var storeId = document.getElementById(element);
return storeId;
}
grabbingId("testing").syle.color = "red";
You can use something like this whit array and for loop.
<p id='fisrt'>??????</p>
<p id='second'>??????</p>
<p id='third'>??????</p>
<p id='forth'>??????</p>
<p id='fifth'>??????</p>
<button id="change" onclick="changeColor()">color red</button>
<script>
var ids = ['fisrt','second','third','forth','fifth'];
function changeColor() {
for (var i = 0; i < ids.length; i++) {
document.getElementById(ids[i]).style.color='red';
}
}
</script>
For me worked flawles something like this
doStuff(
document.getElementById("myCircle1") ,
document.getElementById("myCircle2") ,
document.getElementById("myCircle3") ,
document.getElementById("myCircle4")
);
Use jQuery or similar to get access to the collection of elements in only one sentence. Of course, you need to put something like this in your html's "head" section:
<script type='text/javascript' src='url/to/my/jquery.1.xx.yy.js' ...>
So here is the magic:
.- First of all let's supose that you have some divs with IDs as you wrote, i.e.,
...some html...
<div id='MyCircle1'>some_inner_html_tags</div>
...more html...
<div id='MyCircle2'>more_html_tags_here</div>
...blabla...
<div id='MyCircleN'>more_and_more_tags_again</div>
...zzz...
.- With this 'spell' jQuery will return a collection of objects representing all div elements with IDs containing the entire string "myCircle" anywhere:
$("div[id*='myCircle']")
This is all! Note that you get rid of details like the numeric suffix, that you can manipulate all the divs in a single sentence, animate them... Voilá!
$("div[id*='myCircle']").addClass("myCircleDivClass").hide().fadeIn(1000);
Prove this in your browser's script console (press F12) right now!
As stated by jfriend00,
document.getElementById() only supports one name at a time and only returns a single node not an array of nodes.
However, here's some example code I created which you can give one or a comma separated list of id's. It will give you one or many elements in an array. If there are any errors, it will return an array with an Error as the only entry.
function safelyGetElementsByIds(ids){
if(typeof ids !== 'string') return new Error('ids must be a comma seperated string of ids or a single id string');
ids = ids.split(",");
let elements = [];
for(let i=0, len = ids.length; i<len; i++){
const currId = ids[i];
const currElement = (document.getElementById(currId) || new Error(currId + ' is not an HTML Element'));
if(currElement instanceof Error) return [currElement];
elements.push(currElement);
};
return elements;
}
safelyGetElementsByIds('realId1'); //returns [<HTML Element>]
safelyGetElementsByIds('fakeId1'); //returns [Error : fakeId1 is not an HTML Element]
safelyGetElementsByIds('realId1', 'realId2', 'realId3'); //returns [<HTML Element>,<HTML Element>,<HTML Element>]
safelyGetElementsByIds('realId1', 'realId2', 'fakeId3'); //returns [Error : fakeId3 is not an HTML Element]
If, like me, you want to create an or-like construction, where either of the elements is available on the page, you could use querySelector. querySelector tries locating the first id in the list, and if it can't be found continues to the next until it finds an element.
The difference with querySelectorAll is that it only finds a single element, so looping is not necessary.
document.querySelector('#myCircle1, #myCircle2, #myCircle3, #myCircle4');
here is the solution
if (
document.getElementById('73536573').value != '' &&
document.getElementById('1081743273').value != '' &&
document.getElementById('357118391').value != '' &&
document.getElementById('1238321094').value != '' &&
document.getElementById('1118122010').value != ''
) {
code
}
You can do it with document.getElementByID Here is how.
function dostuff (var here) {
if(add statment here) {
document.getElementById('First ID'));
document.getElementById('Second ID'));
}
}
There you go! xD

Vanilla JavaScript equivalent of jQuery(…).parent().nextAll(selector)

I’m trying to have a vanilla JavaScript selector (without using jQuery) to get the same selection as shown below:
$('[data-automationid=pictureupload_1]').parent().nextAll('input[type=text]')
Can someone please help me? I’ve been struggling with it.
There is no nextAll method in DOM as far as I know, so it is a bit tricky to do that without using jQuery.
We can use a generator to iterate and filter nextElementSibling like this:
function* myNextAll(e, selector) {
while (e = e.nextElementSibling) {
if ( e.matches(selector) ) {
yield e;
}
}
}
let e1 = document.querySelector("[data-automationid=pictureupload_1]").parentElement;
let siblings = [...myNextAll(e1, "input[type=text]")];
Use document.querySelector('[data-automationid=pictureupload_1]') to select the starting-node.
Get with parentElement.children all the siblings from the parent-node (including the parent itself).
Iterate through the siblings until the parent-node is founded.
Look for all other siblings if they are INPUT-nodes and from type text (=1).
Collect them in an array.
For demonstration iterate over the result and change the background via test-class.
If you want try: https://jsfiddle.net/7p8wt4km/2/
let result = [];
let par = document.querySelector('[data-automationid=pictureupload_1]').parentElement;
let sibling = par.parentElement.children;
let found = false;
for (let i=0; i< sibling.length; i++) {
if (!found && sibling[i] ===par) {
found = true;
continue;
} else if (found) {
let sib = sibling[i];
if (sib.nodeName !== 'INPUT' || sib.nodeType!= 1) continue;
result.push(sib);
}
}
result.forEach(el => { el.classList.add('test');});
.test { background: green; }
<div>
<div>
Sibling 0
</div>
<div>
Parent
<div data-automationid='pictureupload_1'>
pictureupload_1
</div>
</div>
<input type='text'>
<div type='text'>
Sibling 2
</div>
<input type='test'>
<input type='checkbox'>
</div>
You can try my code get with index element
const getIndex = (node, groupNode) => {
return [...groupNode].indexOf(node);
}
Element.prototype.nextAll = function(){
var allChildren = this.parentNode.children;
var index = getIndex(this, allChildren);
allChildren = [...allChildren].filter((item) => {
return getIndex(item, allChildren) > index;
});
return allChildren;
}
The normal jQuery selector function and the parent method should be clear:
document.querySelector("[data-automationid=pictureupload_1]").parentNode
nextAll doesn’t currently have a vanilla JavaScript equivalent, but we can make one out of native DOM methods.
There are two ways of approaching it:
Select all children first, then filter all matching siblings after a certain element, or
using loops.
1. Select all children first, then filter all matching siblings after a certain element
Getting the set of siblings can be partially achieved with .parentNode.children.
But don’t worry about selecting the parent element itself, because filtering by DOM order is easy.
This uses Node.prototype.compareDocumentPosition and Element.prototype.matches.
I’ve also included some optional chaining so that if parentReference === document, parentReference.parentNode.children won’t throw an error.
It defaults to an empty array, then.
const selectParentMatchingNextSiblings = (jQuerySelector, siblingSelector) => {
const parentReference = document.querySelector(jQuerySelector).parentNode;
return Array.from(parentReference.parentNode?.children ?? [])
.filter((element) => parentReference.compareDocumentPosition(element) & Document.DOCUMENT_POSITION_FOLLOWING && element.matches(siblingSelector));
};
selectParentMatchingNextSiblings("[data-automationid=pictureupload_1]", "input[type=text]");
Alternative way with Ranges
The Range API can also be used for document order comparison.
const selectParentMatchingNextSiblings = (jQuerySelector, siblingSelector) => {
const parentReference = document.querySelector(jQuerySelector).parentNode,
nextSiblings = document.createRange();
nextSiblings.setStartAfter(parentReference);
nextSiblings.setEndAfter(parentReference.parentNode?.lastElementChild ?? parentReference);
return Array.from(parentReference.parentNode?.children ?? [])
.filter((element) => nextSiblings.comparePoint(element, 0) === 0 && element.matches(siblingSelector));
};
selectParentMatchingNextSiblings("[data-automationid=pictureupload_1]", "input[type=text]");
Note that this one won’t work with "html" as the first selector.
2. Using loops
const selectMatchingNextSiblings = (jQuerySelector, siblingSelector) => {
const parentReference = document.querySelector(jQuerySelector).parentNode,
result = [];
let currentElement = parentReference.nextElementSibling;
while(currentElement){
if(currentElement.matches(siblingSelector)){
result.push(currentElement);
}
currentElement = currentElement.nextElementSibling;
}
return result;
};
selectParentMatchingNextSiblings("[data-automationid=pictureupload_1]", "input[type=text]");
This should be self-explanatory.
The options from the other answers are also fine.

getElementsByClassName, recursion, one parameter, no underscore.js

I am trying to write getElementsByClassName() without using the getElementsByClassName method or the _. methods. I want to use recursion with the function having only one parameter, then push each value into an array. Afterword return that array. Below is my code so far. I have tried several versions, what am I doing wrong? Thank you for your help.
I realize that this question has been asked before and answered. However, I am trying to write the function using only one parameter, others use two. I am also using no _. underscore methods, others use underscore. I need to use recursion using no underscore, only one parameter, and can not use the getElementsByClassName method. I have been working on this for quite awhile and would love some help thanks!
var getElementsByClassName = function(className) {
var nodeArray = [];
var fakeNode = [1,2,3,4,5,6,7];
// var variableNode = document.getElementsByClassName(className); // ['element 1', 'element 2', 'element 3']
if(document.nodeName === className) {
var variableNode = document.querySelector(className);
// base case:
if (variableNode.length === 0) {
return [];
// rec case:
} else {
for(var i = 0; i < variableNode.length; i++) {
nodeArray.push(variableNode[i]);
}
getElementsByClassName();
}
}
return nodeArray;
};
In order to do this recursively, you need to recurse through the DOM hierarchy. This means that the function has to take a DOM node to start at, then make recursive calls on all its children. At each level it creates a result array; it adds the current node if it matches the criteria, concatenates the results from the children, and then returns this result.
function getElementsByClassName(className, node = document) {
var nodeArray = [];
if (node.classList && node.classList.contains(className)) {
nodeArray.push(node);
}
if (node.children) {
for (var i = 0; i < node.children.length; i++) {
nodeArray = nodeArray.concat(getElementsByClassName(className, node.children[i]));
}
}
return nodeArray;
}
console.log(getElementsByClassName("a").map(e => e.id));
console.log(getElementsByClassName("b").map(e => e.id));
<div id="foo" class="a">
<div id="bar" class="b">
<span id="span-1" class="a">abc</span>
<span id="span-2" class="b">def</span>
</div>
<h1 id="header-1" class="a">Header</h1>
</div>
The base of the recursion is when you get to a node with no children, because node.childNodes.length will be 0 and it won't go into the loop.
Notice the default value for the node argument. This allows you to call the function with one argument to search the entire document, but it will use the second argument when it recurses.

ID Ends With in pure Javascript

I am working in a Javascript library that brings in jQuery for one thing: an "ends with" selector. It looks like this:
$('[id$=foo]')
It will find the elements in which the id ends with "foo".
I am looking to do this without jQuery (straight JavaScript). How might you go about this? I'd also like it to be as efficient as reasonably possible.
Use querySelectorAll, not available in all browsers (like IE 5/6/7/8) though. It basically works like jQuery:
http://jsfiddle.net/BBaFa/2/
console.log(document.querySelectorAll("[id$=foo]"));
You will need to iterate over all elements on the page and then use string functions to test it. The only optimizations I can think of is changing the starting point - i.e. not document.body but some other element where you know your element will be a child of - or you could use document.getElementsByTagName() to get an element list if you know the tag name of the elements.
However, your task would be much easier if you could use some 3rd-party-javascript, e.g. Sizzle (4k minified, the same selector engine jQuery uses).
So, using everything that was said, I put together this code. Assuming my elements are all inputs, then the following code is probably the best I am going to get?
String.prototype.endsWith = function(suffix) {
return this.indexOf(suffix, this.length - suffix.length) !== -1;
};
function getInputsThatEndWith(text) {
var result = new Array();
var inputs = document.getElementsByTagName("input");
for(var i=0; i < inputs.length; i++) {
if(inputs[i].id.endsWith(text))
result.push(inputs[i]);
}
return result;
}
I put it on JsFiddle: http://jsfiddle.net/MF29n/1/
#ThiefMaster touched on how you can do the check, but here's the actual code:
function idEndsWith(str)
{
if (document.querySelectorAll)
{
return document.querySelectorAll('[id$="'+str+'"]');
}
else
{
var all,
elements = [],
i,
len,
regex;
all = document.getElementsByTagName('*');
len = all.length;
regex = new RegExp(str+'$');
for (i = 0; i < len; i++)
{
if (regex.test(all[i].id))
{
elements.push(all[i]);
}
}
return elements;
}
}
This can be enhanced in a number of ways. It currently iterates through the entire dom, but would be more efficient if it had a context:
function idEndsWith(str, context)
{
if (!context)
{
context = document;
}
...CODE... //replace all occurrences of "document" with "context"
}
There is no validation/escaping on the str variable in this function, the assumption is that it'll only receive a string of chars.
Suggested changes to your answer:
RegExp.quote = function(str) {
return str.replace(/([.?*+^$[\]\\(){}-])/g, "\\$1");
}; // from https://stackoverflow.com/questions/494035/#494122
String.prototype.endsWith = function(suffix) {
return !!this.match(new RegExp(RegExp.quote(suffix) + '$'));
};
function getInputsThatEndWith(text) {
var results = [],
inputs = document.getElementsByTagName("input"),
numInputs = inputs.length,
input;
for(var i=0; i < numInputs; i++) {
var input = inputs[i];
if(input.id.endsWith(text)) results.push(input);
}
return results;
}
http://jsfiddle.net/mattball/yJjDV/
Implementing String.endsWith using a regex instead of indexOf() is mostly a matter of preference, but I figured it was worth including for variety. If you aren't concerned about escaping special characters in the suffix, you can remove the RegExp.quote() bit, and just use
new RegExp(suffix + '$').
If you know the type of DOM elements you are targeting,
then get a list of references to them using getElementsByTagName , and then iterate over them.
You can use this optimization to fasten the iterations:
ignore the elements not having id.
target the nearest known parent of elements you want to seek, lets say your element is inside a div with id='myContainer', then you can get a restricted subset using
document.getElementById('myContainer').getElementsByTagName('*') , and then iterate over them.

Getting the contents of an element WITHOUT its children [duplicate]

This question already has answers here:
How to get the text node of an element?
(11 answers)
Closed 6 months ago.
I have a mild preference in solving this in pure JS, but if the jQuery version is simpler, then jQuery is fine too. Effectively the situation is like this
<span id="thisone">
The info I want
<span id="notthisone">
I don't want any of this nonsense
</span>
</span>
I effectively want to get
The info I want
but not
The info I want I don't want any of this nonsense
and I especially don't want
The info I want <span id="notthisone"> I don't want any of this nonsense </span>
which is unfortunately what I am getting right now...
How would I do this?
With js only:
Try it out: http://jsfiddle.net/g4tRn/
var result = document.getElementById('thisone').firstChild.nodeValue;
​alert(result);​
With jQuery:
Try it out: http://jsfiddle.net/g4tRn/1
var result = $('#thisone').contents().first().text();
alert(result);​
Bonus:
If there are other text nodes in the outer <span> that you want to get, you could do something like this:
Try it out: http://jsfiddle.net/g4tRn/4
var nodes = document.getElementById('thisone').childNodes;
var result = '';
for(var i = 0; i < nodes.length; i++) {
if(nodes[i].nodeType == 3) { // If it is a text node,
result += nodes[i].nodeValue; // add its text to the result
}
}
alert(result);
​
If you just want the first child then it's rather simple. If you are looking for the first text-only element then this code will need some modification.
var text = document.getElementById('thisone').firstChild.nodeValue;
alert(text);
Have you tried something like this?
var thisone = $("#thisone").clone();
thisone.children().remove();
var mytext = thisone.html();
FROM: http://viralpatel.net/blogs/2011/02/jquery-get-text-element-without-child-element.html
$("#foo")
.clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.text(); //get the text of element
Pure JavaScript
In this pure JavaScript example, I account for the possibility of multiple text nodes that could be interleaved with other kinds of nodes. Pass a containing NodeList in from calling / client code.
function getText (nodeList, target)
{
var trueTarget = target - 1;
var length = nodeList.length; // Because you may have many child nodes.
for (var i = 0; i < length; i++) {
if ((nodeList[i].nodeType === Node.TEXT_NODE) && (i === trueTarget)) {
return nodeList.childNodes[i].nodeValue;
}
}
return null;
}
You might use this function to create a wrapper function that uses this one to accumulate multiple text values.
To get a string of the child text nodes and not the element or other child nodes from a given element:
function getTextNodesText(el) {
return Array.from(el.childNodes)
.filter((child) => child.nodeType === Node.TEXT_NODE)
.map((child) => child.textContent)
.join("");
}

Categories