Skip to content
This repository was archived by the owner on Feb 20, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 36 additions & 3 deletions src/Block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import BlockType = require('./BlockType');
import View = require('./View');
import DomUtils = require('./DomUtils');
import IBlockSpec = require('./IBlockSpec');
import IView = require('./IView');
import EventGroup = require('./EventGroup');

class Block {
Expand All @@ -13,8 +14,10 @@ class Block {
view: View;
placeholder: Comment;
bindings: Binding[] = [];
subViews: { name: string; view:IView }[] = [];
_lastValues: any = {};
scope: {[key: string]: string};
bound = false;
scope: {[key: string]: any};
events = new EventGroup(this);

constructor(view: View, parent: Block) {
Expand All @@ -32,8 +35,9 @@ class Block {
}

bind() {

this.bound = true;
this._bindEvents();
this._bindSubviews();

this.children.forEach((child) => {
child.bind();
Expand Down Expand Up @@ -69,6 +73,8 @@ class Block {
child.dispose();
});

this._disposeSubviews();

this.events.dispose();
}

Expand Down Expand Up @@ -229,6 +235,23 @@ class Block {
});
}

_bindSubviews() {
var length = this.subViews.length;
for (var i = 0; i < length; i++) {
this.subViews[i].view.activate();
}
}

_disposeSubviews() {
var length = this.subViews.length;
for (var i = 0; i < length; i++) {
var subview = this.subViews[i];
subview.view.dispose();
this.view.removeChild(subview.view);
delete this.scope[subview.name];
}
}

_processBinding(spec: IBlockSpec, element: HTMLElement): HTMLElement {

if (spec.binding) {
Expand All @@ -255,7 +278,17 @@ function renderNodes(block:Block, nodes: IBlockSpec[]): Node[]{
}
return c;
} else if (node.type === BlockType.View) {
return block._processBinding(node, block.view[node.name].render());
var viewRef = block.view[node.name];
var view: IView;
if (typeof viewRef === 'function') {
view = new viewRef();
block.subViews.push({name: node.name, view: view});
block.view.addChild(view);
block.scope[node.name] = view;
} else {
view = viewRef;
}
return block._processBinding(node, view.render());
}
});
}
Expand Down
6 changes: 4 additions & 2 deletions src/RepeaterBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ class RepeaterBlock extends Block {
source: string;
iterator: string;
blockTemplate: IBlockSpec[];
bound = false;
rendered = false;
_lastList;
_currentList = new List<IItem>();
Expand Down Expand Up @@ -120,11 +119,14 @@ class RepeaterBlock extends Block {
if (this.rendered) {
child.render();
}

this.parent.insertElements(child.elements, <any>precedingElement);

if (this.bound) {
child.bind();
}

this.parent.insertElements(child.elements, <any>precedingElement);

}

_removeChild(index: number) {
Expand Down
2 changes: 1 addition & 1 deletion src/View.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ class View extends BaseView {
}

_getValueFromFunction(target, existingArgs ? , scopeSource ? : IScopeObj) {
var propTarget = this._getPropTarget(target);
var propTarget = this._getPropTarget(target, scopeSource);
var args = [];
var returnValue = '';

Expand Down
2 changes: 0 additions & 2 deletions test/Block.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ describe('Block', function () {

it('should render a subview', function () {
var subView = new BaseView();
subView.element = document.createElement("div")
view.addChild(subView);
view['subView'] = subView;

Expand All @@ -168,7 +167,6 @@ describe('Block', function () {

it('should render a subview with bindings', function () {
var subView = new BaseView();
subView.element = document.createElement("div")
view.addChild(subView);
view['subView'] = subView;
var callbackCalled = false;
Expand Down
128 changes: 128 additions & 0 deletions test/RepeaterBlock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,29 @@

import chai = require("chai");
var assert = chai.assert;
import BaseView = require('../src/BaseView');
import Block = require('../src/Block');
import BlockProcessor = require('../src/BlockProcessor');
import BlockType = require('../src/BlockType');
import View = require('../src/View');
import ViewModel = require('../src/ViewModel');
import List = require('../src/List');

class TestView extends BaseView {

viewModelType = TestViewModel;

onPostRender() {
this.element.textContent = "Test";
}
}

class TestViewModel extends ViewModel {
upper(text: string): string {
return text.toUpperCase();
}
}

describe('Block', function () {

var view: View;
Expand Down Expand Up @@ -651,6 +668,117 @@ describe('Block', function () {
block.dispose();
});

it('should support subviews', function () {

view['subView'] = TestView;
view.setData({ data: new List([{ val: 1 }, { val: 2 }, { val: 3 }]) });
var block = BlockProcessor.fromSpec(view, {
type: BlockType.Element,
tag: "div",
children: [
{
type: BlockType.RepeaterBlock,
source: "data",
iterator: "item",
children: [{
type: BlockType.Element,
tag: "div",
binding: {
text: "item.val"
}
}, {
type: BlockType.View,
name: "subView"
}]
}
]
});

block.render();
block.bind();
block.update();
var div = block.elements[0];
assert.strictEqual(div.textContent, '1Test2Test3Test');
assert.strictEqual(view.children.length, 3);
block.dispose();
});

it('should lifecycle views correctly', function () {

view['subView'] = TestView;
var list = new List([]);
view.setData({ data: list});
var block = BlockProcessor.fromSpec(view, {
type: BlockType.Element,
tag: "div",
children: [
{
type: BlockType.RepeaterBlock,
source: "data",
iterator: "item",
children: [{
type: BlockType.View,
name: "subView"
}]
}
]
});

block.render();
block.bind();

var div = block.elements[0];
assert.strictEqual(div.textContent, '');
assert.strictEqual(view.children.length, 0);

list.push({ val: 1 });
assert.strictEqual(div.textContent, 'Test');
assert.strictEqual(view.children.length, 1);
var child = <BaseView> view.children[0];
assert.strictEqual(child.isActive, true);
list.pop();
assert.strictEqual(view.children.length, 0);
assert.strictEqual(child.isActive, false);
assert.strictEqual(child.isDisposed, true);


block.dispose();
});

it('should add subviews to block scope', function () {

view['subView'] = TestView;
view.setData({ data: new List([{ val: 'hey' }, { val: 'hi' }, { val: 'yo' }]) });
var block = BlockProcessor.fromSpec(view, {
type: BlockType.Element,
tag: "div",
children: [
{
type: BlockType.RepeaterBlock,
source: "data",
iterator: "item",
children: [{
type: BlockType.Element,
tag: "div",
binding: {
text: "subView.upper(item.val)"
}
}, {
type: BlockType.View,
name: "subView"
}]
}
]
});

block.render();
block.bind();
block.update();
var div = block.elements[0];
assert.strictEqual(div.textContent, 'HEYTestHITestYOTest');
assert.strictEqual(view.children.length, 3);
block.dispose();
});
});

});