In my polymer element i have attributeChanged method
Polymer('my-tag', {
//some code
attributeChanged: function(attrName, oldVal, newVal) {
console.log(attrName, 'old: ' + oldVal, 'new:', newVal);
},
myAttributeChanged: function(oldVal, newVal){
console.log("myattribute changed", 'old: ' + oldVal, 'new:', newVal);
}
});
This get invoked when i manually change attribute.
tag.setAttribute('myAttribute',"wow");
this does not get invoked when i set attribute by 2 way data binding
<my-tag id="myTagId" myAttribute="{{wowAtrribute}}"></my-tag>
//in script section
this.wowAttribute = "wow";
This does not invoke attributeChanged
method, while just invoking myAttributeChanged
.
Is this expected behaviour? Is there way to get a blanked Changed method invoked for 2 way data binding?
TLDR: Digging around in poylmer.js and CustomElements.js what you're seeing is indeed how it's supposed to act (may not their intention, but in the code at least).
In CustomElements.js there's these couple functions which overload together overload the setAttribute and removeAttribute functions to call the changeAttributeCallback function.
function overrideAttributeApi(prototype) {
if (prototype.setAttribute._polyfilled) {
return;
}
var setAttribute = prototype.setAttribute;
prototype.setAttribute = function(name, value) {
changeAttribute.call(this, name, value, setAttribute);
};
var removeAttribute = prototype.removeAttribute;
prototype.removeAttribute = function(name) {
changeAttribute.call(this, name, null, removeAttribute);
};
prototype.setAttribute._polyfilled = true;
}
function changeAttribute(name, value, operation) {
name = name.toLowerCase();
var oldValue = this.getAttribute(name);
operation.apply(this, arguments);
var newValue = this.getAttribute(name);
if (this.attributeChangedCallback && newValue !== oldValue) {
this.attributeChangedCallback(name, oldValue, newValue);
}
}
In polymer.js 'attributeChanged' is effectively aliased as 'attributeChanged'. So the only time that callback is used is when you use setAttribute or removeAttribute.
For individual attributes though it's different. This, in polymer.js is where those 'myAttributeChanged' functions are setup
inferObservers: function(prototype) {
// called before prototype.observe is chained to inherited object
var observe = prototype.observe, property;
for (var n in prototype) {
if (n.slice(-7) === 'Changed') {
property = n.slice(0, -7);
if (this.canObserveProperty(property)) {
if (!observe) {
observe = (prototype.observe = {});
}
observe[property] = observe[property] || n;
}
}
}
}
So basically, for any property that ends in "Changed" polymer sets up an observer for whatever proceeds "Changed". Interestingly, this doesn't actually have to be an attribute defined anywhere in your polymer element to work, but that's a different story.