Reputation: 11
I have an element which renders a array of objects using dom-repeat. There is also a feature to modify a particular object. However, after updating the object, even if the array is updated, the dom does not reflect the change (render is called as well). I am using Polymer provided mutation function (this.slice, have a look in the _commitChange function below). Can someone point out what is wrong here? One thing to note is that individual items in the array are objects rather than primitives /
<dom-module id="em-person-qualifications">
<template>
<style include="shared-styles"></style>
<style>
:host {
display: block;
}
iron-pages {
height: 100%;
}
</style>
<iron-pages id="container" selected="0">
<div id="listContainer">
<template id="listTemplate" is="dom-repeat" items="[[data]]">
<paper-item>
<paper-item-body two-line>
<div>
<span>[[item.qualificationLevel.level]]</span>,
<span>[[item.qualificationLevel.levelCategory]]</span>
</div>
<div secondary>
<span>[[item.fromInstitute.edumateOrgDisplayName]]</span>
<span>[[item.status]]</span>
</div>
</paper-item-body>
<paper-icon-button icon="more-vert" on-tap="_loadModifyUI"></paper-icon-button>
</paper-item>
</template>
</div>
<div id="detailContainer">
<paper-toolbar>
<div class="title">
<us-com-i18n key="qualificationDetail"></us-com-i18n>
</div>
<paper-icon-button id="button" icon="clear" on-click="_showList"></paper-icon-button>
</paper-toolbar>
<div>
<iron-label for="levelContainer">
<us-com-i18n key="level"></us-com-i18n>
</iron-label>
<div id="levelContainer" class="layout horizontal wrap">
<us-com-freeorref data="{{currItem.qualificationLevel.level}}"></us-com-freeorref>
<paper-dropdown-menu label="select">
<paper-menu class="dropdown-content" attrForSelected="data-value" selected="{{currItem.qualificationLevel.levelCategory}}">
<paper-item data-value="10">Graduate</paper-item>
<paper-item data-value="11">Post-graduate</paper-item>
</paper-menu>
</paper-dropdown-menu>
</div>
<iron-label for="majorSubjectContainer">
<us-com-i18n key="majors"></us-com-i18n>
</iron-label>
<div id="majorSubjectContainer">
<template is="dom-repeat" items="[[currItem.majorSubjects]]">
<em-party-subject data="{{item}}"></em-party-subject>
</template>
</div>
<iron-label for="minorSubjectContainer">
<us-com-i18n key="minors"></us-com-i18n>
</iron-label>
<div id="minorSubjectContainer">
<template is="dom-repeat" items="[[currItem.minorSubjects]]">
<em-party-subject data="{{item}}"></em-party-subject>
</template>
</div>
<iron-label for="during">
<us-com-i18n key="during"></us-com-i18n>
</iron-label>
<div class="layout horizontal wrap" id="during">
<span><us-com-i18n key="from"></span>
<us-com-date data="{{currItem.fromMonthYear}}"></us-com-date>
<span><us-com-i18n key="to"></span>
<us-com-date data="{{currItem.toMonthYear}}"></us-com-date>
</div>
<paper-input type="text" value="{{currItem.status}}" label="status">
<us-com-formattedlongtext data="{{currItem.achievmentStatement}}" label="achievements"></us-com-formattedlongtext>
<div class="buttons">
<paper-button tabindex="0" raised autofocus on-click="_commitChange">
<iron-icon icon="check"></iron-icon>Ok
</paper-button>
</div>
</div>
</div>
</iron-pages>
</template>
<script>
(function() {
'use strict';
Polymer({
is: 'em-person-qualifications',
properties: {
data: {
type: Array,
value: function() {
return [{
'qualificationLevel': {
'level': 'Bsc',
'levelCategory': 10
},
'majorSubjects': [],
'minorSubjects': [],
'fromMonthYear': {},
'toMonthYear': {},
'fromInstitute': {
'edumateOrgDisplayName': 'XYZ College'
},
'status': 'ABCD',
'achievmentStatement': {}
}, {
'qualificationLevel': {
'level': 'M-Tech',
'levelCategory': 11
},
'majorSubjects': [],
'minorSubjects': [],
'fromMonthYear': {},
'toMonthYear': {},
'fromInstitute': {
'edumateOrgDisplayName': 'ABC College'
},
'status': 'EFGH',
'achievmentStatement': {}
}];
}
},
currItem: Object,
currIndex: Number,
currChange: String
},
behaviors: [app.I18nBehavior],
_showList: function() {
this._commitChange();
//this.$.container.selected = '0';
},
_loadAddUI: function() {
this.currChange = 'A';
this.currItem = {};
this.$.container.selected = '1';
},
_loadModifyUI: function(e) {
this.currChange = 'M';
this.currItem = e.model.item;
this.currIndex = this.data.indexOf(e.model.item);
this.$.container.selected = '1';
},
_loadDeleteUI: function() {
this.currChange = 'D';
//Find out the index from the data-index attribute of the button
this.currIndex = 0;
},
_commitChange: function() {
//var model = e.model;
//this.splice('data',)
if (this.currChange === 'A') {
this.push('data', this.currItem);
} else if (this.currChange === 'M') {
this.splice('data', this.currIndex, 1, this.currItem);
console.log('data[this.currIndex] = ' + this.data[this.currIndex].status);
} else if (this.currChange === 'D') {
this.splice('data', this.currIndex, 1);
}
this.$.listTemplate.render();
this.$.container.selected = '0';
}
});
})();
</script>
</dom-module>
Strings as I see in most examples.
Upvotes: 1
Views: 340
Reputation: 7591
I'm on a huge Polymer 1.9 project, and is currently switching to Polymer 2.0, and I can tell that things like updating a dom-repeat is handled in a better way in Polymer 2.
Updating subproperties in a dom-repeat is a nightmare in 1.0, and the simplest solution is to override dirty checking, where Polymer is checking every single property to see if the DOM needs to update.
var copiedData = JSON.parse( JSON.stringify(data) );
this.set('data', []);
this.set('data', copiedData);
If you're desperate, use this method, but it can create a performance issue on phones or if the list is over about 100 items. You could probably also just do ...
this.set('data', JSON.parse( JSON.stringify(data) ));
... as a totally new array will override dirty checking. Anyways, a dom-repeat wont update with this.splice
if the length of the array doesn't change, so I would do something like this.set('data.' + this.currIndex, this.currItem)
to update the subproperty directly instead of the splicing that occurs here:
_commitChange: function() {
// ...
} else if (this.currChange === 'M') {
this.splice('data', this.currIndex, 1, this.currItem);
Also, you don't need this as Polymer should update automatically:
this.$.listTemplate.render();
Upvotes: 1