diff --git a/src/name-expression.js b/src/name-expression.js index eb6f31ce..06d43c3d 100644 --- a/src/name-expression.js +++ b/src/name-expression.js @@ -1,3 +1,5 @@ +import { bindingMode } from './binding-mode'; + function getAU(element) { let au = element.au; @@ -43,10 +45,17 @@ export class NameExpression { } class NameBinder { + /** + * Name binding for reference + * @param {Expression} sourceExpression + * @param {any} target + * @param {any} lookupFunctions + */ constructor(sourceExpression, target, lookupFunctions) { this.sourceExpression = sourceExpression; this.target = target; this.lookupFunctions = lookupFunctions; + this.mode = bindingMode.oneTime; } bind(source) { @@ -64,16 +73,24 @@ class NameBinder { this.sourceExpression.assign(this.source, this.target, this.lookupFunctions); } + call() { + if (!this.isBound) { + return; + } + this.sourceExpression.assign(this.source, this.target, this.lookupFunctions); + } + unbind() { if (!this.isBound) { return; } this.isBound = false; - if (this.sourceExpression.evaluate(this.source, this.lookupFunctions) === this.target) { - this.sourceExpression.assign(this.source, null, this.lookupFunctions); + const { source, lookupFunctions, sourceExpression } = this; + if (sourceExpression.evaluate(source, lookupFunctions) === this.target) { + sourceExpression.assign(source, null, lookupFunctions); } - if (this.sourceExpression.unbind) { - this.sourceExpression.unbind(this, this.source); + if (sourceExpression.unbind) { + sourceExpression.unbind(this, source); } this.source = null; } diff --git a/test/name-expression.spec.js b/test/name-expression.spec.js index 43f1895b..44b8bf06 100644 --- a/test/name-expression.spec.js +++ b/test/name-expression.spec.js @@ -8,6 +8,7 @@ import { } from '../src/ast'; import {createScopeForTest} from '../src/scope'; import {NameExpression} from '../src/name-expression'; +import { bindingMode } from '../src/binding-mode'; describe('NameExpression', () => { let element; @@ -23,6 +24,13 @@ describe('NameExpression', () => { }; }); + it('creates one time binding mode binding', () => { + let sourceExpression = new AccessScope('foo'); + let expression = new NameExpression(sourceExpression, 'element'); + let binding = expression.createBinding(element); + expect(binding.mode).toBe(bindingMode.oneTime); + }); + it('binds element to scope', () => { let sourceExpression = new AccessScope('foo'); let expression = new NameExpression(sourceExpression, 'element'); @@ -104,4 +112,34 @@ describe('NameExpression', () => { binding.unbind(); expect(scope.bindingContext.foo).toBe('should remain'); }); + + it('re-assigns value when invoking call()', () => { + let sourceExpression = new AccessScope('foo'); + let expression = new NameExpression(sourceExpression, 'element'); + let scope = createScopeForTest({}); + let binding = expression.createBinding(element); + binding.bind(scope); + expect(scope.bindingContext.foo).toBe(element); + scope.bindingContext.foo = null; + expect(binding.target).toBe(element); + binding.call(); + expect(scope.bindingContext.foo).toBe(element); + }); + + it('does nothing when not bound + invoking call()', () => { + let sourceExpression = new AccessScope('foo'); + let expression = new NameExpression(sourceExpression, 'element'); + let scope = createScopeForTest({}); + let binding = expression.createBinding(element); + binding.bind(scope); + expect(scope.bindingContext.foo).toBe(element); + scope.bindingContext.foo = null; + expect(binding.target).toBe(element); + binding.isBound = false; + binding.call(); + expect(scope.bindingContext.foo).toBe(null); + binding.isBound = true; + binding.call(); + expect(scope.bindingContext.foo).toBe(element); + }); });