Create a function to get selectors like jquery does with pure javascript - javascript

I am tired of including jquery in simple projects but I am so used to using it and I am trying to break free form my dependency on it. I am trying to create a function that will give the same feel of getting selectors like classes and tags. Example: $('selector').innerHTML = ".something";. I have just been looping through them one by one like so:
var classElements = document.querySelectorAll('.something');
for (var i = classElements.length - 1; i >= 0; i--) {
classElements[i].innerHTML = "This Is A Div";
}
But I wanted to create a function where I could just loop through a selector without having to write out a for loop for everything that I want to find. So I could just write it our like above $('.something').innerHTML = "something";
So far this is what I have but it will only get the first of each selector and won't get all of them. Needless to say I am very stuck and the more I read on the subject the more confused I get. I was wondering if someone could point me in the right direction where my thinking is flawed or explain how jquery goes about doing this. Here is my code:
window.getElements = function(selector) {
var selectors = document.querySelectorAll(selector);
for (var i = selectors.length - 1; i >= 0; i--) {
var elements = selectors[i];
}
return elements;
};
getElements(".something").innerHTML = "something";
Here is a fiddle Fiddle

Here is how you would do it. I have done what you have asked which is allow you to use all the native functionality rather than coin wrappers around it. jQuery returns its own api which acts on the selectors. What I have done is create a selector which allows you to act on each element it finds
window.getElements = function(selector,cb) {
var selectors = document.querySelectorAll(selector);
[].forEach.call(selectors, cb);
};
getElements(".something", function(el){el.innerHTML = "ha"});
getElements("#one", function(el){el.style.background = "red" });
It takes the dom list that is found, converts it into an array and then calls your passed function where you pass your native code
Here is a fiddle
https://jsfiddle.net/y52f4wh8/5/
Jquery works differently:
window.jquery = function(selector,cb) {
var selectors = document.querySelectorAll(selector);
function command(cb) {
[].forEach.call(selectors, cb);
};
// Here we return our own api that uses the command function to act on
// our selected list.
return {
html: function(str){
command(function(el){
el.innerHTML=str;
});
},
bg: function(color){
command(function(el){
el.style.background = color;
});
}
}
};
// The jquery way!
jquery(".something").html("ha");

getElements(".something").innerHTML = "something";
this does not work because that your function gets and returns all of the elements, which is a NodeList, but it does not automatically apply methods to every element in the collection as jQuery does. In order to do that, you would have to convert the elements to an array and actually call the function on each element using a loop or some other function.
EDIT: To be clear, you cannot just call NodeList.innerHTML = '' on a NodeList because innerHTML is applied to one element. jQuery internally takes care of BOTH of the collecting of elements, and the applying of methods for you.
EDIT #2: After examining your function more carefully, I have realized there are other issues, but what I wrote above is still the basis from which you want to spring.
You could use something like this for getting elements?:
function getElements(elements) {
return [...querySelectorAll(elements)]
}
But applying functions on nodes is going to be more selective on a case-by-case basis since many of them are applied differently.

The selector part of JQuery is called Sizzle. It has all the functionality that you need but does not come with the other parts of JQuery.
If you would like to find out more about the javascript behind it, I recommend to take a look at the sourcefiles of Sizzle.

jQuery is essentially a wrapper object for NodeList which adds more functionality to DOM operations. If you want to create your own wrapper object which defines functions for bulk versions of all the Element API, you are free to do so, but then you might as well use jQuery or some derivative.
If you want an extremely lightweight proxy object for doing bulk operations on DOM elements, there is the Proxy object in ES6 which can make this very easy to do, but has no IE support.
const $ = function(selector) {
const nodeList = document.querySelectorAll(selector);
return new Proxy(nodeList, {
set: function(target, property, value) {
for (let i = 0; i < target.length; i++) {
target[i][property] = value;
}
},
get: function(target, property) {
return target[0] && target[0][property];
}
});
};
console.log($('p').innerHTML);
$('p').innerHTML = 'Bulk assignement!';
<p>A B C</p>
<p>1 2 3</p>
<p>Do Re Mi</p>

An approach which would be best avoided is to define a setter for innerHTML on NodeList.
Object.defineProperty(NodeList.prototype, 'innerHTML', {
set(text) {
[...this].forEach(elt => elt.innerHTML = text);
}
});
const $ = selector => document.querySelectorAll(selector);
$('.foo').innerHTML = "it works";
<div class="foo"></div>
<div class="foo"></div>

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

how to make a class accept a method without specifying the method in advance?

If i have something like this :
function foo(class){
for(i=0; i<(class.length);i++){
return document.getElementsByClassName(class)[i];
}
}
And now i want to do something like this:
foo("someclass").innerHTML="something";
it will do it only for the first element and i understand why this happens and how to make it work correctly, but how can i make the function get other methods without telling it in the loop exactly what to do,like this
foo("someclass").innerHTML="something";//this to put something inside the element
foo("someclass").style.backgroundColor="#000");// and this to work also
So,if its possible,how can i make the function do this without putting these methods in the foo function loop? Is there a way to put these methods in a variable like this
function foo(class).variableMethod{
for(i=0; i<(class.length);i++){
document.getElementsByClassName(class)[i].variableMethod;
}
}
Is this possible?
You can pass a function to foo(), and have foo() call that function with each matched element:
function foo(className, func)
{
var elements = document.getElementsByClassName(className);
for (var i = 0; i < elements.length; ++i) {
func(elements[i]);
}
}
Now you can do something like:
foo("someclass", function(element) {
element.innerHTML = "something";
element.style.backgroundColor = "#000";
});
Just to add to the other great answers here, one thing you could do is create on override method called innerHtml. You could then have innerHtml check for a collection as well as a single instance and opperate as required.
UPDATE
Here's a quick example of method chaining. Here I basically obtain a collection of elements based on tag name and set their value using a val() method that I created using the Javascript prototype object.
function Foo(tagName)
{
this.collection = document.getElementsByTagName(tagName);
return this;
}
Foo.prototype.val= function(value){
for(var i = 0; i < this.collection.length; i++)
{
this.collection[i].innerHTML = value;
}
}
var x = new Foo("li").val("Hello World");
You can see a working demo of this here: http://jsfiddle.net/E48ym/1/
Frédéric Hamidi's answer will do what you want I think, but you could also use a framework like jQuery - this is the kind of thing it was designed for. So you could do:
$('.className').text('something');
to set the text of all elements with a class of className to something, or
$('.className').css('background-color', '#000');
to change the background color of all elements with a class of className.

Javascript Shorthand for getElementById

Is there any shorthand for the JavaScript document.getElementById? Or is there any way I can define one? It gets repetitive retyping that over and over.
var $ = function( id ) { return document.getElementById( id ); };
$( 'someID' )
Here I used $, but you can use any valid variable name.
var byId = function( id ) { return document.getElementById( id ); };
byId( 'someID' )
To save an extra character you could pollute the String prototype like this:
pollutePrototype(String, '绎', {
configurable: false, // others must fail
get: function() {
return document.getElementById(this);
},
set: function(element) {
element.id = this;
}
});
function pollutePrototype(buildIn, name, descr) {
var oldDescr = Object.getOwnPropertyDescriptor(buildIn.prototype, name);
if (oldDescr && !oldDescr.configurable) {
console.error('Unable to replace ' + buildIn.name + '.prototype.' + name + '!');
} else {
if (oldDescr) {
console.warn('Replacing ' + buildIn.name + '.prototype.' + name + ' might cause unexpected behaviour.');
}
Object.defineProperty(buildIn.prototype, name, descr);
}
}
It works in some browsers and you can access elements this way:
document.body.appendChild(
'footer'.绎 = document.createElement('div')
);
'footer'.绎.textContent = 'btw nice browser :)';
I have chosen the name of the property almost randomly. If you actually wanted to use this shorthand I would suggest coming up with something easier to type.
You can easily create shorthand easily yourself:
function getE(id){
return document.getElementById(id);
}
id's are saved to the window.
HTML
<div id='logo'>logo</div>
JS
logo.innerHTML;
is the same as writing:
document.getElementById( 'logo' ).innerHtml;
I don't suggest using the former method as it is not common practice.
A quick alternative to contribute:
HTMLDocument.prototype.e = document.getElementById
Then just do:
document.e('id');
There's a catch, it doesn't work in browsers that don't let you extend prototypes (e.g. IE6).
(Shorthand for not only getting element by ID, but also getting element by class :P)
I use something like
function _(s){
if(s.charAt(0)=='#')return [document.getElementById(s.slice(1))];
else if(s.charAt(0)=='.'){
var b=[],a=document.getElementsByTagName("*");
for(i=0;i<a.length;i++)if(a[i].className.split(' ').indexOf(s.slice(1))>=0)b.push(a[i]);
return b;
}
}
Usage : _(".test") returns all elements with class name test, and _("#blah") returns an element with id blah.
<script>
var _ = function(eId)
{
return getElementById(eId);
}
</script>
<script>
var myDiv = _('id');
</script>
There are several good answers here and several are dancing around jQuery-like syntax, but not one mentions actually using jQuery. If you're not against trying it, check out jQuery. It let's you select elements super easy like this..
By ID:
$('#elementId')
By CSS class:
$('.className')
By element type:
$('a') // all anchors on page
$('inputs') // all inputs on page
$('p a') // all anchors within paragaphs on page
There's none built-in.
If you don't mind polluting the global namespace, why not:
function $e(id) {
return document.getElementById(id);
}
EDIT - I changed the function name to be something unusual, but short and not otherwise clashing with jQuery or anything else that uses a bare $ sign.
I frequently use:
var byId='getElementById'
var byClass='getElementsByClass'
var byTag='getElementsByTag'
var mydiv=document[byId]('div')
/* as document["getElementById"] === document.getElementById */
I think it's better than a external function (e.g. $() or byId()) because you can do things like this:
var link=document[byId]('list')[byClass]('li')[0][byTag]('a')[0]
Btw, don't use jQuery for this, jQuery is much, much slower than document.getElementById(), an external function like $() or byId(), or my method: http://jsperf.com/document-getelementbyid-vs-jquery/5
Yes, it gets repetitive to use the same function over and over each time with a different argument:
var myImage = document.getElementById("myImage");
var myDiv = document.getElementById("myDiv");
So a nice thing would be a function that takes all those arguments at the same time:
function getElementsByIds(/* id1, id2, id3, ... */) {
var elements = {};
for (var i = 0; i < arguments.length; i++) {
elements[arguments[i]] = document.getElementById(arguments[i]);
}
return elements;
}
Then you would have references to all your elements stored in one object:
var el = getElementsByIds("myImage", "myDiv");
el.myImage.src = "test.gif";
But you would still have to list all those ids.
You could simplify it even more if you want all elements with ids:
function getElementsWithIds() {
var elements = {};
var elementList = document.querySelectorAll("[id]");
for (var i = 0; i < elementList.length; i++) {
elements[elementList[i].id] = elementList[i];
}
return elements;
}
But it would be pretty expensive to call this function if you have many elements.
So, theoretically, if you would use the with keyword you could write code like this:
with (getElementsByIds('myButton', 'myImage', 'myTextbox')) {
myButton.onclick = function() {
myImage.src = myTextbox.value;
};
}
But I don't want to promote the use of with. Probably there's a better way to do it.
Well, you could create a shorthand function, that's what I do.
function $(element) {
return document.getElementById(element);
}
and then when you wanted to get it, you just do
$('yourid')
Also, another useful trick that I found, is that if you want to get the value or innerHTML of an item ID, you can make functions like this:
function $val(el) {
return $(el).value;
}
function $inner(el) {
return $(el).innerHTML;
}
Hope you like it!
I actually made a kind of mini javascript library based on this whole idea.
Here it is.
If this is on your own site, consider using a library like jQuery to give you this and many other useful shorthands that also abstract away browser differences. Personally, if I wrote enough code to be bothered by the longhand, I would include jQuery.
In jQuery, the syntax would be $("#someid"). If you then want the actual DOM element and not the jQuery wrapper, it's $("#someid")[0], but you could most likely do whatever you're after with the jQuery wrapper.
Or, if you're using this in a browser developer console, research their built-in utilities. As someone else mentioned, the Chrome JavaScript console includes a $("someid") method, and you can also click an element in the developer tools "Elements" view and then reference it with $0 from the console. The previously selected element becomes $1 and so on.
If the only issue here is typing, maybe you should just get yourself a JavaScript editor with intellisense.
If the purpose is to get shorter code, then you could consider a JavaScript library like jQuery, or you can just write your own shorthand functions, like:
function byId(string) {return document.getElementById(string);}
I used to do the above for better performance. What I learnt last year is that with compression techniques the server does it automatically for you, so my shortening technique was actually making my code heavier. Now I am just happy with typing the whole document.getElementById.
If you are asking for a shorthand function...
<!DOCTYPE html>
<html>
<body>
The content of the body element is displayed in your browser.
<div id="d1">DIV</div>
<script>
var d=document;
d.g=document.getElementById;
d.g("d1").innerHTML = "catch";
</script>
</body>
</html>
or
<!DOCTYPE html>
<html>
<body>
The content of the body element is displayed in your browser.
<div id="d1">DIV</div>
<script>
var w=window;
w["d1"].innerHTML = "catch2";
</script>
</body>
Arrow functions make is shorter.
var $id = (id) => document.getElementById(id);
wrap the document.querySelectorAll ... a jquery like select
function $(selector){
var s = document.querySelectorAll(selector);
return s.length > 1 ? s : s[0];
}
// usage: $('$myId')
Well, if the id of the element does not compete with any properties of the global object, you don't have to use any function.
myDiv.appendChild(document.createTextNode("Once I was myDiv. "));
myDiv.id = "yourDiv";
yourDiv.appendChild(document.createTextNode("But now I'm yourDiv."));
edit: But you don't want to make use of this 'feature'.
Another wrapper:
const IDS = new Proxy({}, {
get: function(target, id) {
return document.getElementById(id); } });
IDS.camelCaseId.style.color = 'red';
IDS['dash-id'].style.color = 'blue';
<div id="camelCaseId">div 1</div>
<div id="dash-id">div 2</div>
This, in case you don't want to use the unthinkable, see above.
You can use a wrapper function like :
const byId = (id) => document.getElementById(id);
Or
Assign document.getElementById to a variable by binding it with document object.
const byId = document.getElementById.bind(document);
Note: In second approach, If you don't bind document.getElementById with document you'll get error :
Uncaught TypeError: Illegal invocation
What Function.bind does is it creates a new function with its this keyword set to value that you provide as argument to Function.bind.
Read docs for Function.bind
const $id = id => document.getElementById(id);
...
$id('header')
I just use: function id(id) {return document.getElementById(id);}", called by id(target id).action;
It works for me in Chrome, Edge & Firefox, though not in Safari or Opera.
I wrote this yesterday and found it quite useful.
function gid(id, attribute) {
var x = 'document.getElementById("'+id+'")';
if(attribute) x += '.'+attribute;
eval('x =' + x);
return x;
}
This is how you use it.
// Get element by ID
var node = gid('someID'); //returns <p id='someID' class='style'>Hello World</p>
// returns 'Hello World'
// var getText = document.GetElementById('someID').innerText;
var getText = gid('someID', 'innerText');
// Get parent node
var parentNode = gid('someID', 'parentNode');

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.

Is it possible to get element's numerical index in its parent node without looping?

Normally I'm doing it this way:
for(i=0;i<elem.parentNode.length;i++) {
if (elem.parentNode[i] == elem) //.... etc.. etc...
}
function getChildIndex(node) {
return Array.prototype.indexOf.call(node.parentNode.childNodes, node);
}
This seems to work in Opera 11, Firefox 4, Chromium 10. Other browsers untested. It will throw TypeError if node has no parent (add a check for node.parentNode !== undefined if you care about that case).
Of course, Array.prototype.indexOf does still loop, just within the function call. It's impossible to do this without looping.
Note: If you want to obtain the index of a child Element, you can modify the function above by changing childNodes to children.
function getChildElementIndex(node) {
return Array.prototype.indexOf.call(node.parentNode.children, node);
}
Option #1
You can use the Array.from() method to convert an HTMLCollection of elements to an array. From there, you can use the native .indexOf() method in order to get the index:
function getElementIndex (element) {
return Array.from(element.parentNode.children).indexOf(element);
}
If you want the node index (as oppose to the element's index), then replace the children property with the childNodes property:
function getNodeIndex (element) {
return Array.from(element.parentNode.childNodes).indexOf(element);
}
Option #2
You can use the .call() method to invoke the array type's native .indexOf() method. This is how the .index() method is implemented in jQuery if you look at the source code.
function getElementIndex(element) {
return [].indexOf.call(element.parentNode.children, element);
}
Likewise, using the childNodes property in place of the children property:
function getNodeIndex (element) {
return [].indexOf.call(element.parentNode.childNodes, element);
}
Option #3
You can also use the spread operator:
function getElementIndex (element) {
return [...element.parentNode.children].indexOf(element);
}
function getNodeIndex (element) {
return [...element.parentNode.childNodes].indexOf(element);
}
You could count siblings...
The childNodes list includes text and element nodes-
function whichChild(elem){
var i= 0;
while((elem=elem.previousSibling)!=null) ++i;
return i;
}
There is no way to get the index of a node within its parent without looping in some manner, be that a for-loop, an Array method like indexOf or forEach, or something else. An index-of operation in the DOM is linear-time, not constant-time.
More generally, if list mutations are possible (and the DOM certainly supports mutation), it's generally impossible to provide an index-of operation that runs in constant time. There are two common implementation tactics: linked lists (usually doubly) and arrays. Finding an index using a linked list requires a walk. Finding an index using an array requires a scan. Some engines will cache indexes to reduce time needed to compute node.childNodes[i], but this won't help you if you're searching for a node. Not asking the question is the best policy.
I think you've got it, but:
make sure that variable "i" is declared with var
use === instead of == in the comparison
If you have a collection input elements with the same name (like <textarea name="text_field[]"…) in your form and you want to get the exact numeric index of the field that triggered an event:
function getElementIdxFromName(elem, parent) {
var elms = parent[elem.name];
var i = 0;
if (elms.length === undefined) // there is only one element with this name in the document
return 0;
while((elem!=elms[i])) i++;
return i;
}
Getting numeric id of an element from a collection of elements with the same class name:
function getElementIdxFromClass(elem, cl) {
var elems = document.getElementsByClassName(cl);
var i = 0;
if (elems.length > 0) {
while((elem!=elems[i])) i++;
return i;
}
return 0;
}
Try this:
let element = document.getElementById("your-element-id");
let indexInParent = Array.prototype.slice.call(element.parentNode.parentNode.children).indexOf(element.parentNode));

Categories