10👍
Remember that none of the regular HTML elements come with constructor arguments either: don’t rely on them. Instead, rely on attributes, with JS property backing, and hook those up according to the custom elements spec.
So, in the same way that you’d have to the following code for an Image
:
let img = new Image();
img.src = "https://example.com/someimage.jpg";
img.width = ...
...
or a script element:
let script = document.createElement("script");
script.src = ...
// or script.textContent = ...
your component should not need constructor properties. You’d use it like this:
let preview = new TrackingPreview();
preview.width = 1920;
preview.height = 1080;
or in HTML form,
<track-preview width="100" height="200" ...></track-preview>
And have your custom element react to those properties getting set:
class TrackingPreview extends HTMLElement {
static get observedAttributes() {
return [`width`, `height`];
}
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
const video = this.video = document.createElement('video');
video.setAttribute(`controls`, `controls`);
video.setAttribute(`width`, this.getAttribute(`width`) || 1920);
video.setAttribute(`height`, this.getAttribute(`height`) || 1080);
shadow.appendChild(video);
}
get width() {
return this.video.width;
}
set width(val) {
this.setAttribute(`width`, val);
}
get height() {
return this.video.height;
}
set height(val) {
this.setAttribuite(`height`, val);
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === `width`) {
this.video.width = newValue;
}
if (name === `height`) {
this.video.height = newValue;
}
// ...
}
// ...
}
7👍
The rules of a constructor for a Web Component are pretty strict. One rule is that you are not allowed to pass in any arguments into the constructor.
https://w3c.github.io/webcomponents/spec/custom/#custom-element-conformance
Instead use both a property and an attribute
class TrackingPreview extends HTMLElement {
static get observedAttributes() {
return ['videoid'];
}
constructor() {
super();
const video = document.createElement('video');
video.setAttribute('controls', '');
video.width = 192;
video.height = 108;
this.video = video;
this.attachShadow({mode: 'open'}).appendChild(video);
}
attributeChangedCallback(attrName, oldVal, newVal) {
if (oldVal !== newVal) {
// Since we only watch videoid there is no need to check attrName
this.video.setAttribute('id', newVal);
}
}
get videoId() {
return this.video.getAttribute('id');
}
set videoId(val) {
if (val == null) { // check for null and undefined
this.removeAttribute('videoid');
}
else {
this.setAttribute('videoid', val);
}
}
}
customElements.define('tracking-preview', TrackingPreview);
setTimeout(function() {
let el = document.querySelector('tracking-preview');
if (el) {
console.log(el.videoId);
el.videoId = 99;
console.log(el.videoId);
}
}, 500);
<tracking-preview videoid="10"></tracking-preview>
When you attribute videoid
is set then the attributeChangedCallback
function is called and you pass the value down to your video
element.
In my timeout function I both read and write the videoId
property which read and writes the videoid
attribute.
- Where are my environment variables in Elastic Beanstalk for AL2?
- Convert data on AlterField django migration
- Should I use google-app-engine-django or app-engine-patch or neither or something else?
- Calculate point based on distance and direction
- Crispy-forms: add css class for one of the inputs
-3👍
You can do it with the new
keyword:
const tacking_preview = new TrackingPreview( id )