From b99ef2b80a5490a3fc79c2555f024c1d79f8f519 Mon Sep 17 00:00:00 2001 From: JoostK Date: Sun, 13 May 2018 21:01:37 +0200 Subject: [PATCH] refactor(ivy): simplify bind instruction to reuse bindingUpdated logic (#23881) Added runtime and compiler testcases for interpolated bindings, which verify that NO_CHANGE is properly handled in `bind`. PR Close #23881 --- packages/core/src/render3/instructions.ts | 19 ++-------- .../core/test/render3/instructions_spec.ts | 37 +++++++++++++++++++ packages/core/test/render3/render_util.ts | 6 +-- 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index c577aa5200..523c605a68 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -1266,7 +1266,7 @@ export function text(index: number, value?: any): void { /** * Create text node with binding - * Bindings should be handled externally with the proper bind(1-8) method + * Bindings should be handled externally with the proper interpolation(1-8) method * * @param index Index of the node in the data array. * @param value Stringified value to write. @@ -2151,21 +2151,8 @@ function initBindings() { * * @param value Value to diff */ -export function bind(value: T | NO_CHANGE): T|NO_CHANGE { - if (currentView.bindingStartIndex < 0) { - initBindings(); - return data[currentView.bindingIndex++] = value; - } - - const changed: boolean = - value !== NO_CHANGE && isDifferent(data[currentView.bindingIndex], value); - if (changed) { - throwErrorIfNoChangesMode( - creationMode, checkNoChangesMode, data[currentView.bindingIndex], value); - data[currentView.bindingIndex] = value; - } - currentView.bindingIndex++; - return changed ? value : NO_CHANGE; +export function bind(value: T): T|NO_CHANGE { + return bindingUpdated(value) ? value : NO_CHANGE; } /** diff --git a/packages/core/test/render3/instructions_spec.ts b/packages/core/test/render3/instructions_spec.ts index 43a0de4031..7a59ec8834 100644 --- a/packages/core/test/render3/instructions_spec.ts +++ b/packages/core/test/render3/instructions_spec.ts @@ -35,6 +35,43 @@ describe('instructions', () => { elementEnd(); } + describe('bind', () => { + it('should update bindings when value changes', () => { + const t = new TemplateFixture(createAnchor); + + t.update(() => elementProperty(0, 'title', bind('Hello'))); + expect(t.html).toEqual(''); + + t.update(() => elementProperty(0, 'title', bind('World'))); + expect(t.html).toEqual(''); + expect(ngDevMode).toHaveProperties({ + firstTemplatePass: 1, + tNode: 2, // 1 for hostElement + 1 for the template under test + tView: 1, + rendererCreateElement: 1, + rendererSetProperty: 2 + }); + }); + + it('should not update bindings when value does not change', () => { + const idempotentUpdate = () => elementProperty(0, 'title', bind('Hello')); + const t = new TemplateFixture(createAnchor, idempotentUpdate); + + t.update(); + expect(t.html).toEqual(''); + + t.update(); + expect(t.html).toEqual(''); + expect(ngDevMode).toHaveProperties({ + firstTemplatePass: 1, + tNode: 2, // 1 for hostElement + 1 for the template under test + tView: 1, + rendererCreateElement: 1, + rendererSetProperty: 1 + }); + }); + }); + describe('elementAttribute', () => { it('should use sanitizer function', () => { const t = new TemplateFixture(createDiv); diff --git a/packages/core/test/render3/render_util.ts b/packages/core/test/render3/render_util.ts index 7bb954e2cd..2486905eae 100644 --- a/packages/core/test/render3/render_util.ts +++ b/packages/core/test/render3/render_util.ts @@ -58,9 +58,9 @@ export class TemplateFixture extends BaseFixture { /** * * @param createBlock Instructions which go into the creation block: - * `if (creationMode) { __here__ }`. - * @param updateBlock Optional instructions which go after the creation block: - * `if (creationMode) { ... } __here__`. + * `if (rf & RenderFlags.Create) { __here__ }`. + * @param updateBlock Optional instructions which go into the update block: + * `if (rf & RenderFlags.Update) { __here__ }`. */ constructor( private createBlock: () => void, private updateBlock: () => void = noop,