Reputation: 123563
I'm trying to get:
document.createElement('div') //=> true
{tagName: 'foobar something'} //=> false
In my own scripts, I used to just use this since I never needed tagName
as a property:
if (!object.tagName) throw ...;
So for the second object, I came up with the following as a quick solution -- which mostly works. ;)
The problem is, it depends on browsers enforcing read-only properties, which not all do.
function isDOM(obj) {
var tag = obj.tagName;
try {
obj.tagName = ''; // Read-only for DOM, should throw exception
obj.tagName = tag; // Restore for normal objects
return false;
} catch (e) {
return true;
}
}
Is there a good substitute?
Upvotes: 333
Views: 286750
Reputation: 1564
You can test for a DOM node with document.cloneNode.call(obj)
which throws only when passed a value that isn't a DOM node. So it's just a matter of using try/catch. It even works with nodes from a different frame or window.
In Internet Explorer 8 and below one must use a different approach. Thankfully it is just a matter of trying to write to obj.nodeType
as that throws only if it's a DOM node. So again it's just a matter of using try/catch.
So here is the complete function:
// Cross browser solution that works with high accuracy
function isDOMNode(obj) {
if (obj!=null && typeof obj.nodeType=="number") {//nodeType is always a number
var testNodeObj = document.cloneNode
, success = false;
if (typeof testNodeObj=="function") {// Test for non-IE8- browsers
try {
testNodeObj.call(obj);// Throws if obj is not a DOM node
success = true;
}
catch(e) {
}
}
else if ({}.hasOwnProperty.call(obj, 'nodeType')) {//Possible IE8- node
try {
obj.nodeType = obj.nodeType// throws in IE8- on DOM nodes
}
catch(e) {
success = true;
}
}
}
return !!success
}
Upvotes: 0
Reputation: 941
for specific element type like my case i think this solution enough to detect if it valid audio element.
const elm = document.querySelector("#demo");
if (elm.nodeName && elm.nodeName.toLowerCase() === 'audio'){
alert(elm.nodeName);
}
Said By google element.nodeName is a DOM Level 1 (1998) feature. It is fully supported in all browsers: Chrome, Edge, Firefox, Safari, Opera, IE. Yes, Yes ... so by logic if it has
nodeName
and it equal to audio it sure element and should work on all browser, if you need div or other element change the string note toLowerCase becauseelm.nodeName
returns 'AUDIO'
Upvotes: 0
Reputation: 534
Here's a simple solution to this task that checks the most basic important criterias of a DOM HTML element:
const isHTMLEl = o => typeof o === 'object' && !!o.tagName && o instanceof HTMLElement && !!o.nodeType;
const obj = document.createElement('iframe');
console.log( isHTMLEl(obj) ); // returns true
console.log( isHTMLEl([]) ); // return false
console.log( isHTMLEl('<div />') ); // returns false
Upvotes: 1
Reputation: 4996
The accepted answer is a bit complicated, and does not detect all types of HTML elements. For example, SVG elements are not supported. In contrast, this answer works for HTML as well as SVG, etc.
See it in action here: https://jsfiddle.net/eLuhbu6r/
function isElement(element) {
return element instanceof Element || element instanceof HTMLDocument;
}
Cherry on top: the above code is IE8 compatible.
Upvotes: 125
Reputation: 21873
A simple way to test if a variable is a DOM element (verbose, but more traditional syntax :-)
function isDomEntity(entity) {
if(typeof entity === 'object' && entity.nodeType !== undefined){
return true;
}
else{
return false;
}
}
Or as HTMLGuy suggested (short and clean syntax):
const isDomEntity = entity =>
typeof entity === 'object' && entity.nodeType !== undefined
Upvotes: 10
Reputation: 1752
Here's my version. It has support for elements from iframe
/**
* @param {any} value
* @param {any} view Optional. If the value is from an iframe, provide the iframe content window here.
* @returns {boolean}
*/
function isHtmlElement(value, view) {
if (value instanceof HTMLElement) return true
if (view && value instanceof view.HTMLElement) return true
return !!(
value &&
typeof value === 'object' &&
value !== null &&
value.nodeType === 1 &&
typeof value.nodeName === 'string'
)
}
Upvotes: 0
Reputation: 1
I use this function:
function isHTMLDOMElement(obj) {
if (Object.prototype.toString.call(obj).slice(-8) === 'Element]') {
if (Object.prototype.toString.call(obj).slice(0, 12) === '[object HTML') {
return true;
}
return false;
}
return false;
}
https://jsfiddle.net/1qazxsw2/wz7e0fvj/9/
Upvotes: -1
Reputation: 1653
if you are using jQuery, try this
$('<div>').is('*') // true
$({tagName: 'a'}).is('*') // false
$({}).is('*') // false
$([]).is('*') // false
$(0).is('*') // false
$(NaN).is('*') // false
Upvotes: -1
Reputation: 1
The only way to guarentee you're checking an actual HTMLEement, and not just an object with the same properties as an HTML Element, is to determine if it inherits from Node, since its impossible to make a new Node() in JavaScript. (unless the native Node function is overwritten, but then you're out of luck). So:
function isHTML(obj) {
return obj instanceof Node;
}
console.log(
isHTML(test),
isHTML(ok),
isHTML(p),
isHTML(o),
isHTML({
constructor: {
name: "HTML"
}
}),
isHTML({
__proto__: {
__proto__: {
__proto__: {
__proto__: {
constructor: {
constructor: {
name: "Function"
},
name: "Node"
}
}
}
}
}
}),
)
<div id=test></div>
<blockquote id="ok"></blockquote>
<p id=p></p>
<br id=o>
<!--think of anything else you want--!>
Upvotes: 0
Reputation: 34123
No need for hacks, you can just ask if an element is an instance of the DOM Element:
const isDOM = el => el instanceof Element
Upvotes: 53
Reputation: 5369
According to mdn
Element
is the most general base class from which all objects in aDocument
inherit. It only has methods and properties common to all kinds of elements.
We can implement isElement
by prototype. Here is my advice:
/**
* @description detect if obj is an element
* @param {*} obj
* @returns {Boolean}
* @example
* see below
*/
function isElement(obj) {
if (typeof obj !== 'object') {
return false
}
let prototypeStr, prototype
do {
prototype = Object.getPrototypeOf(obj)
// to work in iframe
prototypeStr = Object.prototype.toString.call(prototype)
// '[object Document]' is used to detect document
if (
prototypeStr === '[object Element]' ||
prototypeStr === '[object Document]'
) {
return true
}
obj = prototype
// null is the terminal of object
} while (prototype !== null)
return false
}
console.log(isElement(document)) // true
console.log(isElement(document.documentElement)) // true
console.log(isElement(document.body)) // true
console.log(isElement(document.getElementsByTagName('svg')[0])) // true or false, decided by whether there is svg element
console.log(isElement(document.getElementsByTagName('svg'))) // false
console.log(isElement(document.createDocumentFragment())) // false
Upvotes: 2
Reputation: 49632
This might be of interest:
function isElement(obj) {
try {
//Using W3 DOM2 (works for FF, Opera and Chrome)
return obj instanceof HTMLElement;
}
catch(e){
//Browsers not supporting W3 DOM2 don't have HTMLElement and
//an exception is thrown and we end up here. Testing some
//properties that all elements have (works on IE7)
return (typeof obj==="object") &&
(obj.nodeType===1) && (typeof obj.style === "object") &&
(typeof obj.ownerDocument ==="object");
}
}
It's part of the DOM, Level2.
Update 2: This is how I implemented it in my own library: (the previous code didn't work in Chrome, because Node and HTMLElement are functions instead of the expected object. This code is tested in FF3, IE7, Chrome 1 and Opera 9).
//Returns true if it is a DOM node
function isNode(o){
return (
typeof Node === "object" ? o instanceof Node :
o && typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName==="string"
);
}
//Returns true if it is a DOM element
function isElement(o){
return (
typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName==="string"
);
}
Upvotes: 360
Reputation: 1
(element instanceof $ && element.get(0) instanceof Element) || element instanceof Element
This will check for even if it is a jQuery or JavaScript DOM element
Upvotes: 0
Reputation: 692
This is from the lovely JavaScript library MooTools:
if (obj.nodeName){
switch (obj.nodeType){
case 1: return 'element';
case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
}
}
Upvotes: 6
Reputation: 41
old thread, but here's an updated possibility for ie8 and ff3.5 users:
function isHTMLElement(o) {
return (o.constructor.toString().search(/\object HTML.+Element/) > -1);
}
Upvotes: 4
Reputation: 3672
I have a special way to do this that has not yet been mentioned in the answers.
My solution is based on four tests. If the object passes all four, then it is an element:
The object is not null.
The object has a method called "appendChild".
The method "appendChild" was inherited from the Node class, and isn't just an imposter method (a user-created property with an identical name).
The object is of Node Type 1 (Element). Objects that inherit methods from the Node class are always Nodes, but not necessarily Elements.
Q: How do I check if a given property is inherited and isn't just an imposter?
A: A simple test to see if a method was truly inherited from Node is to first verify that the property has a type of "object" or "function". Next, convert the property to a string and check if the result contains the text "[Native Code]". If the result looks something like this:
function appendChild(){
[Native Code]
}
Then the method has been inherited from the Node object. See https://davidwalsh.name/detect-native-function
And finally, bringing all the tests together, the solution is:
function ObjectIsElement(obj) {
var IsElem = true;
if (obj == null) {
IsElem = false;
} else if (typeof(obj.appendChild) != "object" && typeof(obj.appendChild) != "function") {
//IE8 and below returns "object" when getting the type of a function, IE9+ returns "function"
IsElem = false;
} else if ((obj.appendChild + '').replace(/[\r\n\t\b\f\v\xC2\xA0\x00-\x1F\x7F-\x9F ]/ig, '').search(/\{\[NativeCode]}$/i) == -1) {
IsElem = false;
} else if (obj.nodeType != 1) {
IsElem = false;
}
return IsElem;
}
Upvotes: 0
Reputation: 4536
Each DOMElement.constructor returns function HTML...Element() or [Object HTML...Element] so...
function isDOM(getElem){
if(getElem===null||typeof getElem==="undefined") return false;
var c = getElem.constructor.toString();
var html = c.search("HTML")!==-1;
var element = c.search("Element")!==-1;
return html&&element;
}
Upvotes: 0
Reputation: 288660
Most answers use some kind of duck typing, checking for example that the object has a nodeType
property. But that's not enough, because non-nodes can also have node-like properties.
The other common approach is instanceof
, which can produce false positives e.g. with Object.create(Node)
, which is not a node despite inheriting node properties.
Moreover, both approaches above call internal essential methods, which can be problematic e.g. if the tested value is a proxy.
Instead, what I recommend is borrowing a node method and calling it on our object. The browser will check that the value is a node probably by looking at internal slots not customizable in proxies, so even they won't be able to interfere with our check.
function isNode(value) {
try {
Node.prototype.cloneNode.call(value, false);
return true;
} catch(err) {
return false;
}
}
You can also use property getters, if you prefer.
function isNode(value) {
try {
Object.getOwnPropertyDescriptor(Node.prototype,'nodeType').get.call(value);
return true;
} catch(err) {
return false;
}
}
Similarly, if you want to test if a value is an element, you can use
function isElement(value) {
try {
Element.prototype.getAttribute.call(value, '');
return true;
} catch(err) {
return false;
}
}
function isHTMLElement(value) {
try {
HTMLElement.prototype.click.call(value);
return true;
} catch(err) {
return false;
}
}
Upvotes: 0
Reputation: 1413
A absolute right method, check target is a real html element primary code:
(function (scope) {
if (!scope.window) {//May not run in window scope
return;
}
var HTMLElement = window.HTMLElement || window.Element|| function() {};
var tempDiv = document.createElement("div");
var isChildOf = function(target, parent) {
if (!target) {
return false;
}
if (parent == null) {
parent = document.body;
}
if (target === parent) {
return true;
}
var newParent = target.parentNode || target.parentElement;
if (!newParent) {
return false;
}
return isChildOf(newParent, parent);
}
/**
* The dom helper
*/
var Dom = {
/**
* Detect if target element is child element of parent
* @param {} target The target html node
* @param {} parent The the parent to check
* @returns {}
*/
IsChildOf: function (target, parent) {
return isChildOf(target, parent);
},
/**
* Detect target is html element
* @param {} target The target to check
* @returns {} True if target is html node
*/
IsHtmlElement: function (target) {
if (!X.Dom.IsHtmlNode(target)) {
return false;
}
return target.nodeType === 1;
},
/**
* Detect target is html node
* @param {} target The target to check
* @returns {} True if target is html node
*/
IsHtmlNode:function(target) {
if (target instanceof HTMLElement) {
return true;
}
if (target != null) {
if (isChildOf(target, document.documentElement)) {
return true;
}
try {
tempDiv.appendChild(target.cloneNode(false));
if (tempDiv.childNodes.length > 0) {
tempDiv.innerHTML = "";
return true;
}
} catch (e) {
}
}
return false;
}
};
X.Dom = Dom;
})(this);
Upvotes: 0
Reputation: 4828
differentiate a raw js object from a HTMLElement
function isDOM (x){
return /HTML/.test( {}.toString.call(x) );
}
use:
isDOM( {a:1} ) // false
isDOM( document.body ) // true
// OR
Object.defineProperty(Object.prototype, "is",
{
value: function (x) {
return {}.toString.call(this).indexOf(x) >= 0;
}
});
use:
o={}; o.is("HTML") // false
o=document.body; o.is("HTML") // true
Upvotes: 1
Reputation: 5267
This could be helpful: isDOM
//-----------------------------------
// Determines if the @obj parameter is a DOM element
function isDOM (obj) {
// DOM, Level2
if ("HTMLElement" in window) {
return (obj && obj instanceof HTMLElement);
}
// Older browsers
return !!(obj && typeof obj === "object" && obj.nodeType === 1 && obj.nodeName);
}
In the code above, we use the double negation operator to get the boolean value of the object passed as argument, this way we ensure that each expression evaluated in the conditional statement be boolean, taking advantage of the Short-Circuit Evaluation, thus the function returns true
or false
Upvotes: 3
Reputation: 41
I think prototyping is not a very good solution but maybe this is the fastest one: Define this code block;
Element.prototype.isDomElement = true;
HTMLElement.prototype.isDomElement = true;
than check your objects isDomElement property:
if(a.isDomElement){}
I hope this helps.
Upvotes: 3
Reputation: 1878
This will work for almost any browser. (No distinction between elements and nodes here)
function dom_element_check(element){
if (typeof element.nodeType !== 'undefined'){
return true;
}
return false;
}
Upvotes: 1
Reputation: 3773
For the ones using Angular:
angular.isElement
https://docs.angularjs.org/api/ng/function/angular.isElement
Upvotes: 1
Reputation: 2961
How about Lo-Dash's _.isElement
?
$ npm install lodash.iselement
And in the code:
var isElement = require("lodash.iselement");
isElement(document.body);
Upvotes: 8
Reputation: 2937
Not to hammer on this or anything but for ES5-compliant browsers why not just:
function isDOM(e) {
return (/HTML(?:.*)Element/).test(Object.prototype.toString.call(e).slice(8, -1));
}
Won't work on TextNodes and not sure about Shadow DOM or DocumentFragments etc. but will work on almost all HTML tag elements.
Upvotes: 0
Reputation: 78
Test if obj
inherits from Node.
if (obj instanceof Node){
// obj is a DOM Object
}
Node is a basic Interface from which HTMLElement and Text inherit.
Upvotes: 1
Reputation: 437
here's a trick using jQuery
var obj = {};
var element = document.getElementById('myId'); // or simply $("#myId")
$(obj).html() == undefined // true
$(element).html() == undefined // false
so putting it in a function:
function isElement(obj){
return (typeOf obj === 'object' && !($(obj).html() == undefined));
}
Upvotes: 0
Reputation: 81
var IsPlainObject = function ( obj ) { return obj instanceof Object && ! ( obj instanceof Function || obj.toString( ) !== '[object Object]' || obj.constructor.name !== 'Object' ); },
IsDOMObject = function ( obj ) { return obj instanceof EventTarget; },
IsDOMElement = function ( obj ) { return obj instanceof Node; },
IsListObject = function ( obj ) { return obj instanceof Array || obj instanceof NodeList; },
// In fact I am more likely t use these inline, but sometimes it is good to have these shortcuts for setup code
Upvotes: 3
Reputation: 171
The using the root detection found here, we can determine whether e.g. alert is a member of the object's root, which is then likely to be a window:
function isInAnyDOM(o) {
return (o !== null) && !!(o.ownerDocument && (o.ownerDocument.defaultView || o.ownerDocument.parentWindow).alert); // true|false
}
To determine whether the object is the current window is even simpler:
function isInCurrentDOM(o) {
return (o !== null) && !!o.ownerDocument && (window === (o.ownerDocument.defaultView || o.ownerDocument.parentWindow)); // true|false
}
This seems to be less expensive than the try/catch solution in the opening thread.
Don P
Upvotes: 4