Closed sourcegr closed 7 years ago
also, note that I am aware that when I include the title
in the observedAttributes
and then on the attributeChangedCallback
I do a this.update();
, it works as expected, but I believe this is overhead for the developer, especially on attributes that will probably never change in the my-title
element lifecycle!
Once again, please correct me if I am wrong
This works, and yes, it is an expected behavior, I explain you why.
class MyTitle extends HyperHTMLElement {
static get observedAttributes() { return ['title']; }
attributeChangedCallback() {
this.update()
}
update() {
return this.html`
<h2 style="background:red">${this.title}!</h2>
`;
}
}
The created()
callback is grant to be called once and before connectedCallback()
and attributeChangedCallback()
.
This is a standard behavior lost in V1 but present in V0. Custom Elements V1 don't have any mechanism to setup a component before the rest happens and with random order, since there's no guarantee that connectedCallback
will triger before attributeChangedCallback
or vice-versa.
HyperHTMLElement
grants you an entry point to setup components, so far, so good.
Whenever you need to create a shadow dom, to inject, query, or modify the content or even render, if you don't have any other ways of doing that.
In your case you are creating a component that works through attributes to show its own content.
When you use Custom Elements like that, your explicit intent is to observe attributes and react at those changes. If you don't do so, your component has already an overhead because if it's a one off that you need, drop the observable completely and just:
<my-title>${this.title}</my-title>
because if that's not what you expect, then you expect content changes when attribute changes.
And if you do so, you need attributeChangeCallback
that with native Custom Elements triggers once after the component has been setup.
If you observe attributes, and you want to react / change layout when these have a value, use attributeChangedCallback
as the entry point to render.
If you don't need to render when attributes are changed, drop observed attributes, as easy as that.
Cleaner, faster, better for you own components.
If you want automatically do that, which is something this class cannot possibly know or do, unless it forces you to have a render()
(or update()
? or maybe populate()
?) method with a fixed signature, you can create your thin layer and define your own fixed behavior with your component.
class MyBase extends HyperHTMLElement {
attributeChangedCallback() { this.update(); }
update() {}
}
That's it, from now on all you have to extend is MyBase
instead of HyperHTMLElement
.
After all, isn't this why classes can also be awesome?
After all, isn't this why classes can also be awesome?
yes, one of the few times! ;)
The think is that this is a minimal example, just to describe the situation. There ara times where more than one variable has to be changed or displayed and the <my-title>${this.title}</my-title>
solution is not suitable!
Many thanks for your explanation!
There are times where more than one variable has to be changed or displayed
And don't you need to re-render the component when these changes happen?
Also, how do you know that an attribute has been set at all, if you don't render on both created and attributeChangedCallback?
You are using native Custom Elements behavior here.
Rather than explaining why it's normal to need rendering eventually on both created and attributeChangedCallback, there's not much else I can do.
Custom Elements are upgraded by specifications. If these have observed attributes and these attributes have a value, the attributeChangedCallback
will be triggered.
If you need to change anything on the layout when this happens, you need to render on attributeChangedCallback otherwise you're shooting your own foot :wink:
P.S. calling this.update
even 60 times per second is safe and fast. The whole point of hyperHTML is that updates are the cheapest thing ever: same values won't modify the DOM at all
Thanks for the info!
I understand that this topic is actually beyond the HyperHTML-Element scope so I really appreciate the advice
Keep up the great work!
OK, this might be a silly question, or maybe something is wrong with my understanding.
please see this plunk
The title is not displayed in the first
my-title
element which is defined in themy-element
template. It gets itstitle
attribute from the parent element. The secondmy-title
has a static title, and it shows up as expected.I was expecting that it would be visible, but it is not. Is this the expected behaviour?
If so, could someone be kind enough to explain me why this is happening and how I could avoid such cases in the future?
In this plunk, I also included a button that, when clicked, updates the
my-title
element, and then, the title shows up!Tia,