Skip to content

Commit

Permalink
Add adopted lifecycle method to components
Browse files Browse the repository at this point in the history
  • Loading branch information
ThaNarie committed Mar 5, 2018
1 parent 2d0798c commit a80c193
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 10 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "muban-core",
"version": "1.0.1",
"version": "1.1.0",
"description": "The core library and webpack loaders for Muban",
"main": "./index.js",
"types": "./index.d.ts",
Expand Down
1 change: 0 additions & 1 deletion src/lib/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ export type BootstrapOptions = {
indexTemplate: any;
appTemplate: any;
dataContext: any;
dataContextHot: any;
partialsContext: any;
Handlebars: any;
};
Expand Down
17 changes: 16 additions & 1 deletion src/lib/utils/initComponents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import { getComponents, setComponentInstance } from './componentStore';
/**
* Called to init components for the elements in the DOM.
*
* @param {HTMLElement} rootElement
* Once the component tree for the passed rootELement is fully constructed, the adopted() lifecycle
* method will be called on all new components that implement that method.
* When the adopted() method is called, it means that the component is fully adopted by all its
* parents and the application is fully mounted.
*
* @param {HTMLElement} rootElement Only components on or in this element will be constructed, this
* means you can update a new section of HTML at a later time.
*/
export default function initComponents(rootElement: HTMLElement): void {
const list = [];
Expand Down Expand Up @@ -38,6 +44,8 @@ export default function initComponents(rootElement: HTMLElement): void {
// before any parents, allowing the parents to directly reference them
const sortedList = sortBy(list, ['depth']).reverse();

const newInstances = [];

// create all corresponding classes
sortedList.forEach(({ component, element }) => {
const BlockConstructor = component;
Expand All @@ -47,11 +55,18 @@ export default function initComponents(rootElement: HTMLElement): void {
try {
const instance = new BlockConstructor(element);
setComponentInstance(displayName, { instance, element });
newInstances.push(instance);
} catch (e) {
// tslint:disable-next-line no-console
console.error(e);
}
});

newInstances.forEach(instance => {
if (typeof instance.adopted === 'function') {
instance.adopted();
}
});
}

/**
Expand Down
7 changes: 0 additions & 7 deletions test/Example.spec.ts

This file was deleted.

5 changes: 5 additions & 0 deletions test/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function createHTML(content) {
const div = document.createElement('div');
div.innerHTML = content;
return <HTMLElement>div.firstElementChild;
}
82 changes: 82 additions & 0 deletions test/initComponents.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { expect, use } from 'chai';
import { spy } from 'sinon';
import sinonChai from 'sinon-chai';

import initComponents from '../src/lib/utils/initComponents';
import { registerComponent } from '../src/lib/utils/componentStore';
import { createHTML } from './helpers';

use(sinonChai);

describe('initComponents', () => {
it('should test mount and adopt lifecycle methods', () => {

const mountSpy = spy();
const adoptSpy = spy();

const foo = class Foo {
static displayName: string = 'foo';

constructor() {
// dom ready
mountSpy('foo');
}

adopted() {
// fully adopted in tree
adoptSpy('foo');
}
};
registerComponent(foo);

const bar = class Bar {
static displayName: string = 'bar';

constructor() {
// dom ready
mountSpy('bar');
}

adopted() {
// fully adopted in tree
adoptSpy('bar');
}
};
registerComponent(bar);

const div = createHTML(`
<div>
<div data-component="foo">
foo
<div data-component="bar">
Foobar
<div class="container"></div>
</div>
</div>
</div>
`);

initComponents(div);

expect(mountSpy).to.have.been.calledTwice;
expect(adoptSpy).to.have.been.calledTwice;
expect(mountSpy).to.have.been.calledBefore(adoptSpy);

const inner = createHTML(`
<div>
<div data-component="foo">
</div>
</div>
`);

div.querySelector('.container').appendChild(inner);

initComponents(inner);

expect(mountSpy).to.have.been.calledThrice;
expect(adoptSpy).to.have.been.calledThrice;

expect(mountSpy.args).to.deep.equal([['bar'], ['foo'], ['foo']]);
expect(adoptSpy.args).to.deep.equal([['bar'], ['foo'], ['foo']]);
});
});

0 comments on commit a80c193

Please sign in to comment.