Checking if an element is present in the dom at the click of one button, if element is not present add it, else remove it [duplicate] - javascript

How do you test an element for existence without the use of the getElementById method?
I have set up a live demo for reference. I will also print the code on here as well:
<!DOCTYPE html>
<html>
<head>
<script>
var getRandomID = function (size) {
var str = "",
i = 0,
chars = "0123456789abcdefghijklmnopqurstuvwxyzABCDEFGHIJKLMNOPQURSTUVWXYZ";
while (i < size) {
str += chars.substr(Math.floor(Math.random() * 62), 1);
i++;
}
return str;
},
isNull = function (element) {
var randomID = getRandomID(12),
savedID = (element.id)? element.id : null;
element.id = randomID;
var foundElm = document.getElementById(randomID);
element.removeAttribute('id');
if (savedID !== null) {
element.id = savedID;
}
return (foundElm) ? false : true;
};
window.onload = function () {
var image = document.getElementById("demo");
console.log('undefined', (typeof image === 'undefined') ? true : false); // false
console.log('null', (image === null) ? true : false); // false
console.log('find-by-id', isNull(image)); // false
image.parentNode.removeChild(image);
console.log('undefined', (typeof image === 'undefined') ? true : false); // false ~ should be true?
console.log('null', (image === null) ? true : false); // false ~ should be true?
console.log('find-by-id', isNull(image)); // true ~ correct but there must be a better way than this?
};
</script>
</head>
<body>
<div id="demo"></div>
</body>
</html>
Basically the above code demonstrates an element being stored into a variable and then removed from the DOM. Even though the element has been removed from the DOM, the variable retains the element as it was when first declared. In other words, it is not a live reference to the element itself, but rather a replica. As a result, checking the variable's value (the element) for existence will provide an unexpected result.
The isNull function is my attempt to check for an elements existence from a variable, and it works, but I would like to know if there is an easier way to accomplish the same result.
PS: I'm also interested in why JavaScript variables behave like this if anyone knows of some good articles related to the subject.

It seems some people are landing here, and simply want to know if an element exists (a little bit different to the original question).
That's as simple as using any of the browser's selecting method, and checking it for a truthy value (generally).
For example, if my element had an id of "find-me", I could simply use...
var elementExists = document.getElementById("find-me");
This is specified to either return a reference to the element or null. If you must have a Boolean value, simply toss a !! before the method call.
In addition, you can use some of the many other methods that exist for finding elements, such as (all living off document):
querySelector()/querySelectorAll()
getElementsByClassName()
getElementsByName()
Some of these methods return a NodeList, so be sure to check its length property, because a NodeList is an object, and therefore truthy.
For actually determining if an element exists as part of the visible DOM (like the question originally asked), Csuwldcat provides a better solution than rolling your own (as this answer used to contain). That is, to use the contains() method on DOM elements.
You could use it like so...
document.body.contains(someReferenceToADomElement);

Use getElementById() if it's available.
Also, here's an easy way to do it with jQuery:
if ($('#elementId').length > 0) {
// Exists.
}
And if you can't use third-party libraries, just stick to base JavaScript:
var element = document.getElementById('elementId');
if (typeof(element) != 'undefined' && element != null)
{
// Exists.
}

Using the Node.contains DOM API, you can check for the presence of any element in the page (currently in the DOM) quite easily:
document.body.contains(YOUR_ELEMENT_HERE);
CROSS-BROWSER NOTE: the document object in Internet Explorer does not have a contains() method - to ensure cross-browser compatibility, use document.body.contains() instead.

I simply do:
if(document.getElementById("myElementId")){
alert("Element exists");
} else {
alert("Element does not exist");
}
It works for me and had no issues with it yet...

I prefer to use the node.isConnected property (Visit MDN).
Note: This will return true if the element is appended to a ShadowRoot as well, which might not be everyone's desired behaviour.
Example:
const element = document.createElement('div');
console.log(element.isConnected); // Returns false
document.body.append(element);
console.log(element.isConnected); // Returns true

Easiest way:
const cond = document.getElementById('elem') || false
if (cond) {
//does
} else {
//does not
}
If needed in strictly visible DOM, meaning not on entire page, use something like view-js (my lib so beat it up as much as you want)
<script src='https://view-js.glitch.me/view-main.js'></script>
<script>
elem = $sel('#myelem');
if (isVis(elem)) { //yes } else { //no }
</script>
function test() {
pt = document.querySelector('#result')
iv = document.querySelector('#f')
cond = document.querySelector('#'+iv.value) || false
if (cond) {
pt.innerText = 'Found!'
} else {
pt.innerText = 'Not found!'
}
}
Enter an id to see if it exists: <input id='f'></input>
<button onclick='test()'>Test!</button>
<br />
<p id='result'>I am a p tag. I will change depending on the result.</p>
<br />
<div id='demo'>I am a div. My id is demo.</div>

You could just check to see if the parentNode property is null.
That is,
if(!myElement.parentNode)
{
// The node is NOT in the DOM
}
else
{
// The element is in the DOM
}

From Mozilla Developer Network:
This function checks to see if an element is in the page's body. As contains() is inclusive and determining if the body contains itself isn't the intention of isInPage, this case explicitly returns false.
function isInPage(node) {
return (node === document.body) ? false : document.body.contains(node);
}
node is the node we want to check for in the <body>.

The easiest solution is to check the baseURI property, which is set only when the element is inserted in the DOM, and it reverts to an empty string when it is removed.
var div = document.querySelector('div');
// "div" is in the DOM, so should print a string
console.log(div.baseURI);
// Remove "div" from the DOM
document.body.removeChild(div);
// Should print an empty string
console.log(div.baseURI);
<div></div>

A simple way to check if an element exist can be done through one-line code of jQuery.
Here is the code below:
if ($('#elementId').length > 0) {
// Do stuff here if the element exists
} else {
// Do stuff here if the element does not exist
}

jQuery solution:
if ($('#elementId').length) {
// element exists, do something...
}
This worked for me using jQuery and did not require $('#elementId')[0] to be used.

csuwldcat's solution seems to be the best of the bunch, but a slight modification is needed to make it work correctly with an element that's in a different document than the JavaScript code is running in, such as an iframe:
YOUR_ELEMENT.ownerDocument.body.contains(YOUR_ELEMENT);
Note the use of the element's ownerDocument property, as opposed to just plain old document (which may or may not refer to the element's owner document).
torazaburo posted an even simpler method that also works with non-local elements, but unfortunately, it uses the baseURI property, which is not uniformly implemented across browsers at this time (I could only get it to work in the WebKit-based ones). I couldn't find any other element or node properties that could be used in a similar fashion, so I think for the time being the above solution is as good as it gets.

This code works for me, and I didn't have any issues with it.
if(document.getElementById("mySPAN")) {
// If the element exists, execute this code
alert("Element exists");
}
else {
// If the element does not exist execute this code
alert("Element does not exists");
}

Instead of iterating parents, you can just get the bounding rectangle which is all zeros when the element is detached from the DOM:
function isInDOM(element) {
if (!element)
return false;
var rect = element.getBoundingClientRect();
return (rect.top || rect.left || rect.height || rect.width)?true:false;
}
If you want to handle the edge case of a zero width and height element at zero top and zero left, you can double check by iterating parents till the document.body:
function isInDOM(element) {
if (!element)
return false;
var rect = element.getBoundingClientRect();
if (element.top || element.left || element.height || element.width)
return true;
while(element) {
if (element == document.body)
return true;
element = element.parentNode;
}
return false;
}

Another option is element.closest:
element.closest('body') === null

Use this command below to return whether or not the element exists in the DOM:
return !!document.getElementById('myElement');

Check element exist or not
const elementExists = document.getElementById("find-me");
if(elementExists){
console.log("have this element");
}else{
console.log("this element doesn't exist");
}

Check if the element is a child of <html> via Node::contains():
const div = document.createElement('div');
console.log(
document.documentElement.contains(div)
);//-> false
document.body.appendChild(div);
console.log(
document.documentElement.contains(div)
); //-> true
I've covered this and more in is-dom-detached.

You can also use jQuery.contains, which checks if an element is a descendant of another element. I passed in document as the parent element to search because any elements that exist on the page DOM are a descendant of document.
jQuery.contains( document, YOUR_ELEMENT)

A simple solution with jQuery:
$('body').find(yourElement)[0] != null

// This will work prefectly in all :D
function basedInDocument(el) {
// This function is used for checking if this element in the real DOM
while (el.parentElement != null) {
if (el.parentElement == document.body) {
return true;
}
el = el.parentElement; // For checking the parent of.
} // If the loop breaks, it will return false, meaning
// the element is not in the real DOM.
return false;
}

All existing elements have parentElement set, except the HTML element!
function elExists (e) {
return (e.nodeName === 'HTML' || e.parentElement !== null);
};

If an element is in the DOM, its parents should also be in
And the last grandparent should be the document
So to check that we just loop unto the element's parentNode tree until we reach the last grandparent
Use this:
/**
* #param {HTMLElement} element - The element to check
* #param {boolean} inBody - Checks if the element is in the body
* #return {boolean}
*/
var isInDOM = function(element, inBody) {
var _ = element, last;
while (_) {
last = _;
if (inBody && last === document.body) { break;}
_ = _.parentNode;
}
return inBody ? last === document.body : last === document;
};

this condition chick all cases.
function del() {
//chick if dom has this element
//if not true condition means null or undifind or false .
if (!document.querySelector("#ul_list ")===true){
// msg to user
alert("click btn load ");
// if console chick for you and show null clear console.
console.clear();
// the function will stop.
return false;
}
// if its true function will log delet .
console.log("delet");
}

As I landed up here due to the question. Few of the solutions from above don't solve the problem. After a few lookups, I found a solution on the internet that provided if a node is present in the current viewport where the answers I tried solves of it's present in the body or not.
function isInViewport(element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
console.log(
isInViewport(document.querySelector('.selector-i-am-looking-for'))
);
<div class="selector-i-am-looking-for"></div>
The snippet is taken from HERE to keep as a backup as the links may be unavailable after some time. Check the link for an explanation.
And, didn't intend to post in the comment, as in most cases, they are ignored.

Use querySelectorAll with forEach,
document.querySelectorAll('.my-element').forEach((element) => {
element.classList.add('new-class');
});
as the opposite of:
const myElement = document.querySelector('.my-element');
if (myElement) {
element.classList.add('new-class');
}

I liked this approach:
var elem = document.getElementById('elementID');
if (elem)
do this
else
do that
Also
var elem = ((document.getElementById('elemID')) ? true:false);
if (elem)
do this
else
do that

Related

Is there a way to test a css-selector query to an unappended element?

I have this code:
Element.prototype.queryTest = function(strQuery) {
var _r;
if (this.parentElement == null) {
_r = Array.prototype.slice.call(document.querySelectorAll(strQuery)).indexOf(this);
} else {
_r = Array.prototype.slice.call(this.parentElement.querySelectorAll(strQuery)).indexOf(this);
}
return !!(_r+1);
}
I am searching for some way to test a query to an unappended element.
I want to change the first code to make this work:
var t = document.createElement("span");
t.classList.add("asdfg");
console.log(t.queryTest("span.adsfg"));
If there is a way to detect if the element isn't appended I could create a new temporary unappended one and append the target one to the temporary one to test the css-selector query.
Is there a way to detect if the element hasn't been appended jet? Could the target element be accessible even after freeing the temporary parent one? I have tested it on Chrome and it is accessible but I don't know if that is the case for firefox.
I know I can use document.querySelectorAll("*") to get a list of nodes but... isn't too CPU-demmanding the process to turn this NodeList to an Array? This is why I prefer not to use that way.
Thanks in advance.
There is already a native Element.prototype.matches method which does that:
const el = document.createElement('span');
el.classList.add('test');
console.log(el.matches('span.test'));
Note that to check if a node is connected or not, there is the Node.prototype.isConnected getter.
I did it.
Element.prototype.querySelectorTest = function(strQuery) {
var _r;
if (this.parentElement != null) {
_r = Array.prototype.indexOf.call(this.parentElement.querySelectorAll(strQuery),this);
} else if (this == document.documentElement) {
_r = ((document.querySelector(strQuery) == this)-1);
} else {
_r = ((this == document.createElement("i").appendChild(this).parentElement.querySelector(strQuery))-1);
}
return !!(_r+1);
}
I changed the way it check the nodeList.
I renamed the function to a more proper name.
If the target element is the root one there's no need to make a querySelectorAll.
If you append the unappended element to a temporary one to test the child you don't loose the reference (variable value in case there is one).
This is not my native language so please consider that.

Elegant way of checking if one of the parentNodes has a certain class

I have a menu that expands and retracts on hover. The problem is the menu has many elements and to trigger my expand function I need to write something like below. My actual code includes more code and I was wondering if there would be a better way to do this.
var e = event.target
if(
e.parentNode.className.split(" ")[0] === "main-section" ||
e.parentNode.parentNode.className.split(" ")[0] === "main-section" ||
e.parentNode.parentNode.parentNode.className.split(" ")[0] === "main-section"){
//do somehtings}
In modern environments you can use the DOM's closest method:
if (e.closest(".main-section")) {
// One was found...
}
It looks at the current element to see if it matches the selector, then its parent element, then its parent, etc. to the root of the tree. It returns the element it finds, or null if it doesn't find one.
For slightly older environments, Element#closest can be polyfilled. Or if you don't like polyfilling, you can give yourself a utility function instead that uses closest if it exists, or uses matches if not:
function closest(el, selector) {
if (el.closest) {
return el.closest(selector);
}
var matches = el.matches || el.matchesSelector;
while (el) {
if (matches.call(el, selector)) {
return el;
}
el = el.parentNode;
}
return null;
}
...which you'd use like this:
if (closest(e, ".main-section")) {
// One was found...
}
Method closest() is not supported in some browsers, so I took this function for you from this answer
function findAncestor (el, sel) {
while ((el = el.parentElement) && !((el.matches || el.matchesSelector).call(el,sel)));
return el;
}
Use classList with a recursive function like so.
const start = document.getElementById("start");
function recursiveCheck(ele, className, limit = 3, current = 0){
return ele.classList.contains(className) ? true : current >= limit ? false : recursiveCheck(ele.parentNode, className, limit, current + 1);
}
console.log(
recursiveCheck(start, "test")
);
<div class="test">
<div>
<div id="start"><div>
</div>
</div>

Check if jQuery object is a variable or Dom element [duplicate]

Let's say that I define an element
$foo = $('#foo');
and then I call
$foo.remove()
from some event. My question is, how do I check whether $foo has been removed from the DOM or not? I've found that $foo.is(':hidden') works, but that would of course also return true if I merely called $foo.hide().
Like this:
if (!jQuery.contains(document, $foo[0])) {
//Element is detached
}
This will still work if one of the element's parents was removed (in which case the element itself will still have a parent).
How about doing this:
$element.parents('html').length > 0
I just realized an answer as I was typing my question: Call
$foo.parent()
If $f00 has been removed from the DOM, then $foo.parent().length === 0. Otherwise, its length will be at least 1.
[Edit: This is not entirely correct, because a removed element can still have a parent; for instance, if you remove a <ul>, each of its child <li>s will still have a parent. Use SLaks' answer instead.
Probably the most performative way is:
document.contains(node); // boolean
This also works with jQuery:
document.contains($element[0]); // var $element = $("#some-element")
document.contains(this[0]); // in contexts like $.each(), `this` is the jQ object
Source from MDN
Note:
Internet Explorer only supports contains() for elements.
Since I'm unable to respond as a comment (too low karma I guess), here's a full reply. The fastest way is easily to unroll the jQuery check for browser support and to shave the constant factors to minimum.
As seen also here - http://jsperf.com/jquery-element-in-dom/28 - the code would look like this:
var isElementInDOM = (function($) {
var docElt = document.documentElement, find,
contains = docElt.contains ?
function(elt) { return docElt.contains(elt); } :
docElt.compareDocumentPosition ?
function(elt) {
return docElt.compareDocumentPosition(elt) & 16;
} :
((find = function(elt) {
return elt && (elt == docElt || find(elt.parentNode));
}), function(elt) { return find(elt); });
return function(elt) {
return !!(elt && ((elt = elt.parent) == docElt || contains(elt)));
};
})(jQuery);
This is semantically equivalent to jQuery.contains(document.documentElement, elt[0]).
instead of iterating parents you can just get the bounding rect which is all zeros when the element is detached from dom
function isInDOM(element) {
var rect=element.getBoundingClientRect();
return (rect.top || rect.bottom || rect.height || rect.width)?true:false;
}
if you want to handle the edge case of a zero width and height element at zero top and zero left you can double check by iterating parents till the document.body
I liked this approach. No jQuery and no DOM search. First find the top parent (ancestor). Then see if that is the documentElement.
function ancestor(HTMLobj){
while(HTMLobj.parentElement){HTMLobj=HTMLobj.parentElement}
return HTMLobj;
}
function inTheDOM(obj){
return ancestor(obj)===document.documentElement;
}
Agree with Perro's comment. It can also be done like this:
$foo.parents().last().is(document.documentElement);
jQuery.fn.isInDOM = function () {
if (this.length == 1) {
var element = this.get(0);
var rect = element.getBoundingClientRect();
if (rect.top + rect.bottom + rect.width + rect.height + rect.left + rect.right == 0)
return false;
return true;
}
return false;
};
Why not just: if( $('#foo').length === 0)... ?
if($foo.nodeType ){ element is node type}

JavaScript: querySelector Null vs querySelector

What is the main difference between these two methods of referencing?
What are the benefits of using one or the other? Also what kind of usage-case would they each be best suited to?
var selection = document.querySelector('.selector') !== null;
var selection = document.querySelector('.selector');
Is the former solely for browser legacy support?
The first one gets the reference and checks if the element exists, and saves this status as a boolean value in the variable. If the element exists, the variable contains true otherwise false.
You would use the first one if you only want to know if the element exists, but don't need the reference to it.
Example:
var selection = document.querySelector('.selector') !== null;
if (selection) {
alert('The element exists in the page.');
} else {
alert('The element does not exists in the page.');
}
The second one gets the reference and stores in the variable, but doesn't check if the element exists. If the element exists, the variable contains the reference to the element, otherwise the variable contains null.
You would use the second one if you need the reference to the element. If it's possible that the element doesn't exist in the page, you should check if the variable contains null before you try to do something with the reference.
Example:
var selection = document.querySelector('.selector');
if (selection !== null) {
alert('I have a reference to a ' + selection.tagName + ' element.');
} else {
alert('The element does not exists in the page.');
}
you could also do:
[].filter.call([document.querySelector('.single-selected-class')], item => item)
.forEach(item => item.blur());
The first statement contains a bool value depends on document.querySelector('.selector') is null or not
var selection = document.querySelector('.selector') !== null;
the second statement contains the actual value of document.querySelector('.selector');
var selection = document.querySelector('.selector');
You can try to avoid the conditional statement with:
var selection = document.querySelectorAll('.selector');
selection.forEach(function(item) {
alert(item);
});
Caution! querySelectorAll() behaves differently than most common JavaScript DOM libraries, which might lead to unexpected results
Source: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
I was developing a similar solution for CMS EFFCORE and came up with the following:
if (!Node.prototype.hasOwnProperty('querySelector__withHandler')) {
Object.defineProperty(Node.prototype, 'querySelector__withHandler', {
configurable: true,
enumerable : true,
writable : true,
value: function (query, handler) {
var result = this.querySelector(query);
if (result instanceof Node) {
handler(result);
}
}
});
}
document.querySelector__withHandler('a', function(link){
alert(link)
})

removing all the DOM Elements with a specific className

How I can remove all DOM Elements with specific classname or element width ID's that start with a specific pattern. like (without any framework!)
id="selectbox1"
id="selectbox2"
id="selectbox3"
id="selectbox4"
Thanks
You'd have to use getElementsByTagName(*) iterate over the entire collection, check the .className property with a regex /\bYourClasName\b/ (className can have more than one class, seperated by a space) and then also check the element's .id property with another regex: /^IDStartsWithThis/ finally on any matches you would have to call element.parentNode.removeChild(element);
(On my way to work and in a rush, if you need more code I can supply it once I get there around 630 est)
Edit: here's the code:
usage: removeElemIf(idStartsWith,containsClass). you can pass null, only the id (second param is undefined), blanks (blanks are ignored, both parameters are trimmed first). Case is insensitive for both parameters.
function removeElemIf(theID, theClass) { /* class => full match, id => startswith */
checkID = !(theID === undefined || theID === null || (theID = theID.replace(/^\s*|\s*$/g, '')).length == 0);
checkClass = !(theClass === undefined || theClass === null || (theClass = theClass.replace(/^\s*|\s*$/g, '')).length == 0);
if (!(checkID || checkClass)) return;
var oBody = document.getElementsByTagName('body')[0]; // only search the body
var oElems = oBody.getElementsByTagName('*'); // get all the elements within body
for (i = oElems.length - 1; i >= 0; i--) { // loop through backwards in case of delete
el = oElems[i]; // set current element
found = false; // reset flag
if (checkID) { /* check the ID for starting with "theID", originally used indexOf but its case sensitive*/
re = new RegExp('^'+theID,'i');
if (el.id.match(re)) found = true;
}
if (!found && checkClass) { /* only test class if the id doesn't match,
save the regex in instances where the
class names are long or many*/
re = new RegExp('\\b' + theClass + '\\b', 'i');
if (el.className.match(re)) found = true;
}
if (found) el.parentNode.removeChild(el); /* if found, remove from parent */
}
}
Traverse through the dom tree and compare against the className property of each element found. Yes it's tedious, but that's how it's done. You can either traverse in a recursive fashion or an iterative one. The first is the easiest to write, but the second has much better performance.
see this SO thread:
jQuery matching pattern
and check out getElementsByTagName() function

Categories