Reputation: 3316
I am trying to bind a Polymer
property to the disabled attribute of a CheckBox
, but the CheckBox
only get disabled/enabled at the beginning.
I have to mention that the property I am binding to is a sub-property of a Polymer
property.
Component's code:
<link rel="import" href="../polymer/polymer.html"/>
<dom-module id="checkbox-disabled-example">
<template>
<button
on-click="onClick" >
Toggle Disabled Enabled </button>
<template is="dom-repeat" items="{{elementsObject.items}}" as="item">
<input
type="checkbox"
disabled$="{{item.disabled}}" >
{{item.name}} <br>
</template>
</template>
<script>
Polymer({
is: 'checkbox-disabled-example',
properties:{
elementsObject:{
type: Object,
value: {}
},
},
onClick: function(){
this.elementsObject.items.forEach(
function(item, index, array){
item.disabled = !item.disabled;
}
);
}
});
</script>
</dom-module>
index.html code:
<body>
<template id="just-for-demo" is="dom-bind" >
<checkbox-disabled-example elements-object={{ckData}} >
</checkbox-disabled-example>
</template>
<script>
window.addEventListener('WebComponentsReady', function() {
var template = document.querySelector('template[is=dom-bind]');
var data =
{
items:
[
{ disabled: true, name:"Element 01"},
{ disabled: false, name:"Element 02"},
{ disabled: false, name:"Element 03"},
{ disabled: false, name:"Element 04"},
{ disabled: false, name:"Element 05"},
{ disabled: true, name:"Element 06"}
]
};
template.ckData = data;
});
</script>
</body>
As you can see I create several Check Boxes, each one of them bound to the disabled property of its item.
When I click on the button I toggle the disabled value of each item, however the Check boxes states don't change.
What am I doing wrong?
Upvotes: 3
Views: 643
Reputation: 3850
Changes that imperatively mutate an object or array are not observable. If you have a simple property like:
this.name = 'Jane';
Polymer will automatically create a setter and it will automatically pick up any changes on that property. However, changes on an object subproperty or an array item will not work:
this.address.street = 'Elm Street';
The setter on address will not be called and the change will not be detected.
Polymer provides specific methods for making observable changes to subproperties and arrays, in the example above you would need to call:
this.set('address.street', 'Elm Street');
The address.street part is called path. It's a string that identifies a property or subproperty relative to a scope. In most cases, the scope is a host element. If you are creating a path to an array item, you will need to pass the index:
this.set('items.5', 'Changed index 5');
In your specific example, a simple change to the click event handler would be enough:
onClick: function() {
var that = this;
this.elementsObject.items.forEach(function(item, index, array) {
that.set('elementsObject.items.'+index+'.disabled', !item.disabled);
});
}
Or you can use the cool new ES6 arrow function syntax to make it more readable and remove the ugly that = this:
onClick: function() {
this.elementsObject.items.forEach((item, index, array) => {
this.set('elementsObject.items.'+index+'.disabled', !item.disabled);
});
}
Upvotes: 1