diff --git a/src/model/LinkModel.js b/src/model/LinkModel.js index 7b521fbc58..12af8c1c24 100755 --- a/src/model/LinkModel.js +++ b/src/model/LinkModel.js @@ -156,6 +156,8 @@ export default class LinkModel extends ModelBase { c.relinking(target.joinKey(c.key), safe); }); + if (!safe) this.keypath = undefined; + if (this.rootLink) this.addShuffleTask(() => { this.relinked(); diff --git a/src/view/items/Element.js b/src/view/items/Element.js index d2f492830c..f6602884e2 100755 --- a/src/view/items/Element.js +++ b/src/view/items/Element.js @@ -6,7 +6,7 @@ import { escapeHtml, voidElements } from 'utils/html'; import { createElement, detachNode, matches, safeAttributeString } from 'utils/dom'; import runloop from 'src/global/runloop'; import Context from 'shared/Context'; -import { destroyed } from 'shared/methodCallers'; +import { destroyed, shuffled } from 'shared/methodCallers'; import { ContainerItem } from './shared/Item'; import Fragment from '../Fragment'; import ConditionalAttribute from './element/ConditionalAttribute'; @@ -380,6 +380,11 @@ export default class Element extends ContainerItem { this.rendered = true; } + shuffled() { + super.shuffled(); + this.decorators.forEach(shuffled); + } + toString() { const tagName = this.template.e; diff --git a/src/view/items/element/Decorator.js b/src/view/items/element/Decorator.js index 9c10e80477..9ac3b7bdcc 100755 --- a/src/view/items/element/Decorator.js +++ b/src/view/items/element/Decorator.js @@ -94,6 +94,10 @@ export default class Decorator { }, true); } + shuffled() { + if (this.handle && this.handle.shuffled) this.handle.shuffled(); + } + toString() { return ''; } diff --git a/src/view/resolvers/ReferenceExpressionProxy.js b/src/view/resolvers/ReferenceExpressionProxy.js index 01f8c00699..88445f29ae 100755 --- a/src/view/resolvers/ReferenceExpressionProxy.js +++ b/src/view/resolvers/ReferenceExpressionProxy.js @@ -98,6 +98,7 @@ export default class ReferenceExpressionProxy extends LinkModel { this.relinking(model); fireShuffleTasks(); refreshPathDeps(this); + this.fragment.shuffled(); } }; diff --git a/tests/browser/plugins/decorators.js b/tests/browser/plugins/decorators.js index e6a3283f9e..499a414b3d 100644 --- a/tests/browser/plugins/decorators.js +++ b/tests/browser/plugins/decorators.js @@ -739,4 +739,40 @@ export default function() { target: fixture }); }); + + test(`decorators are notified of shuffling due to reference expression changes`, t => { + t.expect(4); + + let path, child; + const r = new Ractive({ + target: fixture, + template: `{{#with foo[bar]}}
{{/with}}`, + data: { + bar: 'baz', + foo: { + baz: {}, + bat: {} + } + }, + decorators: { + check(node) { + const ctx = this.getContext(node); + path = ctx.resolve(); + child = ctx.resolve('.foo'); + return { + teardown() {}, + shuffled() { + path = ctx.resolve(); + child = ctx.resolve('.foo'); + } + }; + } + } + }); + t.equal(path, 'foo.baz'); + t.equal(child, 'foo.baz.foo'); + r.set('bar', 'bat'); + t.equal(path, 'foo.bat'); + t.equal(child, 'foo.bat.foo'); + }); }