Reputation: 339
I'd problem when I set a object y a property in webcomponents. In my code it's listening change in a property with attributeChangedCallback(attrName, oldVal, newVal)
but when I receive a new property the value of newVal is equal to [Object object]
. Why is it happening?
Thanks
Upvotes: 1
Views: 2197
Reputation: 7591
From the documentation:
attributeChangedCallback (native)
Attributes must be explicitly registered to be observed.
For Polymer elements, only properties explicitly declared in the properties object are tracked for attribute changes. (That is, changing the attribute value invokes the attribute changed callback, and causes Polymer to set the property value from the attribute.)
https://polymer-library.polymer-project.org/2.0/docs/about_20
If you're getting [object object], I'm guessing that you need to declare the object in properties
.
Also, I wouldn't use attributeChangedCallback
myself, but instead put a complex observer on the property.
class XCustom extends Polymer.Element {
static get is() {return 'x-custom'; }
static get properties() {
return {
user: {
type: Object,
value: function() {
return {};
}
}
}
}
// Observe the name sub-property on the user object
static get observers() {
return [
'userNameChanged(user.name)'
]
}
// For a property or sub-property dependency, the corresponding
// argument is the new value of the property or sub-property
userNameChanged(name) {
if (name) {
console.log('new name: ' + name);
} else {
console.log('user name is undefined');
}
}
}
https://polymer-library.polymer-project.org/2.0/docs/devguide/observers#simple-observers
Upvotes: 0
Reputation: 11574
Best practice suggests we handle attribute and property changes in the attributeChangedCallback method of HTMLElements. The distinction being attributes are set via html, e.g. <my-element size=3>
; whereas properties are set in the js, e.g. myElement.size = 3
.
The idea is, our HTMLElement subclasses would have a size setter that would set the attribute, and allow us to handle both cases in attributeChangedCallback
, e.g.
class MyElement extends HTMLElement {
...
get size() {
return this.getAttribute('size');
}
set size(value) {
this.setAttribute('size', value);
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'size') {
// handle size update here
}
}
}
This seems like a good idea, in that it allows a single place to handle both possible methods of updating the size. In fact, this is encouraged by google's HTMLElement best practices guide
That being said, this is problematic given that HTML attributes can only handle strings. So then, we have 2 alternatives,
1) Disregard the best practices suggestion, which isn't totally unreasonable given HTMLElements are still a new thing and best practices aren't necessarily drawn from decades of experience working with them. Perhaps, we do the exact opposite, of delegating attribute changes to property changes, as this would still achieve google's suggested aim, 'avoid[ing] reentrancy issues` and having a single handler.
class MyElement extends HTMLElement {
...
get size() {
this.size_;
}
set size(value) {
this.size_ = value;
// handle size update here
}
attributeChangedCallback(name, oldValue, newValue) {
this[name] = newValue;
}
}
or 2) Rely on setters for properties that can be set to JS objects and attributeChangedCallback for properties that can be represented as strings.
class MyElement extends HTMLElement {
...
get size() {
return this.getAttribute('size');
}
set size(value) {
this.setAttribute('size', value);
}
get myObj() {
return this.myObj_;
}
set myObj(value) {
this.myObj_ = value;
// handle myObj update here
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'size') {
// handle size update here
}
}
}
Upvotes: 2
Reputation: 31181
A HTML element attribute is always of type string.
If you want to pass a Javascript object, you should convert it to a JSON notation:
<custom-element attribute-name='{ "value": "v1" }'></custom-element>
You can then parse it attributeChangedCallback()
:
var o = JSON.parse( newVal )
Upvotes: 2
Reputation: 10945
Since you didn't provide any example code I can't figure out what is failing.
But here is a simple component that supports the attributeChangedCallback
method.
If this code helps, great. But it would be nice to see your code to understand what is failing.
// Class for `<my-el>`
class MyEl extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
}
static get observedAttributes() {
return ['name'];
}
attributeChangedCallback(attrName, oldVal, newVal) {
if (oldVal !== newVal) {
this.shadowRoot.innerHTML = newVal;
}
}
}
// Define our web component
customElements.define('my-el', MyEl);
<my-el name="Frodo Baggins"></my-el>
Upvotes: 0