diff --git a/packages/client/src/createApp.js b/packages/client/src/createApp.js index ba229f38ba..bddbb8999d 100644 --- a/packages/client/src/createApp.js +++ b/packages/client/src/createApp.js @@ -5,8 +5,9 @@ import { setState, setStateFromBinding } from "./state/setState"; import { trimSlash } from "./common/trimSlash"; import { isBound } from "./state/isState"; import { _initialiseChildren } from "./render/initialiseChildren"; +import { createTreeNode } from "./render/renderComponent"; -export const createApp = (componentLibraries, appDefinition, user, uiFunctions) => { +export const createApp = (document, componentLibraries, appDefinition, user, uiFunctions) => { const coreApi = createCoreApi(appDefinition, user); appDefinition.hierarchy = coreApi.templateApi.constructHierarchy(appDefinition.hierarchy); @@ -50,19 +51,19 @@ export const createApp = (componentLibraries, appDefinition, user, uiFunctions) if(isFunction(event)) event(context); } - const initialiseChildrenParams = (hydrate, parentContext, childIndex) => ({ - bb, coreApi, store, parentContext, + const initialiseChildrenParams = (hydrate, treeNode) => ({ + bb, coreApi, store, document, componentLibraries, appDefinition, - hydrate, uiFunctions, childIndex + hydrate, uiFunctions, treeNode }); - const bb = (componentProps, componentContext, childIndex) => ({ - hydrateChildren: _initialiseChildren(initialiseChildrenParams(true, componentContext, childIndex)), - appendChildren: _initialiseChildren(initialiseChildrenParams(false, componentContext, childIndex)), + const bb = (treeNode, componentProps) => ({ + hydrateChildren: _initialiseChildren(initialiseChildrenParams(true, treeNode)), + appendChildren: _initialiseChildren(initialiseChildrenParams(false, treeNode)), insertChildren: (props, htmlElement, anchor) => - _initialiseChildren(initialiseChildrenParams(false, componentContext, childIndex)) + _initialiseChildren(initialiseChildrenParams(false, treeNode)) (props, htmlElement, anchor), - context: componentContext, + context: treeNode.context, props: componentProps, call:safeCallEvent, setStateFromBinding: (binding, value) => setStateFromBinding(store, binding, value), @@ -76,6 +77,6 @@ export const createApp = (componentLibraries, appDefinition, user, uiFunctions) parent }); - return bb(); + return bb(createTreeNode()); } diff --git a/packages/client/src/index.js b/packages/client/src/index.js index 84d3723274..7114cde443 100644 --- a/packages/client/src/index.js +++ b/packages/client/src/index.js @@ -36,6 +36,7 @@ export const loadBudibase = async ({ } const app = createApp( + window.document, componentLibraries, appDefinition, user, diff --git a/packages/client/src/render/initialiseChildren.js b/packages/client/src/render/initialiseChildren.js index 8f46b86bb5..2fef49fa45 100644 --- a/packages/client/src/render/initialiseChildren.js +++ b/packages/client/src/render/initialiseChildren.js @@ -12,18 +12,23 @@ export const _initialiseChildren = (initialiseOpts) => (childrenProps, htmlElement, anchor=null) => { const { uiFunctions, bb, coreApi, - store, componentLibraries, childIndex, - appDefinition, parentContext, hydrate } = initialiseOpts; - - const childComponents = []; + store, componentLibraries, treeNode, + appDefinition, document, hydrate } = initialiseOpts; + + for(let childNode of treeNode.children) { + if(childNode.unsubscribe) + childNode.unsubscribe(); + if(childNode.component) + childNode.component.$destroy(); + } if(hydrate) { while (htmlElement.firstChild) { htmlElement.removeChild(htmlElement.firstChild); } } - - let childIndex = 0; + + const renderedComponents = []; for(let childProps of childrenProps) { const {componentName, libName} = splitName(childProps._component); @@ -33,26 +38,23 @@ export const _initialiseChildren = (initialiseOpts) => const {initialProps, bind} = setupBinding( store, childProps, coreApi, appDefinition.appRootPath); - const componentConstructor = componentLibraries[libName][componentName]; - const {component, context, lastChildIndex} = renderComponent({ + const renderedComponentsThisIteration = renderComponent({ + props: childProps, + parentNode: treeNode, componentConstructor,uiFunctions, - htmlElement, anchor, childIndex, - parentContext, initialProps, bb}); - - childIndex = lastChildIndex; + htmlElement, anchor, initialProps, + bb, document}); - const unsubscribe = bind(component); - childComponents.push({ - component, - context, - unsubscribe - }); + for(let comp of renderedComponentsThisIteration) { + comp.unsubscribe = bind(comp.component); + renderedComponents.push(comp); + } } - return childComponents; + return renderedComponents; } const splitName = fullname => { @@ -65,4 +67,4 @@ const splitName = fullname => { 0, fullname.length - componentName.length - 1); return {libName, componentName}; -} \ No newline at end of file +} diff --git a/packages/client/src/render/renderComponent.js b/packages/client/src/render/renderComponent.js index 143fb9d1d3..00d656915e 100644 --- a/packages/client/src/render/renderComponent.js +++ b/packages/client/src/render/renderComponent.js @@ -1,34 +1,43 @@ export const renderComponent = ({ componentConstructor, uiFunctions, - htmlElement, anchor, parentContext, - initialProps, bb, childIndex}) => { + htmlElement, anchor, props, + initialProps, bb, document, + parentNode}) => { const func = initialProps._id - ? uiFunctions[componentProps._id] + ? uiFunctions[initialProps._id] : undefined; + + const parentContext = (parentNode && parentNode.context) || {}; - let component; - let componentContext; + let renderedNodes = []; const render = (context) => { + let componentContext = parentContext; if(context) { componentContext = {...componentContext}; componentContext.$parent = parentContext; - } else { - componentContext = parentContext; } - initialProps._bb = bb(initialProps, componentContext); + const thisNode = createTreeNode(); + thisNode.context = componentContext; + thisNode.parentNode = parentNode; - component = new componentConstructor({ + parentNode.children.push(thisNode); + renderedNodes.push(thisNode); + + initialProps._bb = bb(thisNode, props); + + thisNode.component = new componentConstructor({ target: htmlElement, props: initialProps, hydrate:false, anchor - }); + }); - childIndex += 1; + thisNode.rootElement = htmlElement.children[ + htmlElement.children.length - 1]; } if(func) { @@ -37,10 +46,15 @@ export const renderComponent = ({ render(); } - return ({ - context: componentContext, - lastChildIndex: childIndex, - component - }); + return renderedNodes; } +export const createTreeNode = () => ({ + context: {}, + rootElement: null, + parentNode: null, + children: [], + component: null, + unsubscribe: () => {} +}); + diff --git a/packages/client/tests/testAppDef.js b/packages/client/tests/testAppDef.js index e028730890..bcaa4cae17 100644 --- a/packages/client/tests/testAppDef.js +++ b/packages/client/tests/testAppDef.js @@ -70,7 +70,7 @@ const maketestlib = (window) => ({ node.removeChild(c); } const components = currentProps._bb.appendChildren(currentProps._children, node); - childNodes = components.map(c => c._element); + childNodes = components.map(c => c.component._element); } else { currentProps._bb.hydrateChildren(currentProps._children, node); }