You're not supposed to put rich data (objects, arrays, functions) in HTML element attributes. Instead, it's suggested to only put rich data in properties (according to the Google custom elements best practices article). I need to run actions when these properties are updated. We have observedAttributes
and attributeChangedCallback
, but there's nothing similar for properties.
Let's say I have a user
prop with things like name
, DoB
, and address
on it. I thought I might be able to trick observedAttributes
by putting a bunk setter a la
set user(val) {
return;
}
Didn't work. return this.user = val
gives an infinite loop.
My only idea at this point is to have a property called _user
that simply gets set to [Object object]
on every change, which triggers the change I actually want. Don't really like that though.
UPDATE: This is what I'm currently doing
In user-info.js
:
class UserInfo extends HTMLElement {
connectedCallback() {
subscribers.push({ element: this, props: ['user'] });
this._user = state.user;
this.render();
}
static get observedAttributes() {
return ['user'];
}
attributeChangedCallback(name, oldValue, newValue) {
this.render();
}
get user() {
return this._user;
}
set user(val) {
if (JSON.stringify(val) !== JSON.stringify(this._user)) {
this._user = val;
return this.setAttribute('user', val);
}
}
render() {
this.innerHTML = `<span>${this._user.name}</span> was born on <span>${this._user.dob}</span>`;
}
}
In main.js
:
document.querySelector('.actions--user').addEventListener('input', e => {
state.user = {...state.user, [e.target.dataset.action]: e.target.value};
})