mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
do not destroy and rerender sub widgets if not necessary
add failing test on rerendering sub widgets...
This commit is contained in:
@@ -25,6 +25,8 @@ interface Meta<T extends WEnv> {
|
||||
isDestroyed: boolean;
|
||||
parent: Widget<T> | null;
|
||||
children: { [key: number]: Widget<T> };
|
||||
// children mapping: from templateID to widgetID
|
||||
cmap: { [key: number]: number };
|
||||
}
|
||||
|
||||
const patch = init([sdListeners, sdAttrs]);
|
||||
@@ -43,6 +45,7 @@ export class Widget<T extends WEnv> {
|
||||
|
||||
env: T;
|
||||
state: Object = {};
|
||||
props: any;
|
||||
refs: { [key: string]: Widget<T> | HTMLElement | undefined } = {}; // either HTMLElement or Widget
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -51,6 +54,7 @@ export class Widget<T extends WEnv> {
|
||||
|
||||
constructor(parent: Widget<T> | T, props?: any) {
|
||||
wl.push(this);
|
||||
this.props = props;
|
||||
let id: number;
|
||||
let p: Widget<T> | null = null;
|
||||
if (parent instanceof Widget) {
|
||||
@@ -69,7 +73,8 @@ export class Widget<T extends WEnv> {
|
||||
isMounted: false,
|
||||
isDestroyed: false,
|
||||
parent: p,
|
||||
children: {}
|
||||
children: {},
|
||||
cmap: {}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -139,6 +144,11 @@ export class Widget<T extends WEnv> {
|
||||
}
|
||||
}
|
||||
|
||||
updateProps(props?: any): Promise<void> {
|
||||
this.props = props;
|
||||
return this.render();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
@@ -691,11 +691,6 @@ const widgetDirective: Directive = {
|
||||
priority: 100,
|
||||
atNodeEncounter({ ctx, value, node, qweb }): boolean {
|
||||
ctx.rootContext.shouldDefineOwner = true;
|
||||
let dummyID = ctx.generateID();
|
||||
let defID = ctx.generateID();
|
||||
ctx.addLine(`let _${dummyID} = {}; // DUMMY`);
|
||||
ctx.addLine(`let _${dummyID}_index = c${ctx.parentNode}.length;`);
|
||||
ctx.addLine(`c${ctx.parentNode}.push(_${dummyID});`);
|
||||
let props = node.getAttribute("t-props");
|
||||
if (props) {
|
||||
props = props.trim();
|
||||
@@ -713,21 +708,48 @@ const widgetDirective: Directive = {
|
||||
props = qweb._formatExpression(props);
|
||||
}
|
||||
}
|
||||
let dummyID = ctx.generateID();
|
||||
let defID = ctx.generateID();
|
||||
let widgetID = ctx.generateID();
|
||||
ctx.addLine(`let _${dummyID} = {}; // DUMMY`);
|
||||
ctx.addLine(`let _${dummyID}_index = c${ctx.parentNode}.length;`);
|
||||
ctx.addLine(`c${ctx.parentNode}.push(_${dummyID});`);
|
||||
ctx.addLine(`let def${defID};`);
|
||||
|
||||
ctx.addLine(`if (${widgetID} in context.__widget__.cmap) {`);
|
||||
ctx.indent();
|
||||
ctx.addLine(
|
||||
`let curWidget = context.__widget__.children[context.__widget__.cmap[${widgetID}]]`
|
||||
);
|
||||
ctx.addLine(
|
||||
`def${defID} = curWidget.updateProps(${props}).then(()=>{vnode=curWidget.__widget__.vnode;c${
|
||||
ctx.parentNode
|
||||
}[_${dummyID}_index]=vnode;vnode.data.hook = {remove(){curWidget.destroy()}}});`
|
||||
);
|
||||
ctx.dedent();
|
||||
ctx.addLine("} else {");
|
||||
ctx.indent();
|
||||
|
||||
ctx.addLine(
|
||||
`let _${widgetID} = new context.widgets['${value}'](owner, ${props});`
|
||||
);
|
||||
ctx.addLine(
|
||||
`let def${defID} = _${widgetID}._start().then(() => _${widgetID}._render()).then(vnode=>{c${
|
||||
`context.__widget__.cmap[${widgetID}] = _${widgetID}.__widget__.id`
|
||||
);
|
||||
ctx.addLine(
|
||||
`def${defID} = _${widgetID}._start().then(() => _${widgetID}._render()).then(vnode=>{c${
|
||||
ctx.parentNode
|
||||
}[_${dummyID}_index]=vnode;vnode.data.hook = {create(_,vn){_${widgetID}._mount(vn)},remove(){_${widgetID}.destroy()}}});`
|
||||
);
|
||||
ctx.addLine(`extra.promises.push(def${defID});`);
|
||||
|
||||
let ref = node.getAttribute("t-ref");
|
||||
if (ref) {
|
||||
ctx.addLine(`context.refs['${ref}'] = _${widgetID};`);
|
||||
}
|
||||
ctx.dedent();
|
||||
ctx.addLine("}");
|
||||
ctx.addLine(`extra.promises.push(def${defID});`);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -56,10 +56,5 @@ export class Discuss extends Widget<Env> {
|
||||
|
||||
class ColorWidget extends Widget<Env> {
|
||||
name = "colorwidget";
|
||||
template = `<div>Current Color: <t t-esc="state.color"/></div>`;
|
||||
state: { color: "red" | "blue" };
|
||||
constructor(parent: Widget<Env>, props: { color: "red" | "blue" }) {
|
||||
super(parent);
|
||||
this.state = { color: props.color };
|
||||
}
|
||||
template = `<div>Current Color: <t t-esc="props.color"/></div>`;
|
||||
}
|
||||
|
||||
@@ -516,6 +516,25 @@ describe("composition", () => {
|
||||
|
||||
expect(children(widget)[0].env).toBe(env);
|
||||
});
|
||||
|
||||
test("rerendering a widget with a sub widget", async () => {
|
||||
class ParentWidget extends Widget<WEnv> {
|
||||
template = `<div><t t-widget="Counter"/></div>`;
|
||||
widgets = { Counter };
|
||||
}
|
||||
const widget = new ParentWidget(env);
|
||||
await widget.mount(fixture);
|
||||
const button = fixture.getElementsByTagName("button")[0];
|
||||
await button.click();
|
||||
await nextTick();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>1<button>Inc</button></div></div>"
|
||||
);
|
||||
await widget.render();
|
||||
expect(fixture.innerHTML).toBe(
|
||||
"<div><div>1<button>Inc</button></div></div>"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("props evaluation (with t-props directive)", () => {
|
||||
|
||||
Reference in New Issue
Block a user