diff --git a/package-lock.json b/package-lock.json
index 33bf6de..98ff218 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "aurelia-templating-resources",
- "version": "1.9.1",
+ "version": "1.11.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -3504,7 +3504,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"aproba": {
"version": "1.2.0",
@@ -3525,12 +3526,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -3545,17 +3548,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -3672,7 +3678,8 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"ini": {
"version": "1.3.5",
@@ -3684,6 +3691,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -3698,6 +3706,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -3705,12 +3714,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -3729,6 +3740,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -3809,7 +3821,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -3821,6 +3834,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
@@ -3906,7 +3920,8 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -3942,6 +3957,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -3961,6 +3977,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -4004,12 +4021,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
}
}
},
diff --git a/src/compose.ts b/src/compose.ts
index db21781..e0df2a1 100644
--- a/src/compose.ts
+++ b/src/compose.ts
@@ -250,7 +250,7 @@ function processChanges(composer: Compose) {
const changes = composer.changes;
composer.changes = Object.create(null);
- if (!('view' in changes) && !('viewModel' in changes) && ('model' in changes) && composer.activationStrategy !== ActivationStrategy.Replace) {
+ if (!('view' in changes) && !('viewModel' in changes) && ('model' in changes) && determineActivationStrategy(composer) !== ActivationStrategy.Replace) {
// just try to activate the current view model
composer.pendingTask = tryActivateViewModel(composer.currentViewModel, changes.model);
if (!composer.pendingTask) { return; }
@@ -298,3 +298,12 @@ function requestUpdate(composer: Compose) {
processChanges(composer);
});
}
+
+function determineActivationStrategy(composer: Compose) {
+ let activationStrategy = composer.activationStrategy;
+ const vm = composer.currentViewModel;
+ if (vm && typeof vm.determineActivationStrategy === 'function') {
+ activationStrategy = vm.determineActivationStrategy();
+ }
+ return activationStrategy;
+}
diff --git a/test/compose.integration.spec.ts b/test/compose.integration.spec.ts
index ac67f91..eb1f9b8 100644
--- a/test/compose.integration.spec.ts
+++ b/test/compose.integration.spec.ts
@@ -1,8 +1,8 @@
import './setup';
import { StageComponent, ComponentTester } from 'aurelia-testing';
import { bootstrap } from 'aurelia-bootstrapper';
-import { Compose } from '../src/compose';
-import { InlineViewStrategy, useView } from 'aurelia-framework';
+import { Compose, ActivationStrategy } from '../src/compose';
+import { InlineViewStrategy, useView, TaskQueue } from 'aurelia-framework';
describe('compose.integration.spec.ts', () => {
@@ -81,6 +81,68 @@ describe('compose.integration.spec.ts', () => {
component.dispose();
});
+ it('works with determineActivationStrategy() - replace', async () => {
+ const { component, compose } = await bootstrapCompose(
+ ``,
+ {
+ viewModel: class {
+ // w/o the get view strategy, the initial composition fails, which results to undefined currentViewModel
+ getViewStrategy() {
+ return new InlineViewStrategy('');
+ }
+
+ determineActivationStrategy() {
+ return ActivationStrategy.Replace;
+ }
+ }
+ }
+ );
+
+ const taskQueue = new TaskQueue();
+ spyOn(compose.compositionEngine, 'compose').and.callThrough();
+ const oldModel = compose.model;
+ compose.modelChanged({ a: 1 }, oldModel);
+
+ taskQueue.queueMicroTask(() => {
+ expect(compose.compositionEngine.compose).toHaveBeenCalledTimes(1);
+ component.dispose();
+ });
+
+ });
+
+ it('works with determineActivationStrategy() - invoke-lifecycle', async () => {
+ let activationCount = 0;
+ const { component, compose } = await bootstrapCompose(
+ ``,
+ {
+ viewModel: class {
+ activate() {
+ activationCount++;
+ }
+
+ // w/o the get view strategy, the initial composition fails, which results to undefined currentViewModel
+ getViewStrategy() {
+ return new InlineViewStrategy('');
+ }
+
+ determineActivationStrategy() {
+ return ActivationStrategy.InvokeLifecycle;
+ }
+ }
+ }
+ );
+
+ const taskQueue = new TaskQueue();
+
+ const oldModel = compose.model;
+ compose.modelChanged({}, oldModel);
+
+ taskQueue.queueMicroTask(() => {
+ expect(activationCount).toBe(2, 'activation count === 2');
+ component.dispose();
+ });
+ });
+
describe('scope traversing', () => {
it('traverses scope by default', async () => {
const { component } = await bootstrapCompose(
diff --git a/test/compose.spec.ts b/test/compose.spec.ts
index 3de590c..3d90b04 100644
--- a/test/compose.spec.ts
+++ b/test/compose.spec.ts
@@ -167,6 +167,19 @@ describe('Compose', () => {
done();
});
});
+
+ it('when "model" changes and the "determineActivationStrategy" hook in view-model returns "replace"', done => {
+ const model = {};
+ sut.currentViewModel = {
+ determineActivationStrategy() { return ActivationStrategy.Replace; }
+ };
+ updateBindable('model', model);
+ taskQueue.queueMicroTask(() => {
+ expect(compositionEngineMock.compose).toHaveBeenCalledTimes(1);
+ expect(compositionEngineMock.compose).toHaveBeenCalledWith(jasmine.objectContaining({ model }));
+ done();
+ });
+ });
});
describe('does not trigger composition', () => {
@@ -178,6 +191,28 @@ describe('Compose', () => {
done();
});
});
+
+ it('when "model" changes and the "determineActivationStrategy" hook in view-model returns "invoke-lifecycle"', done => {
+ const model = {};
+ sut.currentViewModel = {
+ determineActivationStrategy() { return ActivationStrategy.InvokeLifecycle; }
+ };
+ updateBindable('model', model);
+ taskQueue.queueMicroTask(() => {
+ expect(compositionEngineMock.compose).not.toHaveBeenCalled();
+ done();
+ });
+ });
+
+ it('when "model" changes and the "determineActivationStrategy" hook is not implemented in view-model', done => {
+ const model = {};
+ sut.currentViewModel = {};
+ updateBindable('model', model);
+ taskQueue.queueMicroTask(() => {
+ expect(compositionEngineMock.compose).not.toHaveBeenCalled();
+ done();
+ });
+ });
});
it('aggregates changes from single drain of the micro task queue', done => {