x.contains(y)

Troy III 0 Tallied Votes 651 Views Share

Since the Firefox [Bug 633133] of the in operator on DOM Collections has ben finally fixed - We can now write a short fast and clean function of the method "Contains" for FirefoX to check if x.contains(y). And vice- versa.

What we will need is:
a prototype
and we'll chose to use the:

var pro = window.HTMLElement.prototype

that :') will overwrite the native method existing in other gen-V browsers also.

But first (as a bonus) we will write a descendants method so we can chain them and use les code for more productivity:

oElement.descendants( [filter] )

pro.descendants = function(x){
	x = this.getElementsByTagName(x?x:"*")
	return x.length?x:null;
	}

and now we will write the (dependent to descendants) contains method:

oElement.contains( targetElement,[optFilter] )

pro.contains=function(x,y){
	return this.descendants(y)[x.id]
	}

And this is it! Now you have both oElement.descendants([tagsFilter]) and the practical oElement.contains(targetElement, [tagsFilter]).

The [tagsFilter ] is completely optional but is available for further optimization of your code, even though this code is as fast as native - further optimization does no harm . On contrary using it in this manner:

oElement.contains(targetElement,  "SPAN")

makes it even faster .

--------------------------------------------------

PS.:
The only drawback of this short dimple and fast code method is that it can't be used against anonymous elements, or to be exact elements with no ID. Although 99.9% of all times - nobody uses it in blind tests ever (targeting anonymous elements under click or some other mouse event and extracting the argument through event.target/srcelement or similar). But we can afford to add few more letters of code and make it possible.

pro.
contains=function(x,y){
	x.id?'':x.id='_id'
	return this.descendants(y)[x.id]
	}

Attention: this method assigns an id: '_id' to the tested 'this' ( no-id element).

But if that poses a problem for us, we can remove it as soon as we are done with it.

pro.
contains=function(x,y){
	x.id?'':x.id='_id';
	x = this.descendants(y)[x.id];
	x.id=='_id'?x.id='':0;
	return x
	}

if(x.contains(y)) //evaluates true/false;
But also returns the element object, therefore you are able to write something like this: x.contains(y).style...some property

[...]

Dani AI

Generated

A short update and a safer, modern alternative to 's prototype-based approach.

Browsers now expose a standard, fast method: Node.prototype.contains (available on Elements). That does the job reliably and is much safer than overwriting native prototypes or temporarily assigning IDs. 's examples are clever for the era and show useful optimizations (tag filtering), but they rely on fragile behaviors (ID injection, special collections) that are best avoided today.

A small, non-invasive helper that uses the native method when present and falls back to a simple, correct traversal:

function nodeContains(parent, child) {
  if (!parent || !child) return false;
  if (parent === child) return true;            // contains includes the node itself
  if (typeof parent.contains === 'function') {
    return parent.contains(child);
  }
  // fallback for very old environments
  while (child && child !== parent) child = child.parentNode;
  return child === parent;
}

If you need the matching ancestor (or want to return the element object instead of a boolean), walk up from the child and return the ancestor or null. For filtered checks (the tag-filter idea from the thread), prefer child.matches(selector) or child.closest(selector) combined with nodeContains rather than injecting IDs or iterating a live HTMLCollection.

Notes and cautions:

  • Do not modify core prototypes unless you must polyfill a missing standard and you know the implications (library collisions, future breakage).
  • Avoid temporary ID assignment — it can clobber existing IDs and leak state.
  • Remember contains returns true if the two nodes are identical; use parent !== child && parent.contains(child) for strict descendant checks.

This keeps compatibility, performance, and safety without the brittle hacks shown in early workarounds.

Troy III 272 Posting Pro

Ups! :p
I've posted the one I've written [later] to be compatible with FX 633133 bug.
Here is the original idea using (one of the most powerful tinny features of JavaScript) - the IN Operator:

pro.contains=
function(x){return x.id in this.all}

Now that's the only reason I mention the 'in' op., in my 'overture' to this thread ...

At first I was blaming the "all" method, until I noticed that it was the aforementioned "in" operator bug on FX that was causing the failure -but as I already noted it's finally fixed.

*please use: <!DOCTYPE native> to include Firefox in authentic no-restrictions HTML mode.
(otherwise the "all" collection method will not be recognized)
----------------------------
Please note: earlier versions of IE do not support prototyping on elements.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.