Reputation: 886
I'm working with custom elements and I noticed in one case I was unable to access the properties of an instance as in var prop = myCustomElement.myPropery // undefined
where the property is defined in the class as e.g. get myProperty() { blah }
.
I've boiled the problem down to what gets reported as in myCustomElement.constructor
( and thus the prototype/instance type ) when the custom element is defined in a script type="module" vs. without the module type.
Here's a very simple example:
var test = document.getElementById ( "test" );
console.log ( test.mood, test.constructor );
<script type="module">
const template = document.createElement ( "template" );
template.innerHTML = "<span>Hello!</span>";
window.customElements.define ( "test-case",
class TestCase extends window.HTMLElement {
constructor () {
super ();
var frag = template.content.cloneNode ( true ),
shadow = this.attachShadow( { mode: "open" } );
shadow.appendChild ( frag );
}
get mood () {
return "Happy!";
}
} );
</script>
<test-case id="test"></test-case>
... and without the module type
var test = document.getElementById ( "test" );
console.log ( test.mood, test.constructor );
<script>
const template = document.createElement ( "template" );
template.innerHTML = "<span>Hello!</span>";
window.customElements.define ( "test-case",
class TestCase extends window.HTMLElement {
constructor () {
super ();
var frag = template.content.cloneNode ( true ),
shadow = this.attachShadow( { mode: "open" } );
shadow.appendChild ( frag );
}
get mood () {
return "Happy!";
}
} );
</script>
<test-case id="test"></test-case>
This seems quite wrong, is this behavior intentional?
And also, assuming the need to use a module for the purpose of e.g. defining a custom element to be used inside a larger component or library, is there a straight forward way to prevent the module from hiding the type of the custom element?
Note: I'm testing this from latest Chrome (74.0.3729.157), and haven't tried other browsers.
Upvotes: 1
Views: 357
Reputation: 10965
Your non-module script is running before the module script. So you simply need to wait until the element has been defined but calling customElements.whenDefined
:
https://devdocs.io/dom/customelementregistry/whendefined
Also there is no reason to use window
when using customElements
or HTMLElement
.
customElements.whenDefined('test-case').then(
() => {
const test = document.getElementById ( "test" );
console.log ( test.mood, test.constructor );
}
);
<script type="module">
const template = document.createElement ( "template" );
template.innerHTML = "<span>Hello!</span>";
customElements.define ( "test-case",
class TestCase extends HTMLElement {
constructor () {
super ();
const frag = template.content.cloneNode ( true );
const shadow = this.attachShadow( { mode: "open" } );
shadow.appendChild ( frag );
}
get mood () {
return "Happy!";
}
}
);
</script>
<test-case id="test"></test-case>
Upvotes: 1
Reputation: 3527
You need to wait until the element is defined.
See CustomElementRegistry.whenDefined()
The whenDefined() method of the CustomElementRegistry interface returns a Promise that resolves when the named element is defined.
customElements.whenDefined('test-case').then(
() => {
const test = document.getElementById("test");
console.log(test.mood, test.constructor);
}
);
<script type="module">
const template = document.createElement ( "template" );
template.innerHTML = "<span>Hello!</span>";
window.customElements.define ( "test-case",
class TestCase extends window.HTMLElement {
constructor () {
super ();
var frag = template.content.cloneNode ( true ),
shadow = this.attachShadow( { mode: "open" } );
shadow.appendChild ( frag );
}
get mood () {
return "Happy!";
}
} );
</script>
<test-case id="test"></test-case>
Upvotes: 1