mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] prevent crash in case with t-foreach and t-out with components
The t-out directive is compiled internally into a LazyValue, which represents a value that may or may not be created sometimes in the future. It can also be reused more than once, and this is where there may be an issue: if a component is contained in the lazyvalue, it needs a unique key (coming from the t-foreach) to be properly indexed in the parent children map. However, the LazyValue does not keep the key information, so it is not able to provide it to its content. The fix is then quite clear: the LazyValue class should store the key information, and provides it to its content. This allows the LazyValue to be used multiple times, in any place in a template. closes #1270
This commit is contained in:
committed by
Sam Degueldre
parent
669fd622ec
commit
7ab34c5ca5
@@ -214,6 +214,14 @@ class CodeTarget {
|
||||
result.push(`}`);
|
||||
return result.join("\n ");
|
||||
}
|
||||
|
||||
currentKey(ctx: Context) {
|
||||
let key = this.loopLevel ? `key${this.loopLevel}` : "key";
|
||||
if (ctx.tKeyExpr) {
|
||||
key = `${ctx.tKeyExpr} + ${key}`;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
const TRANSLATABLE_ATTRS = ["label", "title", "placeholder", "alt"];
|
||||
@@ -365,19 +373,15 @@ export class CodeGenerator {
|
||||
|
||||
insertBlock(expression: string, block: BlockDescription, ctx: Context): void {
|
||||
let blockExpr = block.generateExpr(expression);
|
||||
const tKeyExpr = ctx.tKeyExpr;
|
||||
if (block.parentVar) {
|
||||
let keyArg = `key${this.target.loopLevel}`;
|
||||
if (tKeyExpr) {
|
||||
keyArg = `${tKeyExpr} + ${keyArg}`;
|
||||
}
|
||||
let key = this.target.currentKey(ctx);
|
||||
this.helpers.add("withKey");
|
||||
this.addLine(`${block.parentVar}[${ctx.index}] = withKey(${blockExpr}, ${keyArg});`);
|
||||
this.addLine(`${block.parentVar}[${ctx.index}] = withKey(${blockExpr}, ${key});`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tKeyExpr) {
|
||||
blockExpr = `toggler(${tKeyExpr}, ${blockExpr})`;
|
||||
if (ctx.tKeyExpr) {
|
||||
blockExpr = `toggler(${ctx.tKeyExpr}, ${blockExpr})`;
|
||||
}
|
||||
|
||||
if (block.isRoot && !ctx.preventRoot) {
|
||||
@@ -1053,7 +1057,8 @@ export class CodeGenerator {
|
||||
this.helpers.add("LazyValue");
|
||||
const bodyAst: AST = { type: ASTType.Multi, content: ast.body };
|
||||
const name = this.compileInNewTarget("value", bodyAst, ctx);
|
||||
let value = `new LazyValue(${name}, ctx, this, node)`;
|
||||
let key = this.target.currentKey(ctx);
|
||||
let value = `new LazyValue(${name}, ctx, this, node, ${key})`;
|
||||
value = ast.value ? (value ? `withDefault(${expr}, ${value})` : expr) : value;
|
||||
this.addLine(`ctx[\`${ast.name}\`] = ${value};`);
|
||||
} else {
|
||||
|
||||
@@ -111,15 +111,18 @@ class LazyValue {
|
||||
ctx: any;
|
||||
component: any;
|
||||
node: any;
|
||||
constructor(fn: any, ctx: any, component: any, node: any) {
|
||||
key: any;
|
||||
|
||||
constructor(fn: any, ctx: any, component: any, node: any, key: any) {
|
||||
this.fn = fn;
|
||||
this.ctx = capture(ctx);
|
||||
this.component = component;
|
||||
this.node = node;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
evaluate(): any {
|
||||
return this.fn.call(this.component, this.ctx, this.node);
|
||||
return this.fn.call(this.component, this.ctx, this.node, this.key);
|
||||
}
|
||||
|
||||
toString() {
|
||||
|
||||
Reference in New Issue
Block a user