I\'m trying to detect whether a custom element with a specific name was registered or not. Is there a way to make such check?
Or is there a way to get list of regist
While I am not sure it applies to other Web Component frameworks, while using Polymer in Chrome, I have a CustomElements object to the window object. The CustomElements object has a key/value collection of all registered custom elements called registry.
function isRegistered(name) {
if (window.CustomElements && window.CustomElements.registry)
return name in window.CustomElements.registry;
return undefined;
}
Since custom elements is now part of the latest standard, I thought I'd share how to do this in 2017+:
Note: the
document.registerElementfunction has been deprecated in favor of customElements.define().
customElements is defined as a global in window. There are three methods defined:
definegetwhenDefinedget is the important one here. get takes a string of the element name and returns the constructor for the named custom element, or undefined if there is no custom element definition for the name.
So in 2017+ to check if an element has been registered do you:
const myElementExists = !!customElements.get('my-element');
I'm not sure if there's a way to get a list of defined elements however.
NOTE: this doesn't work in IE. See here for browser compatibility
in scenarios where custom element classes (constructors) self-register an element, it is sufficient to check for the presence of the class
There is a way to check whether an element was registered. Registered elements have their own constructors, while unregistered ones would use plain HTMLElement() for constructor (or HTMLUnknownElement() whether the name is not valid, but this is out of scope of the question):
document.registerElement('x-my-element');
document.createElement('x-my-element').constructor
//⇒ function x-my-element() { [native code] }
document.createElement('x-my-element-not-registered').constructor
//⇒ function HTMLElement() { [native code] }
That said, the checker might look like:
var isRegistered = function(name) {
return document.createElement(name).constructor !== HTMLElement;
}
Or, with syntactic sugar:
String.prototype.isRegistered = function() {
return document.createElement(this).constructor !== HTMLElement;
}
'x-my-element'.isRegistered()
//⇒ true
'xx-my-element'.isRegistered()
//⇒ false
The mostly careful version:
String.prototype.wasRegistered = function() {
switch(document.createElement(this).constructor) {
case HTMLElement: return false;
case HTMLUnknownElement: return undefined;
}
return true;
}
'x-my-element'.wasRegistered()
//⇒ true
'xx-my-element'.wasRegistered()
//⇒ false
'xx'.wasRegistered()
//⇒ undefined
There is no way to access a list of registered elements, AFAIK.
BTW, I still think that the try-catched registration (as proposed by @stephan-muller) suits your needs better.
As written already on the Polymer's Slack channel, this is a dirty one that can make the job:
function isElementRegistered(elementId) {
return Polymer.telemetry.registrations.find(function(item) { return item.is === elementId })
}
Not sure how much Polumer.telemetry.registrations is reliable though (haven't seen it on the doc) and Array.prototype.find is not cross-browser!
Combining a few of the above approaches you can iterate over everything in use and spit out a unique list of custom (and registered) elements:
function isRegistered(name) {
return document.createElement(name).constructor.__proto__ !== window.HTMLElement;
}
var allElems = document.querySelectorAll('html /deep/ *');
var nodeNames = [].map.call(allElems, el => el.nodeName.toLowerCase())
.filter((value, index, self) => self.indexOf(value) === index)
console.log('all elements', nodeNames);
console.log('registered, custom elements', nodeNames.filter(isRegistered))