mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] qweb: t-widget: accept dyn values
This commit is contained in:
committed by
Géry Debongnie
parent
26f14180e2
commit
376f801541
+29
-4
@@ -13,7 +13,6 @@
|
|||||||
- [`t-if` directive](#t-if-directive)
|
- [`t-if` directive](#t-if-directive)
|
||||||
- [Expression evaluation](#expression-evaluation)
|
- [Expression evaluation](#expression-evaluation)
|
||||||
- [Dynamic attributes (`t-att` and `t-attf` directives)](#dynamic-attributes-t-att-and-t-attf-directives)
|
- [Dynamic attributes (`t-att` and `t-attf` directives)](#dynamic-attributes-t-att-and-t-attf-directives)
|
||||||
- [`t-attf` directive (dynamic attributes)](#t-att-directive-dynamic-attributes)
|
|
||||||
- [`t-call` directive (sub templates)](#t-call-directive-sub-templates)
|
- [`t-call` directive (sub templates)](#t-call-directive-sub-templates)
|
||||||
|
|
||||||
- [JS/OWL Specific Extensions](#jsowl-specific-extensions)
|
- [JS/OWL Specific Extensions](#jsowl-specific-extensions)
|
||||||
@@ -453,6 +452,30 @@ constructor. This will be assigned to the `props` variable, which can be accesse
|
|||||||
on the widget (and also, in the template). Whenever the state is updated, then
|
on the widget (and also, in the template). Whenever the state is updated, then
|
||||||
the subwidget will also be updated automatically.
|
the subwidget will also be updated automatically.
|
||||||
|
|
||||||
|
The `t-widget` directive also accepts dynamic values with string interpolation
|
||||||
|
(like the [`t-attf-`](#dynamic-attributes-t-att-and-t-attf-directives) directive):
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<div t-name="ParentWidget">
|
||||||
|
<t t-widget="ChildWidget#{id}"/>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
class ParentWidget {
|
||||||
|
widgets = { ChildWidget1, ChildWidget2 };
|
||||||
|
state = { id: 1 };
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Similarly to `t-attf-`, there is an alternate form of string interpolation:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<div t-name="ParentWidget">
|
||||||
|
<t t-widget="ChildWidget{{id}}"/>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
### `t-ref` directive
|
### `t-ref` directive
|
||||||
|
|
||||||
The `t-ref` directive helps a component keep reference to some inside part of it.
|
The `t-ref` directive helps a component keep reference to some inside part of it.
|
||||||
@@ -481,8 +504,9 @@ Note: if used on a component, the reference will be set in the `refs`
|
|||||||
variable between `willPatch` and `patched`.
|
variable between `willPatch` and `patched`.
|
||||||
|
|
||||||
The `t-ref` directive also accepts dynamic values with string interpolation
|
The `t-ref` directive also accepts dynamic values with string interpolation
|
||||||
(like the `t-attf-` directive). For example, if we have `id` set to 44 in the
|
(like the [`t-attf-`](#dynamic-attributes-t-att-and-t-attf-directives) and
|
||||||
rendering context,
|
[`t-widget-`](#component-t-widget-t-props) directives). For example, if we have
|
||||||
|
`id` set to 44 in the rendering context,
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<div t-ref="widget_#{id}"/>
|
<div t-ref="widget_#{id}"/>
|
||||||
@@ -492,7 +516,8 @@ rendering context,
|
|||||||
this.refs.widget_44;
|
this.refs.widget_44;
|
||||||
```
|
```
|
||||||
|
|
||||||
Similarly to `t-attf-`, there is an alternate form of string interpolation:
|
Similarly to `t-attf-` and `t-widget`, there is an alternate form of string
|
||||||
|
interpolation:
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<div t-ref="widget_{{id}}"/>
|
<div t-ref="widget_{{id}}"/>
|
||||||
|
|||||||
@@ -459,13 +459,14 @@ QWeb.addDirective({
|
|||||||
|
|
||||||
ctx.addIf(`!w${widgetID}`);
|
ctx.addIf(`!w${widgetID}`);
|
||||||
// new widget
|
// new widget
|
||||||
|
ctx.addLine(`let widgetKey${widgetID} = ${ctx.interpolate(value)};`);
|
||||||
ctx.addLine(
|
ctx.addLine(
|
||||||
`let W${widgetID} = context.widgets && context.widgets['${value}'] || QWeb.widgets['${value}'];`
|
`let W${widgetID} = context.widgets && context.widgets[widgetKey${widgetID}] || QWeb.widgets[widgetKey${widgetID}];`
|
||||||
);
|
);
|
||||||
|
|
||||||
// maybe only do this in dev mode...
|
// maybe only do this in dev mode...
|
||||||
ctx.addLine(
|
ctx.addLine(
|
||||||
`if (!W${widgetID}) {throw new Error(\`Cannot find the definition of widget "${value}"\`)}`
|
`if (!W${widgetID}) {throw new Error('Cannot find the definition of widget "' + widgetKey${widgetID} + '"')}`
|
||||||
);
|
);
|
||||||
ctx.addLine(`w${widgetID} = new W${widgetID}(owner, props${widgetID});`);
|
ctx.addLine(`w${widgetID} = new W${widgetID}(owner, props${widgetID});`);
|
||||||
ctx.addLine(
|
ctx.addLine(
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ exports[`animations t-transition combined with t-widget 1`] = `
|
|||||||
w4 = false
|
w4 = false
|
||||||
}
|
}
|
||||||
if (!w4) {
|
if (!w4) {
|
||||||
let W4 = context.widgets && context.widgets['Child'] || QWeb.widgets['Child'];
|
let widgetKey4 = \`Child\`;
|
||||||
if (!W4) {throw new Error(\`Cannot find the definition of widget \\"Child\\"\`)}
|
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4];
|
||||||
|
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')}
|
||||||
w4 = new W4(owner, props4);
|
w4 = new W4(owner, props4);
|
||||||
context.__owl__.cmap[4] = w4.__owl__.id;
|
context.__owl__.cmap[4] = w4.__owl__.id;
|
||||||
def3 = w4._prepare();
|
def3 = w4._prepare();
|
||||||
@@ -59,8 +60,9 @@ exports[`animations t-transition combined with t-widget and t-if 1`] = `
|
|||||||
w4 = false
|
w4 = false
|
||||||
}
|
}
|
||||||
if (!w4) {
|
if (!w4) {
|
||||||
let W4 = context.widgets && context.widgets['Child'] || QWeb.widgets['Child'];
|
let widgetKey4 = \`Child\`;
|
||||||
if (!W4) {throw new Error(\`Cannot find the definition of widget \\"Child\\"\`)}
|
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4];
|
||||||
|
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')}
|
||||||
w4 = new W4(owner, props4);
|
w4 = new W4(owner, props4);
|
||||||
context.__owl__.cmap[4] = w4.__owl__.id;
|
context.__owl__.cmap[4] = w4.__owl__.id;
|
||||||
def3 = w4._prepare();
|
def3 = w4._prepare();
|
||||||
|
|||||||
@@ -21,8 +21,9 @@ exports[`class and style attributes with t-widget dynamic t-att-style is properl
|
|||||||
w4 = false
|
w4 = false
|
||||||
}
|
}
|
||||||
if (!w4) {
|
if (!w4) {
|
||||||
let W4 = context.widgets && context.widgets['child'] || QWeb.widgets['child'];
|
let widgetKey4 = \`child\`;
|
||||||
if (!W4) {throw new Error(\`Cannot find the definition of widget \\"child\\"\`)}
|
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4];
|
||||||
|
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')}
|
||||||
w4 = new W4(owner, props4);
|
w4 = new W4(owner, props4);
|
||||||
context.__owl__.cmap[4] = w4.__owl__.id;
|
context.__owl__.cmap[4] = w4.__owl__.id;
|
||||||
def3 = w4._prepare();
|
def3 = w4._prepare();
|
||||||
@@ -57,8 +58,9 @@ exports[`class and style attributes with t-widget t-att-class is properly added/
|
|||||||
w4 = false
|
w4 = false
|
||||||
}
|
}
|
||||||
if (!w4) {
|
if (!w4) {
|
||||||
let W4 = context.widgets && context.widgets['child'] || QWeb.widgets['child'];
|
let widgetKey4 = \`child\`;
|
||||||
if (!W4) {throw new Error(\`Cannot find the definition of widget \\"child\\"\`)}
|
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4];
|
||||||
|
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')}
|
||||||
w4 = new W4(owner, props4);
|
w4 = new W4(owner, props4);
|
||||||
context.__owl__.cmap[4] = w4.__owl__.id;
|
context.__owl__.cmap[4] = w4.__owl__.id;
|
||||||
def3 = w4._prepare();
|
def3 = w4._prepare();
|
||||||
@@ -111,8 +113,9 @@ exports[`composition sub widgets with some state rendered in a loop 1`] = `
|
|||||||
w7 = false
|
w7 = false
|
||||||
}
|
}
|
||||||
if (!w7) {
|
if (!w7) {
|
||||||
let W7 = context.widgets && context.widgets['ChildWidget'] || QWeb.widgets['ChildWidget'];
|
let widgetKey7 = \`ChildWidget\`;
|
||||||
if (!W7) {throw new Error(\`Cannot find the definition of widget \\"ChildWidget\\"\`)}
|
let W7 = context.widgets && context.widgets[widgetKey7] || QWeb.widgets[widgetKey7];
|
||||||
|
if (!W7) {throw new Error('Cannot find the definition of widget \\"' + widgetKey7 + '\\"')}
|
||||||
w7 = new W7(owner, props7);
|
w7 = new W7(owner, props7);
|
||||||
context.__owl__.cmap[key8] = w7.__owl__.id;
|
context.__owl__.cmap[key8] = w7.__owl__.id;
|
||||||
def6 = w7._prepare();
|
def6 = w7._prepare();
|
||||||
@@ -127,6 +130,78 @@ exports[`composition sub widgets with some state rendered in a loop 1`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`composition t-widget with dynamic value 1`] = `
|
||||||
|
"function anonymous(context,extra
|
||||||
|
) {
|
||||||
|
let utils = this.utils;
|
||||||
|
let QWeb = this.constructor;
|
||||||
|
let owner = context;
|
||||||
|
var h = this.utils.h;
|
||||||
|
let c1 = [], p1 = {key:1};
|
||||||
|
var vn1 = h('div', p1, c1);
|
||||||
|
//WIDGET
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
|
let def3;
|
||||||
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let props4 = {};
|
||||||
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode && props4 !== w4.__owl__.renderProps) {
|
||||||
|
w4.destroy();
|
||||||
|
w4 = false
|
||||||
|
}
|
||||||
|
if (!w4) {
|
||||||
|
let widgetKey4 = context['state'].widget;
|
||||||
|
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4];
|
||||||
|
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')}
|
||||||
|
w4 = new W4(owner, props4);
|
||||||
|
context.__owl__.cmap[4] = w4.__owl__.id;
|
||||||
|
def3 = w4._prepare();
|
||||||
|
def3 = def3.then(vnode=>{let pvnode=h(vnode.sel, {key: 4, hook: {insert(vn) {let nvn=w4._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w4.destroy();}}});c1[_2_index]=pvnode;w4.__owl__.pvnode = pvnode;});
|
||||||
|
} else {
|
||||||
|
def3 = w4._updateProps(props4, extra.forceUpdate, extra.patchQueue);
|
||||||
|
def3 = def3.then(()=>{if (w4.__owl__.isDestroyed) {return};let pvnode=w4.__owl__.pvnode;c1[_2_index]=pvnode;});
|
||||||
|
}
|
||||||
|
extra.promises.push(def3);
|
||||||
|
return vn1;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`composition t-widget with dynamic value 2 1`] = `
|
||||||
|
"function anonymous(context,extra
|
||||||
|
) {
|
||||||
|
let utils = this.utils;
|
||||||
|
let QWeb = this.constructor;
|
||||||
|
let owner = context;
|
||||||
|
var h = this.utils.h;
|
||||||
|
let c1 = [], p1 = {key:1};
|
||||||
|
var vn1 = h('div', p1, c1);
|
||||||
|
//WIDGET
|
||||||
|
let _2_index = c1.length;
|
||||||
|
c1.push(null);
|
||||||
|
let def3;
|
||||||
|
let w4 = 4 in context.__owl__.cmap ? context.__owl__.children[context.__owl__.cmap[4]] : false;
|
||||||
|
let props4 = {};
|
||||||
|
if (w4 && w4.__owl__.renderPromise && !w4.__owl__.vnode && props4 !== w4.__owl__.renderProps) {
|
||||||
|
w4.destroy();
|
||||||
|
w4 = false
|
||||||
|
}
|
||||||
|
if (!w4) {
|
||||||
|
let widgetKey4 = \`Widget\${context['state'].widget}\`;
|
||||||
|
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4];
|
||||||
|
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')}
|
||||||
|
w4 = new W4(owner, props4);
|
||||||
|
context.__owl__.cmap[4] = w4.__owl__.id;
|
||||||
|
def3 = w4._prepare();
|
||||||
|
def3 = def3.then(vnode=>{let pvnode=h(vnode.sel, {key: 4, hook: {insert(vn) {let nvn=w4._mount(vnode, pvnode.elm);pvnode.elm=nvn.elm;},remove() {},destroy(vn) {w4.destroy();}}});c1[_2_index]=pvnode;w4.__owl__.pvnode = pvnode;});
|
||||||
|
} else {
|
||||||
|
def3 = w4._updateProps(props4, extra.forceUpdate, extra.patchQueue);
|
||||||
|
def3 = def3.then(()=>{if (w4.__owl__.isDestroyed) {return};let pvnode=w4.__owl__.pvnode;c1[_2_index]=pvnode;});
|
||||||
|
}
|
||||||
|
extra.promises.push(def3);
|
||||||
|
return vn1;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`random stuff/miscellaneous snapshotting compiled code 1`] = `
|
exports[`random stuff/miscellaneous snapshotting compiled code 1`] = `
|
||||||
"function anonymous(context,extra
|
"function anonymous(context,extra
|
||||||
) {
|
) {
|
||||||
@@ -148,8 +223,9 @@ exports[`random stuff/miscellaneous snapshotting compiled code 1`] = `
|
|||||||
w4 = false
|
w4 = false
|
||||||
}
|
}
|
||||||
if (!w4) {
|
if (!w4) {
|
||||||
let W4 = context.widgets && context.widgets['child'] || QWeb.widgets['child'];
|
let widgetKey4 = \`child\`;
|
||||||
if (!W4) {throw new Error(\`Cannot find the definition of widget \\"child\\"\`)}
|
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4];
|
||||||
|
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')}
|
||||||
w4 = new W4(owner, props4);
|
w4 = new W4(owner, props4);
|
||||||
context.__owl__.cmap[key5] = w4.__owl__.id;
|
context.__owl__.cmap[key5] = w4.__owl__.id;
|
||||||
def3 = w4._prepare();
|
def3 = w4._prepare();
|
||||||
@@ -183,8 +259,9 @@ exports[`random stuff/miscellaneous t-props should not be undefined (snapshottin
|
|||||||
w4 = false
|
w4 = false
|
||||||
}
|
}
|
||||||
if (!w4) {
|
if (!w4) {
|
||||||
let W4 = context.widgets && context.widgets['child'] || QWeb.widgets['child'];
|
let widgetKey4 = \`child\`;
|
||||||
if (!W4) {throw new Error(\`Cannot find the definition of widget \\"child\\"\`)}
|
let W4 = context.widgets && context.widgets[widgetKey4] || QWeb.widgets[widgetKey4];
|
||||||
|
if (!W4) {throw new Error('Cannot find the definition of widget \\"' + widgetKey4 + '\\"')}
|
||||||
w4 = new W4(owner, props4);
|
w4 = new W4(owner, props4);
|
||||||
context.__owl__.cmap[4] = w4.__owl__.id;
|
context.__owl__.cmap[4] = w4.__owl__.id;
|
||||||
def3 = w4._prepare();
|
def3 = w4._prepare();
|
||||||
|
|||||||
+32
-2
@@ -857,7 +857,7 @@ describe("composition", () => {
|
|||||||
const widget = new ParentWidget(env);
|
const widget = new ParentWidget(env);
|
||||||
await widget.mount(fixture);
|
await widget.mount(fixture);
|
||||||
expect(fixture.innerHTML).toBe("<div><div>world</div></div>");
|
expect(fixture.innerHTML).toBe("<div><div>world</div></div>");
|
||||||
delete QWeb.widgets['WidgetB'];
|
delete QWeb.widgets["WidgetB"];
|
||||||
});
|
});
|
||||||
|
|
||||||
test("don't fallback to global registry if widget defined locally", async () => {
|
test("don't fallback to global registry if widget defined locally", async () => {
|
||||||
@@ -871,7 +871,7 @@ describe("composition", () => {
|
|||||||
const widget = new ParentWidget(env);
|
const widget = new ParentWidget(env);
|
||||||
await widget.mount(fixture);
|
await widget.mount(fixture);
|
||||||
expect(fixture.innerHTML).toBe("<div><span>Belgium</span></div>");
|
expect(fixture.innerHTML).toBe("<div><span>Belgium</span></div>");
|
||||||
delete QWeb.widgets['WidgetB'];
|
delete QWeb.widgets["WidgetB"];
|
||||||
});
|
});
|
||||||
|
|
||||||
test("throw a nice error if it cannot find widget", async () => {
|
test("throw a nice error if it cannot find widget", async () => {
|
||||||
@@ -1254,6 +1254,36 @@ describe("composition", () => {
|
|||||||
`)
|
`)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("t-widget with dynamic value", async () => {
|
||||||
|
env.qweb.addTemplate(
|
||||||
|
"ParentWidget",
|
||||||
|
`<div><t t-widget="{{state.widget}}"/></div>`
|
||||||
|
);
|
||||||
|
class ParentWidget extends Widget {
|
||||||
|
widgets = { WidgetB };
|
||||||
|
state = { widget: "WidgetB" };
|
||||||
|
}
|
||||||
|
const widget = new ParentWidget(env);
|
||||||
|
await widget.mount(fixture);
|
||||||
|
expect(fixture.innerHTML).toBe("<div><div>world</div></div>");
|
||||||
|
expect(env.qweb.templates.ParentWidget.fn.toString()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("t-widget with dynamic value 2", async () => {
|
||||||
|
env.qweb.addTemplate(
|
||||||
|
"ParentWidget",
|
||||||
|
`<div><t t-widget="Widget{{state.widget}}"/></div>`
|
||||||
|
);
|
||||||
|
class ParentWidget extends Widget {
|
||||||
|
widgets = { WidgetB };
|
||||||
|
state = { widget: "B" };
|
||||||
|
}
|
||||||
|
const widget = new ParentWidget(env);
|
||||||
|
await widget.mount(fixture);
|
||||||
|
expect(fixture.innerHTML).toBe("<div><div>world</div></div>");
|
||||||
|
expect(env.qweb.templates.ParentWidget.fn.toString()).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("props evaluation (with t-props directive)", () => {
|
describe("props evaluation (with t-props directive)", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user