Reputation: 5145
I'm trying to implement native document.getElementById
in javascript. I've implemented document.getElementsByClassName
in javascript.
function getElementsByClassName (className) {
var nodeList = [];
function test(node) {
if (node.classList && node.classList.contains(className)) {
nodeList.push(node);
}
for (var index = 0; index < node.childNodes.length; index++) {
test(node.childNodes[index]);
}
return nodeList;
}
test(document.body);
return nodeList;
};
// Fails here.
function getElementById(className) {
const result = [];
function getEachIDNode(node) {
if(node.contains(className)) {
return node;
}
for(let i=0; i<node.childNodes.length; i++) {
getEachIDNode(node.childNodes[i]);
}
}
getEachIDNode(document.body);
}
console.log(getElementsByClassName('winner'));
console.log(getElementById('test'));
<table>
<tr id="test">
<td>#</td>
<td class="winner">aa</td>
<td>bb</td>
<td>cc</td>
<td>dd</td>
</tr>
</table>
<table>
<tr>
<td>#</td>
<td class="winner">aa</td>
<td>bb</td>
<td>cc</td>
<td>dd</td>
</tr>
</table>
<table>
<tr>
<td>#</td>
<td class="winner">dd</td>
<td>cc</td>
<td>bb</td>
<td>aa</td>
</tr>
</table>
I'm trying to understand how I can check if a node has an attribute ID.
Can someone enlighten me?
Upvotes: 3
Views: 2395
Reputation: 136698
The native document.getElementById
does not walk through the DOM tree searching for your Element, and that's why it is faster than other DOM selection methods.
Indeed, browsers have to keep a kind of a hash-map of all the Elements with an id in the active Document. So they just perform a look-up over this hash-map (which is not one) and return the element if they found it.
Thanks to IE </irony>, they do expose some of the entries of this hash-map as properties of the global window
object.
So if you are going to make your own implementation, you can first check if this property returns your Element.
Unfortunately, it may happen that an Element's id do concur with an other property of the window
object. So it may happen that we still need to walk the DOM.
In this case, use a TreeWalker, which is about the fastest API we have to walk through a DOM tree, moreover when we are only interested in some type of nodes (here Elements).
So all in all, a better implementation could look like this:
function getElementById(id) {
if (!(id in window)) {
console.log(id, 'not found');
return null; // we are sure it's not set
}
// id maps are not marked as 'own property'
if (!window.hasOwnProperty(id)) {
if (window[id] instanceof Element &&
window[id].id === id) { // it's our Element
console.log(id, 'found in window');
return window[id];
}
// in case of duplicate window[id] should return an HTMLCollection
// (IIRC only Chrome does it correctly though)
if (window[id] instanceof HTMLCollection &&
window[id][0].id === id) {
console.log(id, 'duplicate id is bad');
return window[id][0];
}
}
console.log(id, 'walking...');
var walker = document.createTreeWalker(
document.documentElement,
NodeFilter.SHOW_ELEMENT,
null,
false
);
while (walker.nextNode()) {
if (walker.currentNode.id === id) {
return walker.currentNode;
}
}
return null;
}
console.log(getElementById('foo'));
console.log(getElementById('unique'));
console.log(getElementById('duplicate'));
window.overwritten = 'oups';
console.log(getElementById('overwritten'));
<div id="unique">
<div id="duplicate"></div>
<div id="duplicate"></div>
<div id="overwritten"></div>
</div>
As you can see, in this implementation we walk the DOM only if the window's property has been set to an other value, greatly improving the performances.
Upvotes: 1
Reputation: 348
To check if a node has an attribute ID.You have to write like this:
var attr_check = $(".selector").attr('id')
if(attr_check != undefined || attr_check != false)
{
console.log("this element has attribute id")
}
You also write this code:
var attr_check = document.getElementById('div-id').attr('id')
instead of this:
var attr_check = $(".selector").attr('id')
Upvotes: 0
Reputation: 19
Check attribute property of DOM element.
function getElementById(id) {
const result = [];
function getEachIDNode(node) {
if(!(node instanceof HTMLElement))
return;
if(node.hasAttribute('id') && node.getAttribute('id') === id) {
result.push(node);
}
for(let i=0; i<node.childNodes.length; i++) {
if(result.length > 0)
return;
getEachIDNode(node.childNodes[i]);
}
}
getEachIDNode(document.body);
return result[0];
}
Upvotes: 1
Reputation: 370729
Check the id
property of the node against the passed argument (probably better to use id
as an argument rather than className
):
function getElementById(id) {
const result = [];
function getEachIDNode(node) {
if(node.id === id) {
result.push(node);
}
for(let i=0; i<node.childNodes.length; i++) {
getEachIDNode(node.childNodes[i]);
}
}
getEachIDNode(document.body);
return result;
}
console.log(getElementById('subchild')[0].innerHTML);
<div id="parent">
<div id="child1">
</div>
<div id="child2">
<div id="subchild">
subchild!
</div>
</div>
</div>
But if you actually want to replicate getElementById
, don't try to return an array, return a single element
:
function getElementById(id) {
let match = null;
const doFind = node => {
if (!match && node.id === id) match = node;
if (!match) return [...node.childNodes].find(doFind);
}
doFind(document.body);
return match;
}
console.log(getElementById('subchild').innerHTML);
<div id="parent">
<div id="child1">
</div>
<div id="child2">
<div id="subchild">
subchild!
</div>
</div>
</div>
Upvotes: 3