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};
})