diff --git a/src/lib/template/dom-repeat.html b/src/lib/template/dom-repeat.html index 63c548a328..72067e0988 100644 --- a/src/lib/template/dom-repeat.html +++ b/src/lib/template/dom-repeat.html @@ -342,9 +342,10 @@ this._debounceTemplate(this._render); }, - _observeChanged: function() { - this._observePaths = this.observe && - this.observe.replace('.*', '.').split(' '); + _observeChanged: function(observe) { + // All observed paths are handled as wildcard/deep observation. So if + // the user specifies a wildcard, we just strip it. + this._observePaths = observe && observe.replace('.*', '').split(' '); }, _itemsChanged: function(change) { @@ -366,29 +367,57 @@ this._keySplices = this._keySplices.concat(change.value.keySplices); this._indexSplices = this._indexSplices.concat(change.value.indexSplices); this._debounceTemplate(this._render); + } else if (change.path === 'items.length') { + // nothing to do } else { // items.* // slice off 'items.' ('items.'.length == 6) var subpath = change.path.slice(6); - this._forwardItemPath(subpath, change.value); - this._checkObservedPaths(subpath); + var headTail = this._splitHeadTail(subpath); + var key = headTail.head; + var path = headTail.tail; + this._forwardItemPath(key, path, change.value); + if (this._shouldResortOrFilter(key, path)) { + // TODO(kschaaf): interim solution: ideally this is just an + // incremental insertion sort of the changed item + this._needFullRefresh = true; + if (this.delay) { + this.debounce('render', this._render, this.delay); + } else { + this._debounceTemplate(this._render); + } + } } }, - _checkObservedPaths: function(path) { - if (this._observePaths) { - path = path.substring(path.indexOf('.') + 1); + _splitHeadTail: function(path) { + var dot = path.indexOf('.'); + if (dot === -1) { + return {head: path}; + } else { + var head = path.slice(0, dot); + var tail = path.slice(dot + 1); + return {head: head, tail: tail}; + } + }, + + _shouldResortOrFilter: function(key, path) { + if (!this._sortFn && !this._filterFn) { + return; + } + if (this._needFullRefresh) { + return; + } + + if (path === undefined) { + return true; + } else if (this._observePaths) { var paths = this._observePaths; for (var i=0; i. path change, // responsible for notifying item. changes to inst for key - _forwardItemPath: function(path, value) { + _forwardItemPath: function(key, path, value) { if (this._keyToInstIdx) { - var dot = path.indexOf('.'); - var key = path.substring(0, dot < 0 ? path.length : dot); var idx = this._keyToInstIdx[key]; var inst = this._instances[idx]; if (inst && !inst.isPlaceholder) { - if (dot >= 0) { - path = this.as + '.' + path.substring(dot+1); + if (path !== undefined) { + path = this.as + '.' + path; inst._notifyPath(path, value, true); } else { inst.__setProperty(this.as, value, true); diff --git a/test/unit/dom-repeat.html b/test/unit/dom-repeat.html index be42bb7d19..e5fd7e8e32 100644 --- a/test/unit/dom-repeat.html +++ b/test/unit/dom-repeat.html @@ -3252,6 +3252,52 @@

x-repeat-chunked

}); }); + suite('re-trigger sort or filter', function() { + + var repeater; + + setup(function() { + var el = document.createElement('x-primitive-large'); + repeater = el.$.repeater; + repeater.sort = function() {}; + repeater.filter = function() {}; + repeater.render(); + }); + + test('no observe set', function() { + assert.isTrue(repeater._shouldResortOrFilter('#2')); + assert.notOk(repeater._shouldResortOrFilter('#1', 'subproperty')); + }); + + test('observe property', function() { + repeater.observe = 'foo.bar'; + + assert.isTrue(repeater._shouldResortOrFilter('#2')); + assert.isTrue(repeater._shouldResortOrFilter('#2', 'foo')); + assert.isTrue(repeater._shouldResortOrFilter('#2', 'foo.bar')); + assert.isTrue(repeater._shouldResortOrFilter('#2', 'foo.bar.baz')); + + assert.notOk(repeater._shouldResortOrFilter('#2', 'foobar')); + assert.notOk(repeater._shouldResortOrFilter('#2', 'foo.bars')); + assert.notOk(repeater._shouldResortOrFilter('#2', 'foo.baz')); + assert.notOk(repeater._shouldResortOrFilter('#1', 'subproperty')); + }); + + test('observe deep property', function() { + repeater.observe = 'foo.bar.*'; + + assert.isTrue(repeater._shouldResortOrFilter('#2')); + assert.isTrue(repeater._shouldResortOrFilter('#2', 'foo')); + assert.isTrue(repeater._shouldResortOrFilter('#2', 'foo.bar')); + assert.isTrue(repeater._shouldResortOrFilter('#2', 'foo.bar.baz')); + + assert.notOk(repeater._shouldResortOrFilter('#2', 'foobar')); + assert.notOk(repeater._shouldResortOrFilter('#2', 'foo.bars')); + assert.notOk(repeater._shouldResortOrFilter('#2', 'foo.baz')); + assert.notOk(repeater._shouldResortOrFilter('#1', 'subproperty')); + }); + }); + suite('repeater API', function() { test('modelForElement', function() {