Elements declared in HTML after Custom Element do not render
up vote
1
down vote
favorite
REAL BIG EDIT:
Hello there, this is edit number 3. This one is here on top because, well, it changes the fundamental question of this post.
In short, I tried putting h1
s both before and after a single Custom Element. Well... only what I have putted before rendered. So, I guess the problem is that no elements are rendered after my Custom Elements.
I'm not deleting my old observations below for recording purposes, since someone may happen to strumble in this problem and understand it wrong, like me.
I'm trying a little bit with Custom Elements v1 on Chrome but things aren't quite right.
The custom element in question - I call it range-slider
- is just a bunch of 1 label
, 1 input range
and 1 input number
put together and styled, plus number
and range
are bind to each other.
RangeSlider.js:
class RangeSlider extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.initShadowDom();
this.flowInputToElem("field", "slider");
this.flowInputToElem("slider", "field");
}
initShadowDom() {
const shadowRoot = this.attachShadow({mode: "open"});
shadowRoot.innerHTML = this.template;
}
flowInputToElem(inputId, elemId) {
const shadowRoot = this.shadowRoot;
const input = shadowRoot.getElementById(inputId);
const elem = shadowRoot.getElementById(elemId);
input.addEventListener("input", e => {
const min = parseFloat(elem.min);
const max = parseFloat(elem.max);
const newVal = parseFloat(input.value);
elem.value = newVal > max
? max
: newVal < min
? min
: newVal;
});
}
get label() {
return this.getAttribute("label") || "Range slider";
}
get min() {
return this.getAttribute("min") || 0;
}
get max() {
return this.getAttribute("max");
}
get value() {
return this.getAttribute("value") || 0;
}
get template() {
return `
<style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style>
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider
w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none
spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
window.customElements.define('range-slider', RangeSlider);
In my understanding, everything seems to be fine with range-slider
. In fact, it works; well, kind of. If I put more than 1 range-slider
on my index.html, only the first one is rendered.
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Pegada de carbono</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="style/position.css">
<link rel="stylesheet" type="text/css" href="style/color.css">
<link rel="stylesheet" type="text/css" href="style/size.css">
<script src="components/rangeSlider/RangeSlider.js"></script>
</head>
<body class="pos-abs h-fill w-fill mrg-none pdg-none bg-white">
<range-slider label="example 1" min="0" max="100" value="25"></range-slider>
<range-slider label="example 2" min="0" max="100" value="45"></range-slider>
<range-slider label="example 3" min="0" max="100" value="65"></range-slider>
</body>
</html>
Chrome:
Why is that?
EDIT:
Strangely enough, when I append the element by JavaScript it renders as expected.
const rangeSlider = document.createElement("range-slider");
rangeSlider.label = "example 4";
rangeSlider.value = "65";
rangeSlider.max = "1000";
rangeSlider.min = "0";
document.body.appendChild(rangeSlider);
EDIT 2:
Okay, I have done some more testing and weirder things happened:
1. if I put 1 native element then 1 range-slider
(or vice-versa),
everything renders okay;
2. if I put range-slider
, native component then another range-slider
, only the first range-slider
renders; (which means not even the native component is okay)
3. if I try to add range-slider
s inside another Custom Element, the outer Custom Element is good and range-slider
number 1 too, but all the other range-slider
s are not.
javascript html google-chrome shadow-dom custom-element
add a comment |
up vote
1
down vote
favorite
REAL BIG EDIT:
Hello there, this is edit number 3. This one is here on top because, well, it changes the fundamental question of this post.
In short, I tried putting h1
s both before and after a single Custom Element. Well... only what I have putted before rendered. So, I guess the problem is that no elements are rendered after my Custom Elements.
I'm not deleting my old observations below for recording purposes, since someone may happen to strumble in this problem and understand it wrong, like me.
I'm trying a little bit with Custom Elements v1 on Chrome but things aren't quite right.
The custom element in question - I call it range-slider
- is just a bunch of 1 label
, 1 input range
and 1 input number
put together and styled, plus number
and range
are bind to each other.
RangeSlider.js:
class RangeSlider extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.initShadowDom();
this.flowInputToElem("field", "slider");
this.flowInputToElem("slider", "field");
}
initShadowDom() {
const shadowRoot = this.attachShadow({mode: "open"});
shadowRoot.innerHTML = this.template;
}
flowInputToElem(inputId, elemId) {
const shadowRoot = this.shadowRoot;
const input = shadowRoot.getElementById(inputId);
const elem = shadowRoot.getElementById(elemId);
input.addEventListener("input", e => {
const min = parseFloat(elem.min);
const max = parseFloat(elem.max);
const newVal = parseFloat(input.value);
elem.value = newVal > max
? max
: newVal < min
? min
: newVal;
});
}
get label() {
return this.getAttribute("label") || "Range slider";
}
get min() {
return this.getAttribute("min") || 0;
}
get max() {
return this.getAttribute("max");
}
get value() {
return this.getAttribute("value") || 0;
}
get template() {
return `
<style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style>
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider
w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none
spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
window.customElements.define('range-slider', RangeSlider);
In my understanding, everything seems to be fine with range-slider
. In fact, it works; well, kind of. If I put more than 1 range-slider
on my index.html, only the first one is rendered.
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Pegada de carbono</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="style/position.css">
<link rel="stylesheet" type="text/css" href="style/color.css">
<link rel="stylesheet" type="text/css" href="style/size.css">
<script src="components/rangeSlider/RangeSlider.js"></script>
</head>
<body class="pos-abs h-fill w-fill mrg-none pdg-none bg-white">
<range-slider label="example 1" min="0" max="100" value="25"></range-slider>
<range-slider label="example 2" min="0" max="100" value="45"></range-slider>
<range-slider label="example 3" min="0" max="100" value="65"></range-slider>
</body>
</html>
Chrome:
Why is that?
EDIT:
Strangely enough, when I append the element by JavaScript it renders as expected.
const rangeSlider = document.createElement("range-slider");
rangeSlider.label = "example 4";
rangeSlider.value = "65";
rangeSlider.max = "1000";
rangeSlider.min = "0";
document.body.appendChild(rangeSlider);
EDIT 2:
Okay, I have done some more testing and weirder things happened:
1. if I put 1 native element then 1 range-slider
(or vice-versa),
everything renders okay;
2. if I put range-slider
, native component then another range-slider
, only the first range-slider
renders; (which means not even the native component is okay)
3. if I try to add range-slider
s inside another Custom Element, the outer Custom Element is good and range-slider
number 1 too, but all the other range-slider
s are not.
javascript html google-chrome shadow-dom custom-element
Updated post with some more details.
– Henrique Guerra
Nov 11 at 4:08
Updated the post to address new question. In short, I thought that I was having problems to render N-ary Custom Elements. After some tests, it seems that I'm not capable of rendering any elements declared by HTML after a Custom one.
– Henrique Guerra
Nov 11 at 5:04
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
REAL BIG EDIT:
Hello there, this is edit number 3. This one is here on top because, well, it changes the fundamental question of this post.
In short, I tried putting h1
s both before and after a single Custom Element. Well... only what I have putted before rendered. So, I guess the problem is that no elements are rendered after my Custom Elements.
I'm not deleting my old observations below for recording purposes, since someone may happen to strumble in this problem and understand it wrong, like me.
I'm trying a little bit with Custom Elements v1 on Chrome but things aren't quite right.
The custom element in question - I call it range-slider
- is just a bunch of 1 label
, 1 input range
and 1 input number
put together and styled, plus number
and range
are bind to each other.
RangeSlider.js:
class RangeSlider extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.initShadowDom();
this.flowInputToElem("field", "slider");
this.flowInputToElem("slider", "field");
}
initShadowDom() {
const shadowRoot = this.attachShadow({mode: "open"});
shadowRoot.innerHTML = this.template;
}
flowInputToElem(inputId, elemId) {
const shadowRoot = this.shadowRoot;
const input = shadowRoot.getElementById(inputId);
const elem = shadowRoot.getElementById(elemId);
input.addEventListener("input", e => {
const min = parseFloat(elem.min);
const max = parseFloat(elem.max);
const newVal = parseFloat(input.value);
elem.value = newVal > max
? max
: newVal < min
? min
: newVal;
});
}
get label() {
return this.getAttribute("label") || "Range slider";
}
get min() {
return this.getAttribute("min") || 0;
}
get max() {
return this.getAttribute("max");
}
get value() {
return this.getAttribute("value") || 0;
}
get template() {
return `
<style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style>
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider
w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none
spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
window.customElements.define('range-slider', RangeSlider);
In my understanding, everything seems to be fine with range-slider
. In fact, it works; well, kind of. If I put more than 1 range-slider
on my index.html, only the first one is rendered.
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Pegada de carbono</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="style/position.css">
<link rel="stylesheet" type="text/css" href="style/color.css">
<link rel="stylesheet" type="text/css" href="style/size.css">
<script src="components/rangeSlider/RangeSlider.js"></script>
</head>
<body class="pos-abs h-fill w-fill mrg-none pdg-none bg-white">
<range-slider label="example 1" min="0" max="100" value="25"></range-slider>
<range-slider label="example 2" min="0" max="100" value="45"></range-slider>
<range-slider label="example 3" min="0" max="100" value="65"></range-slider>
</body>
</html>
Chrome:
Why is that?
EDIT:
Strangely enough, when I append the element by JavaScript it renders as expected.
const rangeSlider = document.createElement("range-slider");
rangeSlider.label = "example 4";
rangeSlider.value = "65";
rangeSlider.max = "1000";
rangeSlider.min = "0";
document.body.appendChild(rangeSlider);
EDIT 2:
Okay, I have done some more testing and weirder things happened:
1. if I put 1 native element then 1 range-slider
(or vice-versa),
everything renders okay;
2. if I put range-slider
, native component then another range-slider
, only the first range-slider
renders; (which means not even the native component is okay)
3. if I try to add range-slider
s inside another Custom Element, the outer Custom Element is good and range-slider
number 1 too, but all the other range-slider
s are not.
javascript html google-chrome shadow-dom custom-element
REAL BIG EDIT:
Hello there, this is edit number 3. This one is here on top because, well, it changes the fundamental question of this post.
In short, I tried putting h1
s both before and after a single Custom Element. Well... only what I have putted before rendered. So, I guess the problem is that no elements are rendered after my Custom Elements.
I'm not deleting my old observations below for recording purposes, since someone may happen to strumble in this problem and understand it wrong, like me.
I'm trying a little bit with Custom Elements v1 on Chrome but things aren't quite right.
The custom element in question - I call it range-slider
- is just a bunch of 1 label
, 1 input range
and 1 input number
put together and styled, plus number
and range
are bind to each other.
RangeSlider.js:
class RangeSlider extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.initShadowDom();
this.flowInputToElem("field", "slider");
this.flowInputToElem("slider", "field");
}
initShadowDom() {
const shadowRoot = this.attachShadow({mode: "open"});
shadowRoot.innerHTML = this.template;
}
flowInputToElem(inputId, elemId) {
const shadowRoot = this.shadowRoot;
const input = shadowRoot.getElementById(inputId);
const elem = shadowRoot.getElementById(elemId);
input.addEventListener("input", e => {
const min = parseFloat(elem.min);
const max = parseFloat(elem.max);
const newVal = parseFloat(input.value);
elem.value = newVal > max
? max
: newVal < min
? min
: newVal;
});
}
get label() {
return this.getAttribute("label") || "Range slider";
}
get min() {
return this.getAttribute("min") || 0;
}
get max() {
return this.getAttribute("max");
}
get value() {
return this.getAttribute("value") || 0;
}
get template() {
return `
<style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style>
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider
w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none
spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
window.customElements.define('range-slider', RangeSlider);
In my understanding, everything seems to be fine with range-slider
. In fact, it works; well, kind of. If I put more than 1 range-slider
on my index.html, only the first one is rendered.
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Pegada de carbono</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="style/position.css">
<link rel="stylesheet" type="text/css" href="style/color.css">
<link rel="stylesheet" type="text/css" href="style/size.css">
<script src="components/rangeSlider/RangeSlider.js"></script>
</head>
<body class="pos-abs h-fill w-fill mrg-none pdg-none bg-white">
<range-slider label="example 1" min="0" max="100" value="25"></range-slider>
<range-slider label="example 2" min="0" max="100" value="45"></range-slider>
<range-slider label="example 3" min="0" max="100" value="65"></range-slider>
</body>
</html>
Chrome:
Why is that?
EDIT:
Strangely enough, when I append the element by JavaScript it renders as expected.
const rangeSlider = document.createElement("range-slider");
rangeSlider.label = "example 4";
rangeSlider.value = "65";
rangeSlider.max = "1000";
rangeSlider.min = "0";
document.body.appendChild(rangeSlider);
EDIT 2:
Okay, I have done some more testing and weirder things happened:
1. if I put 1 native element then 1 range-slider
(or vice-versa),
everything renders okay;
2. if I put range-slider
, native component then another range-slider
, only the first range-slider
renders; (which means not even the native component is okay)
3. if I try to add range-slider
s inside another Custom Element, the outer Custom Element is good and range-slider
number 1 too, but all the other range-slider
s are not.
javascript html google-chrome shadow-dom custom-element
javascript html google-chrome shadow-dom custom-element
edited Nov 11 at 5:01
asked Nov 10 at 22:45
Henrique Guerra
187
187
Updated post with some more details.
– Henrique Guerra
Nov 11 at 4:08
Updated the post to address new question. In short, I thought that I was having problems to render N-ary Custom Elements. After some tests, it seems that I'm not capable of rendering any elements declared by HTML after a Custom one.
– Henrique Guerra
Nov 11 at 5:04
add a comment |
Updated post with some more details.
– Henrique Guerra
Nov 11 at 4:08
Updated the post to address new question. In short, I thought that I was having problems to render N-ary Custom Elements. After some tests, it seems that I'm not capable of rendering any elements declared by HTML after a Custom one.
– Henrique Guerra
Nov 11 at 5:04
Updated post with some more details.
– Henrique Guerra
Nov 11 at 4:08
Updated post with some more details.
– Henrique Guerra
Nov 11 at 4:08
Updated the post to address new question. In short, I thought that I was having problems to render N-ary Custom Elements. After some tests, it seems that I'm not capable of rendering any elements declared by HTML after a Custom one.
– Henrique Guerra
Nov 11 at 5:04
Updated the post to address new question. In short, I thought that I was having problems to render N-ary Custom Elements. After some tests, it seems that I'm not capable of rendering any elements declared by HTML after a Custom one.
– Henrique Guerra
Nov 11 at 5:04
add a comment |
1 Answer
1
active
oldest
votes
up vote
0
down vote
I took your code and modified it slightly and ran in in the snippet mode here on this page and it worked fine.
class OtherEl extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"}).innerHTML = '<div style="background-color: yellow;padding:4px;"><range-slider label="inner slider" min="0" max="100" value="5"></range-slider></div>';
}
}
window.customElements.define('other-el', OtherEl);
class RangeSlider extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"});
}
connectedCallback() {
if (this.shadowRoot.childElementCount === 0) {
this.shadowRoot.innerHTML = this.template;
this.flowInputToElem("field", "slider");
this.flowInputToElem("slider", "field");
}
}
flowInputToElem(inputId, elemId) {
const shadowRoot = this.shadowRoot;
const input = shadowRoot.getElementById(inputId);
const elem = shadowRoot.getElementById(elemId);
input.addEventListener("input", e => {
const min = elem.min;
const max = elem.max;
const newVal = input.value;
elem.value = newVal > max ? max : newVal < min ? min : newVal;
});
}
get label() {
return this.getAttribute("label") || "Range slider";
}
get min() {
return parseFloat(this.getAttribute("min") || '0');
}
get max() {
return parseFloat(this.getAttribute("max") || '100');
}
get value() {
return parseFloat(this.getAttribute("value") || '0');
}
get template() {
return `
<style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style>
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
window.customElements.define('range-slider', RangeSlider);
<h1>Before</h1>
<range-slider label="example 1" min="0" max="100" value="25"></range-slider>
<h2>After 1</h2>
<range-slider label="example 2" min="0" max="100" value="45"></range-slider>
<h2>After 2</h2>
<range-slider label="example 3" min="0" max="100" value="65"></range-slider>
<h2>After 3</h2>
<other-el></other-el>
<h2>After OtherEl</h2>
Then I ran it on my server and saw what you were seeing. Only one element showed.
But I noticed this error in the dev tools:
Since I don't have your CSS files my CSS is not loading and this is causing something to crash in the Web Component code.
When I commented out the <style>
tag in your template:
get template() {
return `
<!-- <style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style> -->
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
Then all 5 show up, including the one inside my other element.
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
I took your code and modified it slightly and ran in in the snippet mode here on this page and it worked fine.
class OtherEl extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"}).innerHTML = '<div style="background-color: yellow;padding:4px;"><range-slider label="inner slider" min="0" max="100" value="5"></range-slider></div>';
}
}
window.customElements.define('other-el', OtherEl);
class RangeSlider extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"});
}
connectedCallback() {
if (this.shadowRoot.childElementCount === 0) {
this.shadowRoot.innerHTML = this.template;
this.flowInputToElem("field", "slider");
this.flowInputToElem("slider", "field");
}
}
flowInputToElem(inputId, elemId) {
const shadowRoot = this.shadowRoot;
const input = shadowRoot.getElementById(inputId);
const elem = shadowRoot.getElementById(elemId);
input.addEventListener("input", e => {
const min = elem.min;
const max = elem.max;
const newVal = input.value;
elem.value = newVal > max ? max : newVal < min ? min : newVal;
});
}
get label() {
return this.getAttribute("label") || "Range slider";
}
get min() {
return parseFloat(this.getAttribute("min") || '0');
}
get max() {
return parseFloat(this.getAttribute("max") || '100');
}
get value() {
return parseFloat(this.getAttribute("value") || '0');
}
get template() {
return `
<style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style>
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
window.customElements.define('range-slider', RangeSlider);
<h1>Before</h1>
<range-slider label="example 1" min="0" max="100" value="25"></range-slider>
<h2>After 1</h2>
<range-slider label="example 2" min="0" max="100" value="45"></range-slider>
<h2>After 2</h2>
<range-slider label="example 3" min="0" max="100" value="65"></range-slider>
<h2>After 3</h2>
<other-el></other-el>
<h2>After OtherEl</h2>
Then I ran it on my server and saw what you were seeing. Only one element showed.
But I noticed this error in the dev tools:
Since I don't have your CSS files my CSS is not loading and this is causing something to crash in the Web Component code.
When I commented out the <style>
tag in your template:
get template() {
return `
<!-- <style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style> -->
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
Then all 5 show up, including the one inside my other element.
add a comment |
up vote
0
down vote
I took your code and modified it slightly and ran in in the snippet mode here on this page and it worked fine.
class OtherEl extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"}).innerHTML = '<div style="background-color: yellow;padding:4px;"><range-slider label="inner slider" min="0" max="100" value="5"></range-slider></div>';
}
}
window.customElements.define('other-el', OtherEl);
class RangeSlider extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"});
}
connectedCallback() {
if (this.shadowRoot.childElementCount === 0) {
this.shadowRoot.innerHTML = this.template;
this.flowInputToElem("field", "slider");
this.flowInputToElem("slider", "field");
}
}
flowInputToElem(inputId, elemId) {
const shadowRoot = this.shadowRoot;
const input = shadowRoot.getElementById(inputId);
const elem = shadowRoot.getElementById(elemId);
input.addEventListener("input", e => {
const min = elem.min;
const max = elem.max;
const newVal = input.value;
elem.value = newVal > max ? max : newVal < min ? min : newVal;
});
}
get label() {
return this.getAttribute("label") || "Range slider";
}
get min() {
return parseFloat(this.getAttribute("min") || '0');
}
get max() {
return parseFloat(this.getAttribute("max") || '100');
}
get value() {
return parseFloat(this.getAttribute("value") || '0');
}
get template() {
return `
<style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style>
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
window.customElements.define('range-slider', RangeSlider);
<h1>Before</h1>
<range-slider label="example 1" min="0" max="100" value="25"></range-slider>
<h2>After 1</h2>
<range-slider label="example 2" min="0" max="100" value="45"></range-slider>
<h2>After 2</h2>
<range-slider label="example 3" min="0" max="100" value="65"></range-slider>
<h2>After 3</h2>
<other-el></other-el>
<h2>After OtherEl</h2>
Then I ran it on my server and saw what you were seeing. Only one element showed.
But I noticed this error in the dev tools:
Since I don't have your CSS files my CSS is not loading and this is causing something to crash in the Web Component code.
When I commented out the <style>
tag in your template:
get template() {
return `
<!-- <style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style> -->
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
Then all 5 show up, including the one inside my other element.
add a comment |
up vote
0
down vote
up vote
0
down vote
I took your code and modified it slightly and ran in in the snippet mode here on this page and it worked fine.
class OtherEl extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"}).innerHTML = '<div style="background-color: yellow;padding:4px;"><range-slider label="inner slider" min="0" max="100" value="5"></range-slider></div>';
}
}
window.customElements.define('other-el', OtherEl);
class RangeSlider extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"});
}
connectedCallback() {
if (this.shadowRoot.childElementCount === 0) {
this.shadowRoot.innerHTML = this.template;
this.flowInputToElem("field", "slider");
this.flowInputToElem("slider", "field");
}
}
flowInputToElem(inputId, elemId) {
const shadowRoot = this.shadowRoot;
const input = shadowRoot.getElementById(inputId);
const elem = shadowRoot.getElementById(elemId);
input.addEventListener("input", e => {
const min = elem.min;
const max = elem.max;
const newVal = input.value;
elem.value = newVal > max ? max : newVal < min ? min : newVal;
});
}
get label() {
return this.getAttribute("label") || "Range slider";
}
get min() {
return parseFloat(this.getAttribute("min") || '0');
}
get max() {
return parseFloat(this.getAttribute("max") || '100');
}
get value() {
return parseFloat(this.getAttribute("value") || '0');
}
get template() {
return `
<style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style>
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
window.customElements.define('range-slider', RangeSlider);
<h1>Before</h1>
<range-slider label="example 1" min="0" max="100" value="25"></range-slider>
<h2>After 1</h2>
<range-slider label="example 2" min="0" max="100" value="45"></range-slider>
<h2>After 2</h2>
<range-slider label="example 3" min="0" max="100" value="65"></range-slider>
<h2>After 3</h2>
<other-el></other-el>
<h2>After OtherEl</h2>
Then I ran it on my server and saw what you were seeing. Only one element showed.
But I noticed this error in the dev tools:
Since I don't have your CSS files my CSS is not loading and this is causing something to crash in the Web Component code.
When I commented out the <style>
tag in your template:
get template() {
return `
<!-- <style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style> -->
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
Then all 5 show up, including the one inside my other element.
I took your code and modified it slightly and ran in in the snippet mode here on this page and it worked fine.
class OtherEl extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"}).innerHTML = '<div style="background-color: yellow;padding:4px;"><range-slider label="inner slider" min="0" max="100" value="5"></range-slider></div>';
}
}
window.customElements.define('other-el', OtherEl);
class RangeSlider extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"});
}
connectedCallback() {
if (this.shadowRoot.childElementCount === 0) {
this.shadowRoot.innerHTML = this.template;
this.flowInputToElem("field", "slider");
this.flowInputToElem("slider", "field");
}
}
flowInputToElem(inputId, elemId) {
const shadowRoot = this.shadowRoot;
const input = shadowRoot.getElementById(inputId);
const elem = shadowRoot.getElementById(elemId);
input.addEventListener("input", e => {
const min = elem.min;
const max = elem.max;
const newVal = input.value;
elem.value = newVal > max ? max : newVal < min ? min : newVal;
});
}
get label() {
return this.getAttribute("label") || "Range slider";
}
get min() {
return parseFloat(this.getAttribute("min") || '0');
}
get max() {
return parseFloat(this.getAttribute("max") || '100');
}
get value() {
return parseFloat(this.getAttribute("value") || '0');
}
get template() {
return `
<style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style>
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
window.customElements.define('range-slider', RangeSlider);
<h1>Before</h1>
<range-slider label="example 1" min="0" max="100" value="25"></range-slider>
<h2>After 1</h2>
<range-slider label="example 2" min="0" max="100" value="45"></range-slider>
<h2>After 2</h2>
<range-slider label="example 3" min="0" max="100" value="65"></range-slider>
<h2>After 3</h2>
<other-el></other-el>
<h2>After OtherEl</h2>
Then I ran it on my server and saw what you were seeing. Only one element showed.
But I noticed this error in the dev tools:
Since I don't have your CSS files my CSS is not loading and this is causing something to crash in the Web Component code.
When I commented out the <style>
tag in your template:
get template() {
return `
<!-- <style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style> -->
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
Then all 5 show up, including the one inside my other element.
class OtherEl extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"}).innerHTML = '<div style="background-color: yellow;padding:4px;"><range-slider label="inner slider" min="0" max="100" value="5"></range-slider></div>';
}
}
window.customElements.define('other-el', OtherEl);
class RangeSlider extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"});
}
connectedCallback() {
if (this.shadowRoot.childElementCount === 0) {
this.shadowRoot.innerHTML = this.template;
this.flowInputToElem("field", "slider");
this.flowInputToElem("slider", "field");
}
}
flowInputToElem(inputId, elemId) {
const shadowRoot = this.shadowRoot;
const input = shadowRoot.getElementById(inputId);
const elem = shadowRoot.getElementById(elemId);
input.addEventListener("input", e => {
const min = elem.min;
const max = elem.max;
const newVal = input.value;
elem.value = newVal > max ? max : newVal < min ? min : newVal;
});
}
get label() {
return this.getAttribute("label") || "Range slider";
}
get min() {
return parseFloat(this.getAttribute("min") || '0');
}
get max() {
return parseFloat(this.getAttribute("max") || '100');
}
get value() {
return parseFloat(this.getAttribute("value") || '0');
}
get template() {
return `
<style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style>
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
window.customElements.define('range-slider', RangeSlider);
<h1>Before</h1>
<range-slider label="example 1" min="0" max="100" value="25"></range-slider>
<h2>After 1</h2>
<range-slider label="example 2" min="0" max="100" value="45"></range-slider>
<h2>After 2</h2>
<range-slider label="example 3" min="0" max="100" value="65"></range-slider>
<h2>After 3</h2>
<other-el></other-el>
<h2>After OtherEl</h2>
class OtherEl extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"}).innerHTML = '<div style="background-color: yellow;padding:4px;"><range-slider label="inner slider" min="0" max="100" value="5"></range-slider></div>';
}
}
window.customElements.define('other-el', OtherEl);
class RangeSlider extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: "open"});
}
connectedCallback() {
if (this.shadowRoot.childElementCount === 0) {
this.shadowRoot.innerHTML = this.template;
this.flowInputToElem("field", "slider");
this.flowInputToElem("slider", "field");
}
}
flowInputToElem(inputId, elemId) {
const shadowRoot = this.shadowRoot;
const input = shadowRoot.getElementById(inputId);
const elem = shadowRoot.getElementById(elemId);
input.addEventListener("input", e => {
const min = elem.min;
const max = elem.max;
const newVal = input.value;
elem.value = newVal > max ? max : newVal < min ? min : newVal;
});
}
get label() {
return this.getAttribute("label") || "Range slider";
}
get min() {
return parseFloat(this.getAttribute("min") || '0');
}
get max() {
return parseFloat(this.getAttribute("max") || '100');
}
get value() {
return parseFloat(this.getAttribute("value") || '0');
}
get template() {
return `
<style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style>
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
window.customElements.define('range-slider', RangeSlider);
<h1>Before</h1>
<range-slider label="example 1" min="0" max="100" value="25"></range-slider>
<h2>After 1</h2>
<range-slider label="example 2" min="0" max="100" value="45"></range-slider>
<h2>After 2</h2>
<range-slider label="example 3" min="0" max="100" value="65"></range-slider>
<h2>After 3</h2>
<other-el></other-el>
<h2>After OtherEl</h2>
get template() {
return `
<!-- <style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style> -->
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
get template() {
return `
<!-- <style>
@import url('style/appearance.css');
@import url('style/color.css');
@import url('style/size.css');
@import url('style/position.css');
@import url('components/rangeSlider/style/slider.css');
</style> -->
<form class="w-max arial">
<label for="field">${this.label}:</label>
<div class="flx flx-middle">
<input id="slider" type="range" min="${this.min}" max="${this.max}" value="${this.value}" class="slider w-big">
<input id="field" type="number" min="0" max="${Infinity}" value="${this.value}" class="mrg-none spin-none brd-none w-small bg-transp txt-center">
</div>
</form>
`;
}
}
answered Nov 12 at 15:25
Intervalia
3,56411029
3,56411029
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53244167%2felements-declared-in-html-after-custom-element-do-not-render%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Updated post with some more details.
– Henrique Guerra
Nov 11 at 4:08
Updated the post to address new question. In short, I thought that I was having problems to render N-ary Custom Elements. After some tests, it seems that I'm not capable of rendering any elements declared by HTML after a Custom one.
– Henrique Guerra
Nov 11 at 5:04