mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] component: call willPatch/patched hooks properly
Each component called its hooks properly individually, however the issue was that it was done component by component. However, in practice, we want the willPatch hooks to be done before ANY patch is actually performed, and the patched should be called AFTER every patch is applied. The trick is to propagate a list of patched components across various function calls. closes #64
This commit is contained in:
+29
-13
@@ -236,17 +236,33 @@ export class Component<
|
||||
}
|
||||
}
|
||||
|
||||
async render(force: boolean = false): Promise<void> {
|
||||
async render(force: boolean = false, patchQueue?: any[]): Promise<void> {
|
||||
if (this.__owl__.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
const renderVDom = this._render(force);
|
||||
const shouldCallPatchHooks: boolean = !patchQueue;
|
||||
if (shouldCallPatchHooks) {
|
||||
patchQueue = [];
|
||||
}
|
||||
const renderVDom = this._render(force, patchQueue);
|
||||
const renderId = this.__owl__.renderId;
|
||||
const vnode = await renderVDom;
|
||||
if (renderId === this.__owl__.renderId) {
|
||||
// we only update the vnode and the actual DOM if no other rendering
|
||||
// occurred between now and when the render method was initially called.
|
||||
if (shouldCallPatchHooks) {
|
||||
for (let i = 0; i < patchQueue!.length; i++) {
|
||||
const c = patchQueue![i];
|
||||
c.__owl__.willPatchVal = c.willPatch();
|
||||
}
|
||||
}
|
||||
this._patch(vnode);
|
||||
if (shouldCallPatchHooks) {
|
||||
for (let i = patchQueue!.length - 1; i >= 0; i--) {
|
||||
const c = patchQueue![i];
|
||||
c.patched(c.__owl__.willPatchVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,10 +321,11 @@ export class Component<
|
||||
|
||||
async updateProps(
|
||||
nextProps: Props,
|
||||
forceUpdate: boolean = false
|
||||
forceUpdate: boolean = false,
|
||||
patchQueue: any[],
|
||||
): Promise<void> {
|
||||
const shouldUpdate = forceUpdate || this.shouldUpdate(nextProps);
|
||||
return shouldUpdate ? this._updateProps(nextProps) : Promise.resolve();
|
||||
return shouldUpdate ? this._updateProps(nextProps, patchQueue) : Promise.resolve();
|
||||
}
|
||||
|
||||
set(target: any, key: string | number, value: any) {
|
||||
@@ -319,21 +336,16 @@ export class Component<
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
async _updateProps(nextProps: Props): Promise<void> {
|
||||
async _updateProps(nextProps: Props, patchQueue: any[]): Promise<void> {
|
||||
await this.willUpdateProps(nextProps);
|
||||
this.props = nextProps;
|
||||
await this.render();
|
||||
await this.render(false, patchQueue);
|
||||
}
|
||||
|
||||
_patch(vnode) {
|
||||
this.__owl__.renderPromise = null;
|
||||
if (this.__owl__.vnode) {
|
||||
const isMounted = this.__owl__.isMounted;
|
||||
const snapshot = isMounted && this.willPatch();
|
||||
this.__owl__.vnode = patch(this.__owl__.vnode, vnode);
|
||||
if (isMounted) {
|
||||
this.patched(snapshot);
|
||||
}
|
||||
} else {
|
||||
this.__owl__.vnode = patch(document.createElement(vnode.sel!), vnode);
|
||||
}
|
||||
@@ -358,7 +370,10 @@ export class Component<
|
||||
return this.__owl__.renderPromise;
|
||||
}
|
||||
|
||||
async _render(force: boolean = false): Promise<VNode> {
|
||||
async _render(force: boolean = false, patchQueue: any[] = []): Promise<VNode> {
|
||||
if (this.__owl__.isMounted) {
|
||||
patchQueue.push(this)
|
||||
}
|
||||
this.__owl__.renderId++;
|
||||
const promises: Promise<void>[] = [];
|
||||
const template = this.inlineTemplate || this.template;
|
||||
@@ -368,7 +383,8 @@ export class Component<
|
||||
let vnode = this.env.qweb.render(template, this, {
|
||||
promises,
|
||||
handlers: this.__owl__.boundHandlers,
|
||||
forceUpdate: force
|
||||
forceUpdate: force,
|
||||
patchQueue,
|
||||
});
|
||||
if (this.__owl__.observer) {
|
||||
this.__owl__.observer.allowMutations = true;
|
||||
|
||||
+2
-2
@@ -1060,7 +1060,7 @@ const widgetDirective: Directive = {
|
||||
ctx.addIf(`w${widgetID} && w${widgetID}.__owl__.renderPromise`);
|
||||
ctx.addIf(`w${widgetID}.__owl__.isStarted`);
|
||||
ctx.addLine(
|
||||
`def${defID} = w${widgetID}.updateProps(props${widgetID}, extra.forceUpdate);`
|
||||
`def${defID} = w${widgetID}.updateProps(props${widgetID}, extra.forceUpdate, extra.patchQueue);`
|
||||
);
|
||||
ctx.addElse();
|
||||
ctx.addLine(`isNew${widgetID} = true`);
|
||||
@@ -1076,7 +1076,7 @@ const widgetDirective: Directive = {
|
||||
ctx.addIf(`!def${defID}`);
|
||||
ctx.addIf(`w${widgetID}`);
|
||||
ctx.addLine(
|
||||
`def${defID} = w${widgetID}.updateProps(props${widgetID}, extra.forceUpdate);`
|
||||
`def${defID} = w${widgetID}.updateProps(props${widgetID}, extra.forceUpdate, extra.patchQueue);`
|
||||
);
|
||||
ctx.addElse();
|
||||
ctx.addLine(
|
||||
|
||||
Reference in New Issue
Block a user