Skip to content

Commit

Permalink
Reduce keySplices to minimum change set before notifying. Fixes #2261
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinpschaaf committed Aug 12, 2015
1 parent 7497729 commit f74d072
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 32 deletions.
48 changes: 27 additions & 21 deletions src/lib/collection.html
Expand Up @@ -106,32 +106,38 @@
},

_applySplices: function(splices) {
var keySplices = [];
for (var i=0; i<splices.length; i++) {
var j, o, key, s = splices[i];
// Removed keys
var removed = [];
for (j=0; j<s.removed.length; j++) {
o = s.removed[j];
key = this.remove(o);
// Dedupe added and removed keys to a final added/removed map
var keyMap = {}, key, i;
splices.forEach(function(s) {
s.addedKeys = [];
for (i=0; i<s.removed.length; i++) {
key = this.getKey(s.removed[i]);
keyMap[key] = keyMap[key] ? null : -1;
}
for (i=0; i<s.addedCount; i++) {
var item = this.userArray[s.index + i];
key = this.getKey(item);
key = (key === undefined) ? this.add(item) : key;
keyMap[key] = keyMap[key] ? null : 1;
s.addedKeys.push(key);
}
}, this);
// Convert added/removed key map to added/removed arrays
var removed = [];
var added = [];
for (var key in keyMap) {
if (keyMap[key] < 0) {
this.removeKey(key);
removed.push(key);
}
// Added keys
var added = [];
for (j=0; j<s.addedCount; j++) {
o = this.userArray[s.index + j];
key = this.add(o);
if (keyMap[key] > 0) {
added.push(key);
}
// Record splice
keySplices.push({
index: s.index,
removed: removed,
removedItems: s.removed,
added: added
});
}
return keySplices;
return [{
removed: removed,
added: added
}];
}

};
Expand Down
25 changes: 14 additions & 11 deletions src/lib/template/dom-repeat.html
Expand Up @@ -268,11 +268,13 @@
this._error(this._logf('dom-repeat', 'expected array for `items`,' +
' found', this.items));
}
this._splices = [];
this._keySplices = [];
this._indexSplices = [];
this._needFullRefresh = true;
this._debounceTemplate(this._render);
} else if (change.path == 'items.splices') {
this._splices = this._splices.concat(change.value.keySplices);
this._keySplices = this._keySplices.concat(change.value.keySplices);
this._indexSplices = this._indexSplices.concat(change.value.indexSplices);
this._debounceTemplate(this._render);
} else { // items.*
// slice off 'items.' ('items.'.length == 6)
Expand Down Expand Up @@ -303,10 +305,10 @@
},

/**
* Forces the element to render its content. Normally rendering is
* asynchronous to a provoking change. This is done for efficiency so
* that multiple changes trigger only a single render. The render method
* should be called if, for example, template rendering is required to
* Forces the element to render its content. Normally rendering is
* asynchronous to a provoking change. This is done for efficiency so
* that multiple changes trigger only a single render. The render method
* should be called if, for example, template rendering is required to
* validate application state.
*/
render: function() {
Expand All @@ -324,17 +326,18 @@
this._needFullRefresh = false;
} else {
if (this._sortFn) {
this._applySplicesUserSort(this._splices);
this._applySplicesUserSort(this._keySplices);
} else {
if (this._filterFn) {
// TODK(kschaaf): Filtering using array sort takes slow path
this._applyFullRefresh();
} else {
this._applySplicesArrayOrder(this._splices);
this._applySplicesArrayOrder(this._indexSplices);
}
}
}
this._splices = [];
this._keySplices = [];
this._indexSplices = [];
// Update final _keyToInstIdx and instance indices
var keyToIdx = this._keyToInstIdx = {};
for (var i=0; i<this._instances.length; i++) {
Expand Down Expand Up @@ -511,10 +514,10 @@
}
this._instances.splice(s.index, s.removed.length);
// Insert placeholders for new rows
for (var i=0; i<s.added.length; i++) {
for (var i=0; i<s.addedKeys.length; i++) {
var inst = {
isPlaceholder: true,
key: s.added[i]
key: s.addedKeys[i]
};
this._instances.splice(s.index + i, 0, inst);
}
Expand Down

0 comments on commit f74d072

Please sign in to comment.