diff --git a/README.md b/README.md index 0094315c..a591c933 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ # aurelia-templating [![npm Version](https://img.shields.io/npm/v/aurelia-templating.svg)](https://www.npmjs.com/package/aurelia-templating) +[![ZenHub](https://raw.githubusercontent.com/ZenHubIO/support/master/zenhub-badge.png)](https://zenhub.io) [![Join the chat at https://gitter.im/aurelia/discuss](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/aurelia/discuss?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![CircleCI](https://circleci.com/gh/aurelia/templating.svg?style=shield)](https://circleci.com/gh/aurelia/templating) This library is part of the [Aurelia](http://www.aurelia.io/) platform and contains an extensible HTML templating engine supporting databinding, custom elements, attached behaviors and more. -> To keep up to date on [Aurelia](http://www.aurelia.io/), please visit and subscribe to [the official blog](http://blog.aurelia.io/) and [our email list](http://eepurl.com/ces50j). We also invite you to [follow us on twitter](https://twitter.com/aureliaeffect). If you have questions look around our [Discourse forums](https://discourse.aurelia.io/), chat in our [community on Gitter](https://gitter.im/aurelia/discuss) or use [stack overflow](http://stackoverflow.com/search?q=aurelia). Documentation can be found [in our developer hub](http://aurelia.io/docs). +> To keep up to date on [Aurelia](http://www.aurelia.io/), please visit and subscribe to [the official blog](http://blog.aurelia.io/) and [our email list](http://eepurl.com/ces50j). We also invite you to [follow us on twitter](https://twitter.com/aureliaeffect). If you have questions look around our [Discourse forums](https://discourse.aurelia.io/), chat in our [community on Gitter](https://gitter.im/aurelia/discuss) or use [stack overflow](http://stackoverflow.com/search?q=aurelia). Documentation can be found [in our developer hub](http://aurelia.io/docs). If you would like to have deeper insight into our development process, please install the [ZenHub](https://zenhub.io) Chrome or Firefox Extension and visit any of our repository's boards. ## Platform Support diff --git a/core.585.!opt!google!chrome!chrome b/core.585.!opt!google!chrome!chrome new file mode 100644 index 00000000..80c21207 Binary files /dev/null and b/core.585.!opt!google!chrome!chrome differ diff --git a/core.631.!opt!google!chrome!chrome b/core.631.!opt!google!chrome!chrome new file mode 100644 index 00000000..47b2a8d9 Binary files /dev/null and b/core.631.!opt!google!chrome!chrome differ diff --git a/core.634.!opt!google!chrome!chrome b/core.634.!opt!google!chrome!chrome new file mode 100644 index 00000000..d3912c14 Binary files /dev/null and b/core.634.!opt!google!chrome!chrome differ diff --git a/dist/amd/aurelia-templating.js b/dist/amd/aurelia-templating.js index 1c3ad57f..5e16a1a6 100644 --- a/dist/amd/aurelia-templating.js +++ b/dist/amd/aurelia-templating.js @@ -4616,6 +4616,7 @@ define(['exports', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aureli function onChildChange(mutations, observer) { var binders = observer.binders; var bindersLength = binders.length; + var groupedMutations = new Map(); for (var _i10 = 0, _ii9 = mutations.length; _i10 < _ii9; ++_i10) { @@ -4628,6 +4629,7 @@ define(['exports', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aureli if (_node.nodeType === 1) { for (var k = 0; k < bindersLength; ++k) { var binder = binders[k]; + if (binder.onRemove(_node)) { trackMutation(groupedMutations, binder, record); } @@ -4640,6 +4642,7 @@ define(['exports', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aureli if (_node2.nodeType === 1) { for (var _k = 0; _k < bindersLength; ++_k) { var _binder = binders[_k]; + if (_binder.onAdd(_node2)) { trackMutation(groupedMutations, _binder, record); } @@ -4648,9 +4651,9 @@ define(['exports', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aureli } } - groupedMutations.forEach(function (value, key) { - if (key.changeHandler !== null) { - key.viewModel[key.changeHandler](value); + groupedMutations.forEach(function (mutationRecords, binder) { + if (binder.isBound && binder.changeHandler !== null) { + binder.viewModel[binder.changeHandler](mutationRecords); } }); } @@ -4660,6 +4663,7 @@ define(['exports', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aureli this.selector = selector; + this.viewHost = viewHost; this.property = property; this.viewModel = viewModel; @@ -4673,6 +4677,8 @@ define(['exports', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aureli } else { this.contentView = null; } + this.source = null; + this.isBound = false; } ChildObserverBinder.prototype.matches = function matches(element) { @@ -4703,6 +4709,14 @@ define(['exports', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aureli }; ChildObserverBinder.prototype.bind = function bind(source) { + if (this.isBound) { + if (this.source === source) { + return; + } + this.source = source; + } + this.isBound = true; + var viewHost = this.viewHost; var viewModel = this.viewModel; var observer = viewHost.__childObserver__; @@ -4777,7 +4791,14 @@ define(['exports', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aureli return true; } - return false; + var currentValue = this.viewModel[this.property]; + if (currentValue === _value2) { + this.viewModel[this.property] = null; + + if (this.isBound && this.changeHandler !== null) { + this.viewModel[this.changeHandler](_value2); + } + } } return false; @@ -4812,7 +4833,7 @@ define(['exports', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aureli this.viewModel[this.property] = _value3; - if (this.changeHandler !== null) { + if (this.isBound && this.changeHandler !== null) { this.viewModel[this.changeHandler](_value3); } } @@ -4821,10 +4842,28 @@ define(['exports', 'aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aureli }; ChildObserverBinder.prototype.unbind = function unbind() { - if (this.viewHost.__childObserver__) { - this.viewHost.__childObserver__.disconnect(); - this.viewHost.__childObserver__ = null; - this.viewModel[this.property] = null; + if (!this.isBound) { + return; + } + this.isBound = false; + this.source = null; + var childObserver = this.viewHost.__childObserver__; + if (childObserver) { + var binders = childObserver.binders; + if (binders && binders.length) { + var idx = binders.indexOf(this); + if (idx !== -1) { + binders.splice(idx, 1); + } + if (binders.length === 0) { + childObserver.disconnect(); + this.viewHost.__childObserver__ = null; + } + } + + if (this.usesShadowDOM) { + this.viewModel[this.property] = null; + } } }; diff --git a/dist/aurelia-templating.js b/dist/aurelia-templating.js index 92002867..30a23fc4 100644 --- a/dist/aurelia-templating.js +++ b/dist/aurelia-templating.js @@ -5881,6 +5881,25 @@ export function child(selectorOrConfig: string | Object): any { return createChildObserverDecorator(selectorOrConfig, false); } +/** + * @internal + * @typedef MutationObserverBinder + * @property {ChildObserverBinder[]} binders + * + * @internal + * @typedef {MutationObserverBinder & MutationObserver} BindableMutationObserver + * + * @internal + * @typedef HasChildObserver + * @property {BindableMutationObserver} __childObserver__ + * + * @internal + * @typedef {Element & HasChildObserver} BindableMutationObserverHost + */ + +/** + * Child observer binder factory + */ class ChildObserver { constructor(config) { this.name = config.name; @@ -5896,6 +5915,11 @@ class ChildObserver { const noMutations = []; +/** + * @param {Map} groupedMutations + * @param {ChildObserverBinder} binder + * @param {MutationRecord} record + */ function trackMutation(groupedMutations, binder, record) { let mutations = groupedMutations.get(binder); @@ -5907,9 +5931,14 @@ function trackMutation(groupedMutations, binder, record) { mutations.push(record); } +/** + * @param {MutationRecord[]} mutations + * @param {BindableMutationObserver} observer + */ function onChildChange(mutations, observer) { let binders = observer.binders; let bindersLength = binders.length; + /**@type {Map} */ let groupedMutations = new Map(); for (let i = 0, ii = mutations.length; i < ii; ++i) { @@ -5922,6 +5951,9 @@ function onChildChange(mutations, observer) { if (node.nodeType === 1) { for (let k = 0; k < bindersLength; ++k) { let binder = binders[k]; + // only track mutation when binder signals so + // for @children scenarios where it should only call change handler + // after retrieving all value of the children if (binder.onRemove(node)) { trackMutation(groupedMutations, binder, record); } @@ -5934,6 +5966,9 @@ function onChildChange(mutations, observer) { if (node.nodeType === 1) { for (let k = 0; k < bindersLength; ++k) { let binder = binders[k]; + // only track mutation when binder signals so + // for @children scenarios where it should only call change handler + // after retrieving all value of the children if (binder.onAdd(node)) { trackMutation(groupedMutations, binder, record); } @@ -5942,16 +5977,32 @@ function onChildChange(mutations, observer) { } } - groupedMutations.forEach((value, key) => { - if (key.changeHandler !== null) { - key.viewModel[key.changeHandler](value); + groupedMutations.forEach((mutationRecords, binder) => { + if (binder.isBound && binder.changeHandler !== null) { + // invoking with mutation records as new value doesn't make it very useful, + // and kind of error prone. + // Probably should change it to the value array + // though it is a breaking change. Consider changing this + binder.viewModel[binder.changeHandler](mutationRecords); } }); } class ChildObserverBinder { + /** + * @param {string} selector the CSS selector used to filter the content of a host + * @param {Element} viewHost the host where this observer belongs to + * @param {string} property the property name of the view model where the aggregated result of this observer should assign to + * @param {object} viewModel the view model that this observer is associated with + * @param {Controller} controller the corresponding Controller of the view model + * @param {string} changeHandler the name of the change handler to invoke when the content of the view host change + * @param {boolean} all indicates whether it should try to match all children of the view host or not + */ constructor(selector, viewHost, property, viewModel, controller, changeHandler, all) { this.selector = selector; + /** + * @type {Element & HasChildObserver} + */ this.viewHost = viewHost; this.property = property; this.viewModel = viewModel; @@ -5965,6 +6016,8 @@ class ChildObserverBinder { } else { this.contentView = null; } + this.source = null; + this.isBound = false; } matches(element) { @@ -5995,6 +6048,14 @@ class ChildObserverBinder { } bind(source) { + if (this.isBound) { + if (this.source === source) { + return; + } + this.source = source; + } + this.isBound = true; + let viewHost = this.viewHost; let viewModel = this.viewModel; let observer = viewHost.__childObserver__; @@ -6060,6 +6121,10 @@ class ChildObserverBinder { if (this.matches(element)) { let value = element.au && element.au.controller ? element.au.controller.viewModel : element; + // for @children scenario + // when it is selecting all child element + // the callback needs to happen AFTER mapping all of the child value + // so returning true as a mean to register a value to be added later if (this.all) { let items = (this.viewModel[this.property] || (this.viewModel[this.property] = [])); let index = items.indexOf(value); @@ -6071,7 +6136,17 @@ class ChildObserverBinder { return true; } - return false; + // for @child scenario + const currentValue = this.viewModel[this.property]; + if (currentValue === value) { + this.viewModel[this.property] = null; + + // when it is a single child observation + // it is safe to trigger change handler immediately + if (this.isBound && this.changeHandler !== null) { + this.viewModel[this.changeHandler](value); + } + } } return false; @@ -6081,6 +6156,10 @@ class ChildObserverBinder { if (this.matches(element)) { let value = element.au && element.au.controller ? element.au.controller.viewModel : element; + // for @children scenario + // when it is selecting all child element + // the callback needs to happen AFTER mapping all of the child value + // so returning true as a mean to register a value to be added later if (this.all) { let items = (this.viewModel[this.property] || (this.viewModel[this.property] = [])); @@ -6104,9 +6183,16 @@ class ChildObserverBinder { return true; } + // for @child scenario + // in multiple child scenario + // it will keep reassigning value to the property + // until the last matched element + // this is unexpected but not easy to determine otherwise this.viewModel[this.property] = value; - if (this.changeHandler !== null) { + // when it is a single child observation + // it is safe to trigger change handler immediately + if (this.isBound && this.changeHandler !== null) { this.viewModel[this.changeHandler](value); } } @@ -6115,10 +6201,29 @@ class ChildObserverBinder { } unbind() { - if (this.viewHost.__childObserver__) { - this.viewHost.__childObserver__.disconnect(); - this.viewHost.__childObserver__ = null; - this.viewModel[this.property] = null; + if (!this.isBound) { + return; + } + this.isBound = false; + this.source = null; + let childObserver = this.viewHost.__childObserver__; + if (childObserver) { + let binders = childObserver.binders; + if (binders && binders.length) { + let idx = binders.indexOf(this); + if (idx !== -1) { + binders.splice(idx, 1); + } + if (binders.length === 0) { + childObserver.disconnect(); + this.viewHost.__childObserver__ = null; + } + } + // when using shadowDOM, the bound property is populated during bind + // so it's safe to unassign it + if (this.usesShadowDOM) { + this.viewModel[this.property] = null; + } } } } diff --git a/dist/commonjs/aurelia-templating.js b/dist/commonjs/aurelia-templating.js index 81ae5059..8e98e422 100644 --- a/dist/commonjs/aurelia-templating.js +++ b/dist/commonjs/aurelia-templating.js @@ -4597,6 +4597,7 @@ function trackMutation(groupedMutations, binder, record) { function onChildChange(mutations, observer) { var binders = observer.binders; var bindersLength = binders.length; + var groupedMutations = new Map(); for (var _i10 = 0, _ii9 = mutations.length; _i10 < _ii9; ++_i10) { @@ -4609,6 +4610,7 @@ function onChildChange(mutations, observer) { if (_node.nodeType === 1) { for (var k = 0; k < bindersLength; ++k) { var binder = binders[k]; + if (binder.onRemove(_node)) { trackMutation(groupedMutations, binder, record); } @@ -4621,6 +4623,7 @@ function onChildChange(mutations, observer) { if (_node2.nodeType === 1) { for (var _k = 0; _k < bindersLength; ++_k) { var _binder = binders[_k]; + if (_binder.onAdd(_node2)) { trackMutation(groupedMutations, _binder, record); } @@ -4629,9 +4632,9 @@ function onChildChange(mutations, observer) { } } - groupedMutations.forEach(function (value, key) { - if (key.changeHandler !== null) { - key.viewModel[key.changeHandler](value); + groupedMutations.forEach(function (mutationRecords, binder) { + if (binder.isBound && binder.changeHandler !== null) { + binder.viewModel[binder.changeHandler](mutationRecords); } }); } @@ -4641,6 +4644,7 @@ var ChildObserverBinder = function () { this.selector = selector; + this.viewHost = viewHost; this.property = property; this.viewModel = viewModel; @@ -4654,6 +4658,8 @@ var ChildObserverBinder = function () { } else { this.contentView = null; } + this.source = null; + this.isBound = false; } ChildObserverBinder.prototype.matches = function matches(element) { @@ -4684,6 +4690,14 @@ var ChildObserverBinder = function () { }; ChildObserverBinder.prototype.bind = function bind(source) { + if (this.isBound) { + if (this.source === source) { + return; + } + this.source = source; + } + this.isBound = true; + var viewHost = this.viewHost; var viewModel = this.viewModel; var observer = viewHost.__childObserver__; @@ -4758,7 +4772,14 @@ var ChildObserverBinder = function () { return true; } - return false; + var currentValue = this.viewModel[this.property]; + if (currentValue === _value2) { + this.viewModel[this.property] = null; + + if (this.isBound && this.changeHandler !== null) { + this.viewModel[this.changeHandler](_value2); + } + } } return false; @@ -4793,7 +4814,7 @@ var ChildObserverBinder = function () { this.viewModel[this.property] = _value3; - if (this.changeHandler !== null) { + if (this.isBound && this.changeHandler !== null) { this.viewModel[this.changeHandler](_value3); } } @@ -4802,10 +4823,28 @@ var ChildObserverBinder = function () { }; ChildObserverBinder.prototype.unbind = function unbind() { - if (this.viewHost.__childObserver__) { - this.viewHost.__childObserver__.disconnect(); - this.viewHost.__childObserver__ = null; - this.viewModel[this.property] = null; + if (!this.isBound) { + return; + } + this.isBound = false; + this.source = null; + var childObserver = this.viewHost.__childObserver__; + if (childObserver) { + var binders = childObserver.binders; + if (binders && binders.length) { + var idx = binders.indexOf(this); + if (idx !== -1) { + binders.splice(idx, 1); + } + if (binders.length === 0) { + childObserver.disconnect(); + this.viewHost.__childObserver__ = null; + } + } + + if (this.usesShadowDOM) { + this.viewModel[this.property] = null; + } } }; diff --git a/dist/es2015/aurelia-templating.js b/dist/es2015/aurelia-templating.js index efd98065..cd6aa313 100644 --- a/dist/es2015/aurelia-templating.js +++ b/dist/es2015/aurelia-templating.js @@ -4274,6 +4274,7 @@ function trackMutation(groupedMutations, binder, record) { function onChildChange(mutations, observer) { let binders = observer.binders; let bindersLength = binders.length; + let groupedMutations = new Map(); for (let i = 0, ii = mutations.length; i < ii; ++i) { @@ -4286,6 +4287,7 @@ function onChildChange(mutations, observer) { if (node.nodeType === 1) { for (let k = 0; k < bindersLength; ++k) { let binder = binders[k]; + if (binder.onRemove(node)) { trackMutation(groupedMutations, binder, record); } @@ -4298,6 +4300,7 @@ function onChildChange(mutations, observer) { if (node.nodeType === 1) { for (let k = 0; k < bindersLength; ++k) { let binder = binders[k]; + if (binder.onAdd(node)) { trackMutation(groupedMutations, binder, record); } @@ -4306,9 +4309,9 @@ function onChildChange(mutations, observer) { } } - groupedMutations.forEach((value, key) => { - if (key.changeHandler !== null) { - key.viewModel[key.changeHandler](value); + groupedMutations.forEach((mutationRecords, binder) => { + if (binder.isBound && binder.changeHandler !== null) { + binder.viewModel[binder.changeHandler](mutationRecords); } }); } @@ -4316,6 +4319,7 @@ function onChildChange(mutations, observer) { let ChildObserverBinder = class ChildObserverBinder { constructor(selector, viewHost, property, viewModel, controller, changeHandler, all) { this.selector = selector; + this.viewHost = viewHost; this.property = property; this.viewModel = viewModel; @@ -4329,6 +4333,8 @@ let ChildObserverBinder = class ChildObserverBinder { } else { this.contentView = null; } + this.source = null; + this.isBound = false; } matches(element) { @@ -4359,6 +4365,14 @@ let ChildObserverBinder = class ChildObserverBinder { } bind(source) { + if (this.isBound) { + if (this.source === source) { + return; + } + this.source = source; + } + this.isBound = true; + let viewHost = this.viewHost; let viewModel = this.viewModel; let observer = viewHost.__childObserver__; @@ -4433,7 +4447,14 @@ let ChildObserverBinder = class ChildObserverBinder { return true; } - return false; + const currentValue = this.viewModel[this.property]; + if (currentValue === value) { + this.viewModel[this.property] = null; + + if (this.isBound && this.changeHandler !== null) { + this.viewModel[this.changeHandler](value); + } + } } return false; @@ -4468,7 +4489,7 @@ let ChildObserverBinder = class ChildObserverBinder { this.viewModel[this.property] = value; - if (this.changeHandler !== null) { + if (this.isBound && this.changeHandler !== null) { this.viewModel[this.changeHandler](value); } } @@ -4477,10 +4498,28 @@ let ChildObserverBinder = class ChildObserverBinder { } unbind() { - if (this.viewHost.__childObserver__) { - this.viewHost.__childObserver__.disconnect(); - this.viewHost.__childObserver__ = null; - this.viewModel[this.property] = null; + if (!this.isBound) { + return; + } + this.isBound = false; + this.source = null; + let childObserver = this.viewHost.__childObserver__; + if (childObserver) { + let binders = childObserver.binders; + if (binders && binders.length) { + let idx = binders.indexOf(this); + if (idx !== -1) { + binders.splice(idx, 1); + } + if (binders.length === 0) { + childObserver.disconnect(); + this.viewHost.__childObserver__ = null; + } + } + + if (this.usesShadowDOM) { + this.viewModel[this.property] = null; + } } } }; diff --git a/dist/native-modules/aurelia-templating.js b/dist/native-modules/aurelia-templating.js index 0564c83f..8c5bc99e 100644 --- a/dist/native-modules/aurelia-templating.js +++ b/dist/native-modules/aurelia-templating.js @@ -4556,6 +4556,7 @@ function trackMutation(groupedMutations, binder, record) { function onChildChange(mutations, observer) { var binders = observer.binders; var bindersLength = binders.length; + var groupedMutations = new Map(); for (var _i10 = 0, _ii9 = mutations.length; _i10 < _ii9; ++_i10) { @@ -4568,6 +4569,7 @@ function onChildChange(mutations, observer) { if (_node.nodeType === 1) { for (var k = 0; k < bindersLength; ++k) { var binder = binders[k]; + if (binder.onRemove(_node)) { trackMutation(groupedMutations, binder, record); } @@ -4580,6 +4582,7 @@ function onChildChange(mutations, observer) { if (_node2.nodeType === 1) { for (var _k = 0; _k < bindersLength; ++_k) { var _binder = binders[_k]; + if (_binder.onAdd(_node2)) { trackMutation(groupedMutations, _binder, record); } @@ -4588,9 +4591,9 @@ function onChildChange(mutations, observer) { } } - groupedMutations.forEach(function (value, key) { - if (key.changeHandler !== null) { - key.viewModel[key.changeHandler](value); + groupedMutations.forEach(function (mutationRecords, binder) { + if (binder.isBound && binder.changeHandler !== null) { + binder.viewModel[binder.changeHandler](mutationRecords); } }); } @@ -4600,6 +4603,7 @@ var ChildObserverBinder = function () { this.selector = selector; + this.viewHost = viewHost; this.property = property; this.viewModel = viewModel; @@ -4613,6 +4617,8 @@ var ChildObserverBinder = function () { } else { this.contentView = null; } + this.source = null; + this.isBound = false; } ChildObserverBinder.prototype.matches = function matches(element) { @@ -4643,6 +4649,14 @@ var ChildObserverBinder = function () { }; ChildObserverBinder.prototype.bind = function bind(source) { + if (this.isBound) { + if (this.source === source) { + return; + } + this.source = source; + } + this.isBound = true; + var viewHost = this.viewHost; var viewModel = this.viewModel; var observer = viewHost.__childObserver__; @@ -4717,7 +4731,14 @@ var ChildObserverBinder = function () { return true; } - return false; + var currentValue = this.viewModel[this.property]; + if (currentValue === _value2) { + this.viewModel[this.property] = null; + + if (this.isBound && this.changeHandler !== null) { + this.viewModel[this.changeHandler](_value2); + } + } } return false; @@ -4752,7 +4773,7 @@ var ChildObserverBinder = function () { this.viewModel[this.property] = _value3; - if (this.changeHandler !== null) { + if (this.isBound && this.changeHandler !== null) { this.viewModel[this.changeHandler](_value3); } } @@ -4761,10 +4782,28 @@ var ChildObserverBinder = function () { }; ChildObserverBinder.prototype.unbind = function unbind() { - if (this.viewHost.__childObserver__) { - this.viewHost.__childObserver__.disconnect(); - this.viewHost.__childObserver__ = null; - this.viewModel[this.property] = null; + if (!this.isBound) { + return; + } + this.isBound = false; + this.source = null; + var childObserver = this.viewHost.__childObserver__; + if (childObserver) { + var binders = childObserver.binders; + if (binders && binders.length) { + var idx = binders.indexOf(this); + if (idx !== -1) { + binders.splice(idx, 1); + } + if (binders.length === 0) { + childObserver.disconnect(); + this.viewHost.__childObserver__ = null; + } + } + + if (this.usesShadowDOM) { + this.viewModel[this.property] = null; + } } }; diff --git a/dist/system/aurelia-templating.js b/dist/system/aurelia-templating.js index 6bc49169..5d56fa51 100644 --- a/dist/system/aurelia-templating.js +++ b/dist/system/aurelia-templating.js @@ -457,6 +457,7 @@ System.register(['aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aurelia- function onChildChange(mutations, observer) { var binders = observer.binders; var bindersLength = binders.length; + var groupedMutations = new Map(); for (var _i10 = 0, _ii9 = mutations.length; _i10 < _ii9; ++_i10) { @@ -469,6 +470,7 @@ System.register(['aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aurelia- if (_node.nodeType === 1) { for (var k = 0; k < bindersLength; ++k) { var binder = binders[k]; + if (binder.onRemove(_node)) { trackMutation(groupedMutations, binder, record); } @@ -481,6 +483,7 @@ System.register(['aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aurelia- if (_node2.nodeType === 1) { for (var _k = 0; _k < bindersLength; ++_k) { var _binder = binders[_k]; + if (_binder.onAdd(_node2)) { trackMutation(groupedMutations, _binder, record); } @@ -489,9 +492,9 @@ System.register(['aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aurelia- } } - groupedMutations.forEach(function (value, key) { - if (key.changeHandler !== null) { - key.viewModel[key.changeHandler](value); + groupedMutations.forEach(function (mutationRecords, binder) { + if (binder.isBound && binder.changeHandler !== null) { + binder.viewModel[binder.changeHandler](mutationRecords); } }); } @@ -4980,6 +4983,7 @@ System.register(['aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aurelia- this.selector = selector; + this.viewHost = viewHost; this.property = property; this.viewModel = viewModel; @@ -4993,6 +4997,8 @@ System.register(['aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aurelia- } else { this.contentView = null; } + this.source = null; + this.isBound = false; } ChildObserverBinder.prototype.matches = function matches(element) { @@ -5023,6 +5029,14 @@ System.register(['aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aurelia- }; ChildObserverBinder.prototype.bind = function bind(source) { + if (this.isBound) { + if (this.source === source) { + return; + } + this.source = source; + } + this.isBound = true; + var viewHost = this.viewHost; var viewModel = this.viewModel; var observer = viewHost.__childObserver__; @@ -5097,7 +5111,14 @@ System.register(['aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aurelia- return true; } - return false; + var currentValue = this.viewModel[this.property]; + if (currentValue === _value2) { + this.viewModel[this.property] = null; + + if (this.isBound && this.changeHandler !== null) { + this.viewModel[this.changeHandler](_value2); + } + } } return false; @@ -5132,7 +5153,7 @@ System.register(['aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aurelia- this.viewModel[this.property] = _value3; - if (this.changeHandler !== null) { + if (this.isBound && this.changeHandler !== null) { this.viewModel[this.changeHandler](_value3); } } @@ -5141,10 +5162,28 @@ System.register(['aurelia-logging', 'aurelia-metadata', 'aurelia-pal', 'aurelia- }; ChildObserverBinder.prototype.unbind = function unbind() { - if (this.viewHost.__childObserver__) { - this.viewHost.__childObserver__.disconnect(); - this.viewHost.__childObserver__ = null; - this.viewModel[this.property] = null; + if (!this.isBound) { + return; + } + this.isBound = false; + this.source = null; + var childObserver = this.viewHost.__childObserver__; + if (childObserver) { + var binders = childObserver.binders; + if (binders && binders.length) { + var idx = binders.indexOf(this); + if (idx !== -1) { + binders.splice(idx, 1); + } + if (binders.length === 0) { + childObserver.disconnect(); + this.viewHost.__childObserver__ = null; + } + } + + if (this.usesShadowDOM) { + this.viewModel[this.property] = null; + } } }; diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index fd311c5c..6b52a1a3 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -1,5 +1,5 @@ -## [1.10.4](https://github.com/aurelia/templating/compare/1.10.1...1.10.4) (2020-01-28) +## [1.10.4](https://github.com/aurelia/templating/compare/1.10.1...1.10.4) (2020-05-18) ### Bug Fixes