Skip to content

Commit

Permalink
Merge pull request #325 from fragsalat/else-fix
Browse files Browse the repository at this point in the history
fix(if-else): Fixed missing binding context when rendering else block
  • Loading branch information
EisenbergEffect authored Oct 24, 2017
2 parents bfd1382 + 2103aca commit 31798f5
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 5 deletions.
12 changes: 10 additions & 2 deletions src/else.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ export class Else extends IfCore {
this._registerInIf();
}

bind(bindingContext, overrideContext) {
super.bind(bindingContext, overrideContext);
// Render on initial
if (!this.ifVm.condition) {
this._show();
}
}

_registerInIf() {
// We support the pattern <div if.bind="x"></div><div else></div>.
// Obvisouly between the two, we must accepts text (spaces) and comments.
Expand All @@ -24,7 +32,7 @@ export class Else extends IfCore {
if (!previous || !previous.au.if) {
throw new Error("Can't find matching If for Else custom attribute.");
}
let ifVm = previous.au.if.viewModel;
ifVm.else = this;
this.ifVm = previous.au.if.viewModel;
this.ifVm.elseVm = this;
}
}
8 changes: 5 additions & 3 deletions src/if.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ export class If extends IfCore {
*/
bind(bindingContext, overrideContext) {
super.bind(bindingContext, overrideContext);
this.conditionChanged(this.condition);
if (this.condition) {
this._show();
}
}

/**
Expand All @@ -37,8 +39,8 @@ export class If extends IfCore {
}

let promise;
if (this.else) {
promise = show ? this._swap(this.else, this) : this._swap(this, this.else);
if (this.elseVm) {
promise = show ? this._swap(this.elseVm, this) : this._swap(this, this.elseVm);
} else {
promise = show ? this._show() : this._hide();
}
Expand Down
139 changes: 139 additions & 0 deletions test/else.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import './setup';
import {ViewSlot} from 'aurelia-templating';
import {If} from '../src/if';
import {Else} from '../src/else';

class ViewMock {
bind() {}
unbind() {}
}

describe('else', () => {
let ifViewSlot, elseViewSlot, ifVm, elseVm, viewFactory;

beforeEach(() => {
const fragment = document.createDocumentFragment();
const ifNode = document.createElement('div');
const elseNode = document.createElement('div');
fragment.appendChild(ifNode);
fragment.appendChild(elseNode);
ifViewSlot = new ViewSlot(ifNode, true);
elseViewSlot = new ViewSlot(elseNode, true);
ifVm = new If(viewFactory, ifViewSlot);
ifVm.view = new ViewMock();
ifNode.au = {if: {viewModel: ifVm}};

elseVm = new Else(viewFactory, elseViewSlot);
elseVm.view = new ViewMock();
});

it('should render when initial condition is false', () => {
ifVm.showing = false;
elseVm.showing = false;

spyOn(ifViewSlot, 'add');
spyOn(ifVm.view, 'bind');
spyOn(elseViewSlot, 'add');
spyOn(elseVm.view, 'bind');

ifVm.condition = false;
ifVm.bind();
elseVm.bind();
// Else should be shown now
expect(ifVm.showing).toBeFalsy();
expect(ifViewSlot.add).not.toHaveBeenCalled();
expect(ifVm.view.bind).not.toHaveBeenCalled();
expect(elseVm.showing).toBeTruthy();
expect(elseViewSlot.add).toHaveBeenCalledTimes(1);
expect(elseVm.view.bind).toHaveBeenCalledTimes(1);
});

it('should not render when initial condition is true', () => {
ifVm.showing = false;
elseVm.showing = false;

spyOn(elseViewSlot, 'add');
spyOn(elseVm.view, 'bind');
spyOn(ifViewSlot, 'add');
spyOn(ifVm.view, 'bind');

ifVm.condition = true;
ifVm.bind();
elseVm.bind();
// If should be shown now
expect(elseVm.showing).toBeFalsy();
expect(elseViewSlot.add).not.toHaveBeenCalled(); // Was not added yet
expect(elseVm.view.bind).not.toHaveBeenCalled(); // Was not added yet
expect(ifVm.showing).toBeTruthy();
expect(ifViewSlot.add).toHaveBeenCalledTimes(1);
expect(ifVm.view.bind).toHaveBeenCalledTimes(1);
});

it('should render when condition changes to false', () => {
ifVm.showing = false;
elseVm.showing = false;

spyOn(ifViewSlot, 'add');
spyOn(ifVm.view, 'bind');
spyOn(ifViewSlot, 'remove');
spyOn(ifVm.view, 'unbind');
spyOn(elseViewSlot, 'add');
spyOn(elseVm.view, 'bind');

ifVm.condition = true;
ifVm.bind();
elseVm.bind();
// Nothing should happen yet since else is not bound yet
expect(ifVm.showing).toBeTruthy();
expect(ifViewSlot.add).toHaveBeenCalledTimes(1);
expect(ifVm.view.bind).toHaveBeenCalledTimes(1);
expect(elseVm.showing).toBeFalsy();
expect(elseViewSlot.add).not.toHaveBeenCalled();
expect(elseVm.view.bind).not.toHaveBeenCalled();

ifVm.condition = false;
ifVm.conditionChanged(false);

// Else should be shown now and if should be removed
expect(ifVm.showing).toBeFalsy();
expect(ifViewSlot.remove).toHaveBeenCalledTimes(1);
expect(ifVm.view.unbind).toHaveBeenCalledTimes(1);
expect(elseVm.showing).toBeTruthy();
expect(elseViewSlot.add).toHaveBeenCalledTimes(1);
expect(elseVm.view.bind).toHaveBeenCalledTimes(1);
});

it('should render when condition changes to true', () => {
ifVm.showing = false;
elseVm.showing = false;

spyOn(ifViewSlot, 'add');
spyOn(ifVm.view, 'bind');
spyOn(elseViewSlot, 'add');
spyOn(elseVm.view, 'bind');
spyOn(elseViewSlot, 'remove');
spyOn(elseVm.view, 'unbind');

ifVm.condition = false;
ifVm.bind();
elseVm.bind();
// Nothing should happen yet since else is not bound yet
expect(ifVm.showing).toBeFalsy();
expect(ifViewSlot.add).not.toHaveBeenCalled();
expect(ifVm.view.bind).not.toHaveBeenCalled();
expect(elseVm.showing).toBeTruthy();
expect(elseViewSlot.add).toHaveBeenCalledTimes(1);
expect(elseVm.view.bind).toHaveBeenCalledTimes(1);

ifVm.condition = true;
ifVm.conditionChanged(true);

// Else should be shown now and if should be removed
expect(ifVm.showing).toBeTruthy();
expect(ifViewSlot.add).toHaveBeenCalledTimes(1);
expect(ifVm.view.bind).toHaveBeenCalledTimes(1);
expect(elseVm.showing).toBeFalsy();
expect(elseViewSlot.remove).toHaveBeenCalledTimes(1);
expect(elseVm.view.unbind).toHaveBeenCalledTimes(1);
});
});

0 comments on commit 31798f5

Please sign in to comment.