diff --git a/src/component/directive.ts b/src/component/directive.ts index cff63928..b20fae47 100644 --- a/src/component/directive.ts +++ b/src/component/directive.ts @@ -245,7 +245,18 @@ QWeb.addDirective({ .join(","); let componentID = ctx.generateID(); - const templateKey = ctx.generateTemplateKey(); + let hasDefinedKey = false; + let templateKey; + if (node.tagName === "t" && !node.hasAttribute("t-key") && value.match(INTERP_REGEXP)) { + defineComponentKey(); + const id = ctx.generateID(); + // the ___ is to make sure we have no possible conflict with normal + // template keys + ctx.addLine(`let k${id} = '___' + componentKey${componentID}`); + templateKey = `k${id}`; + } else { + templateKey = ctx.generateTemplateKey(); + } let ref = node.getAttribute("t-ref"); let refExpr = ""; let refKey: string = ""; @@ -378,9 +389,15 @@ QWeb.addDirective({ ctx.addElse(); // new component + function defineComponentKey() { + if (!hasDefinedKey) { + const interpValue = ctx.interpolate(value); + ctx.addLine(`let componentKey${componentID} = ${interpValue};`); + hasDefinedKey = true; + } + } + defineComponentKey(); const contextualValue = value.match(INTERP_REGEXP) ? "false" : ctx.formatExpression(value); - const interpValue = ctx.interpolate(value); - ctx.addLine(`let componentKey${componentID} = ${interpValue};`); ctx.addLine( `let W${componentID} = ${contextualValue} || context.constructor.components[componentKey${componentID}] || QWeb.components[componentKey${componentID}];` ); diff --git a/tests/component/__snapshots__/component.test.ts.snap b/tests/component/__snapshots__/component.test.ts.snap index 14c5f113..9a75ca41 100644 --- a/tests/component/__snapshots__/component.test.ts.snap +++ b/tests/component/__snapshots__/component.test.ts.snap @@ -257,6 +257,45 @@ exports[`basic widget properties t-key on a component with t-if, and a sibling c }" `; +exports[`composition can switch between dynamic components without the need for a t-key 1`] = ` +"function anonymous(context, extra +) { + // Template name: \\"__template__3\\" + let utils = this.constructor.utils; + let QWeb = this.constructor; + let parent = context; + let scope = Object.create(context); + let h = this.h; + let c1 = [], p1 = {key:1}; + let vn1 = h('div', p1, c1); + // Component '{{state.child}}' + let componentKey2 = (scope['state'].child); + let k3 = '___' + componentKey2 + let w2 = k3 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k3]] : false; + let props2 = {}; + if (w2 && w2.__owl__.currentFiber && !w2.__owl__.vnode) { + w2.destroy(); + w2 = false; + } + if (w2) { + w2.__updateProps(props2, extra.fiber, undefined); + let pvnode = w2.__owl__.pvnode; + c1.push(pvnode); + } else { + let W2 = false || context.constructor.components[componentKey2] || QWeb.components[componentKey2]; + if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} + w2 = new W2(parent, props2); + parent.__owl__.cmap[k3] = w2.__owl__.id; + let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); + let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); + c1.push(pvnode); + w2.__owl__.pvnode = pvnode; + } + w2.__owl__.parentLastFiberId = extra.fiber.id; + return vn1; +}" +`; + exports[`composition sub components with some state rendered in a loop 1`] = ` "function anonymous(context, extra ) { @@ -330,7 +369,9 @@ exports[`composition t-component with dynamic value 1`] = ` let c1 = [], p1 = {key:1}; let vn1 = h('div', p1, c1); // Component '{{state.widget}}' - let w2 = '__3__' in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap['__3__']] : false; + let componentKey2 = (scope['state'].widget); + let k3 = '___' + componentKey2 + let w2 = k3 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k3]] : false; let props2 = {}; if (w2 && w2.__owl__.currentFiber && !w2.__owl__.vnode) { w2.destroy(); @@ -341,13 +382,12 @@ exports[`composition t-component with dynamic value 1`] = ` let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { - let componentKey2 = (scope['state'].widget); let W2 = false || context.constructor.components[componentKey2] || QWeb.components[componentKey2]; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); - parent.__owl__.cmap['__3__'] = w2.__owl__.id; + parent.__owl__.cmap[k3] = w2.__owl__.id; let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); - let pvnode = h('dummy', {key: '__3__', hook: {remove() {},destroy(vn) {w2.destroy();}}}); + let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; } @@ -368,7 +408,9 @@ exports[`composition t-component with dynamic value 2 1`] = ` let c1 = [], p1 = {key:1}; let vn1 = h('div', p1, c1); // Component 'Widget{{state.widget}}' - let w2 = '__3__' in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap['__3__']] : false; + let componentKey2 = \`Widget\${scope['state'].widget}\`; + let k3 = '___' + componentKey2 + let w2 = k3 in parent.__owl__.cmap ? parent.__owl__.children[parent.__owl__.cmap[k3]] : false; let props2 = {}; if (w2 && w2.__owl__.currentFiber && !w2.__owl__.vnode) { w2.destroy(); @@ -379,13 +421,12 @@ exports[`composition t-component with dynamic value 2 1`] = ` let pvnode = w2.__owl__.pvnode; c1.push(pvnode); } else { - let componentKey2 = \`Widget\${scope['state'].widget}\`; let W2 = false || context.constructor.components[componentKey2] || QWeb.components[componentKey2]; if (!W2) {throw new Error('Cannot find the definition of component \\"' + componentKey2 + '\\"')} w2 = new W2(parent, props2); - parent.__owl__.cmap['__3__'] = w2.__owl__.id; + parent.__owl__.cmap[k3] = w2.__owl__.id; let fiber = w2.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; }); - let pvnode = h('dummy', {key: '__3__', hook: {remove() {},destroy(vn) {w2.destroy();}}}); + let pvnode = h('dummy', {key: k3, hook: {remove() {},destroy(vn) {w2.destroy();}}}); c1.push(pvnode); w2.__owl__.pvnode = pvnode; } diff --git a/tests/component/component.test.ts b/tests/component/component.test.ts index bc5a34f4..79e5d317 100644 --- a/tests/component/component.test.ts +++ b/tests/component/component.test.ts @@ -1246,6 +1246,30 @@ describe("composition", () => { expect(fixture.innerHTML).toBe("