diff --git a/src/compiler/code_generator.ts b/src/compiler/code_generator.ts index 97ee8409..3b9a0e72 100644 --- a/src/compiler/code_generator.ts +++ b/src/compiler/code_generator.ts @@ -672,8 +672,9 @@ export class CodeGenerator { this.target.hasRef = true; const isDynamic = INTERP_REGEXP.test(ast.ref); if (isDynamic) { + this.helpers.add("singleRefSetter"); const str = replaceDynamicParts(ast.ref, (expr) => this.captureExpression(expr, true)); - const idx = block!.insertData(`(el) => refs[${str}] = el`, "ref"); + const idx = block!.insertData(`singleRefSetter(refs, ${str})`, "ref"); attrs["block-ref"] = String(idx); } else { let name = ast.ref; @@ -686,7 +687,8 @@ export class CodeGenerator { info[1] = `multiRefSetter(refs, \`${name}\`)`; } else { let id = generateId("ref"); - this.target.refInfo[name] = [id, `(el) => refs[\`${name}\`] = el`]; + this.helpers.add("singleRefSetter"); + this.target.refInfo[name] = [id, `singleRefSetter(refs, \`${name}\`)`]; const index = block!.data.push(id) - 1; attrs["block-ref"] = String(index); } diff --git a/src/runtime/template_helpers.ts b/src/runtime/template_helpers.ts index 82a68e1a..0085d7de 100644 --- a/src/runtime/template_helpers.ts +++ b/src/runtime/template_helpers.ts @@ -202,6 +202,16 @@ function multiRefSetter(refs: RefMap, name: string): RefSetter { }; } +function singleRefSetter(refs: RefMap, name: string): RefSetter { + let _el: HTMLElement | null = null; + return (el) => { + if (el || refs[name] === _el) { + refs[name] = el; + _el = el; + } + }; +} + /** * Validate the component props (or next props) against the (static) props * description. This is potentially an expensive operation: it may needs to @@ -260,6 +270,7 @@ export const helpers = { prepareList, setContextValue, multiRefSetter, + singleRefSetter, shallowEqual, toNumber, validateProps, diff --git a/tests/compiler/__snapshots__/misc.test.ts.snap b/tests/compiler/__snapshots__/misc.test.ts.snap index 33f7acc2..b7a7ee29 100644 --- a/tests/compiler/__snapshots__/misc.test.ts.snap +++ b/tests/compiler/__snapshots__/misc.test.ts.snap @@ -182,7 +182,7 @@ exports[`misc other complex template 1`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; - let { prepareList, withKey } = helpers; + let { prepareList, withKey, singleRefSetter } = helpers; const callTemplate_1 = app.getTemplate(\`LOAD_INFOS_TEMPLATE\`); const comp1 = app.createComponent(\`BundlesList\`, true, false, false, false); const comp2 = app.createComponent(\`BundlesList\`, true, false, false, false); @@ -218,8 +218,8 @@ exports[`misc other complex template 1`] = ` return function template(ctx, node, key = \\"\\") { const refs = this.__owl__.refs; - const ref1 = (el) => refs[\`search_input\`] = el; - const ref2 = (el) => refs[\`settings_menu\`] = el; + const ref1 = singleRefSetter(refs, \`search_input\`); + const ref2 = singleRefSetter(refs, \`settings_menu\`); let b2,b4,b14,b17,b22,b23,b24,b25; let attr1 = \`/runbot/\${ctx['project'].slug}\`; let txt1 = ctx['project'].name; diff --git a/tests/compiler/__snapshots__/t_ref.test.ts.snap b/tests/compiler/__snapshots__/t_ref.test.ts.snap index 6048615a..22ece76f 100644 --- a/tests/compiler/__snapshots__/t_ref.test.ts.snap +++ b/tests/compiler/__snapshots__/t_ref.test.ts.snap @@ -4,13 +4,14 @@ exports[`t-ref can get a dynamic ref on a node 1`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; + let { singleRefSetter } = helpers; let block1 = createBlock(\`
\`); return function template(ctx, node, key = \\"\\") { const refs = this.__owl__.refs; const v1 = ctx['id']; - let ref1 = (el) => refs[\`myspan\${v1}\`] = el; + let ref1 = singleRefSetter(refs, \`myspan\${v1}\`); return block1([ref1]); } }" @@ -20,13 +21,14 @@ exports[`t-ref can get a dynamic ref on a node, alternate syntax 1`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; + let { singleRefSetter } = helpers; let block1 = createBlock(\`
\`); return function template(ctx, node, key = \\"\\") { const refs = this.__owl__.refs; const v1 = ctx['id']; - let ref1 = (el) => refs[\`myspan\${v1}\`] = el; + let ref1 = singleRefSetter(refs, \`myspan\${v1}\`); return block1([ref1]); } }" @@ -36,12 +38,13 @@ exports[`t-ref can get a ref on a node 1`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; + let { singleRefSetter } = helpers; let block1 = createBlock(\`
\`); return function template(ctx, node, key = \\"\\") { const refs = this.__owl__.refs; - const ref1 = (el) => refs[\`myspan\`] = el; + const ref1 = singleRefSetter(refs, \`myspan\`); return block1([ref1]); } }" @@ -66,12 +69,13 @@ exports[`t-ref ref in a t-call 2`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; + let { singleRefSetter } = helpers; let block1 = createBlock(\`
12
\`); return function template(ctx, node, key = \\"\\") { const refs = this.__owl__.refs; - const ref1 = (el) => refs[\`name\`] = el; + const ref1 = singleRefSetter(refs, \`name\`); return block1([ref1]); } }" @@ -81,13 +85,14 @@ exports[`t-ref ref in a t-if 1`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; + let { singleRefSetter } = helpers; let block1 = createBlock(\`
\`); let block2 = createBlock(\`\`); return function template(ctx, node, key = \\"\\") { const refs = this.__owl__.refs; - const ref1 = (el) => refs[\`name\`] = el; + const ref1 = singleRefSetter(refs, \`name\`); let b2; if (ctx['condition']) { b2 = block2([ref1]); @@ -101,7 +106,7 @@ exports[`t-ref refs in a loop 1`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; - let { prepareList, withKey } = helpers; + let { prepareList, singleRefSetter, withKey } = helpers; let block1 = createBlock(\`
\`); let block3 = createBlock(\`
\`); @@ -115,7 +120,7 @@ exports[`t-ref refs in a loop 1`] = ` const key1 = ctx['item']; const tKey_1 = ctx['item']; const v1 = ctx['item']; - let ref1 = (el) => refs[(v1)] = el; + let ref1 = singleRefSetter(refs, (v1)); let txt1 = ctx['item']; c_block2[i1] = withKey(block3([ref1, txt1]), tKey_1 + key1); } @@ -129,14 +134,15 @@ exports[`t-ref two refs, one in a t-if 1`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; + let { singleRefSetter } = helpers; let block1 = createBlock(\`

\`); let block2 = createBlock(\`\`); return function template(ctx, node, key = \\"\\") { const refs = this.__owl__.refs; - const ref1 = (el) => refs[\`name\`] = el; - const ref2 = (el) => refs[\`p\`] = el; + const ref1 = singleRefSetter(refs, \`name\`); + const ref2 = singleRefSetter(refs, \`p\`); let b2; if (ctx['condition']) { b2 = block2([ref1]); diff --git a/tests/components/__snapshots__/hooks.test.ts.snap b/tests/components/__snapshots__/hooks.test.ts.snap index 3fd4d391..e7c427f7 100644 --- a/tests/components/__snapshots__/hooks.test.ts.snap +++ b/tests/components/__snapshots__/hooks.test.ts.snap @@ -4,14 +4,15 @@ exports[`hooks autofocus hook input in a t-if 1`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; + let { singleRefSetter } = helpers; let block1 = createBlock(\`
\`); let block2 = createBlock(\`\`); return function template(ctx, node, key = \\"\\") { const refs = this.__owl__.refs; - const ref1 = (el) => refs[\`input1\`] = el; - const ref2 = (el) => refs[\`input2\`] = el; + const ref1 = singleRefSetter(refs, \`input1\`); + const ref2 = singleRefSetter(refs, \`input2\`); let b2; if (ctx['state'].flag) { b2 = block2([ref2]); @@ -25,13 +26,14 @@ exports[`hooks autofocus hook simple input 1`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; + let { singleRefSetter } = helpers; let block1 = createBlock(\`
\`); return function template(ctx, node, key = \\"\\") { const refs = this.__owl__.refs; - const ref1 = (el) => refs[\`input1\`] = el; - const ref2 = (el) => refs[\`input2\`] = el; + const ref1 = singleRefSetter(refs, \`input1\`); + const ref2 = singleRefSetter(refs, \`input2\`); return block1([ref1, ref2]); } }" @@ -264,12 +266,13 @@ exports[`hooks useEffect hook effect can depend on stuff in dom 1`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; + let { singleRefSetter } = helpers; let block2 = createBlock(\`
\`); return function template(ctx, node, key = \\"\\") { const refs = this.__owl__.refs; - const ref1 = (el) => refs[\`div\`] = el; + const ref1 = singleRefSetter(refs, \`div\`); let b2; if (ctx['state'].value) { b2 = block2([ref1]); @@ -353,12 +356,13 @@ exports[`hooks useRef hook: basic use 1`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; + let { singleRefSetter } = helpers; let block1 = createBlock(\`
\`); return function template(ctx, node, key = \\"\\") { const refs = this.__owl__.refs; - const ref1 = (el) => refs[\`button\`] = el; + const ref1 = singleRefSetter(refs, \`button\`); let txt1 = ctx['value']; return block1([ref1, txt1]); } diff --git a/tests/components/__snapshots__/refs.test.ts.snap b/tests/components/__snapshots__/refs.test.ts.snap index e90390d4..88b0284b 100644 --- a/tests/components/__snapshots__/refs.test.ts.snap +++ b/tests/components/__snapshots__/refs.test.ts.snap @@ -4,12 +4,13 @@ exports[`refs basic use 1`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; + let { singleRefSetter } = helpers; let block1 = createBlock(\`
\`); return function template(ctx, node, key = \\"\\") { const refs = this.__owl__.refs; - const ref1 = (el) => refs[\`div\`] = el; + const ref1 = singleRefSetter(refs, \`div\`); return block1([ref1]); } }" @@ -19,7 +20,7 @@ exports[`refs can use 2 refs with same name in a t-if/t-else situation 1`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; - let { multiRefSetter } = helpers; + let { singleRefSetter, multiRefSetter } = helpers; let block2 = createBlock(\`
\`); let block3 = createBlock(\`\`); @@ -42,13 +43,14 @@ exports[`refs refs and recursive templates 1`] = ` "function anonymous(app, bdom, helpers ) { let { text, createBlock, list, multi, html, toggler, comment } = bdom; + let { singleRefSetter } = helpers; const comp1 = app.createComponent(\`Test\`, true, false, false, false); let block1 = createBlock(\`

\`); return function template(ctx, node, key = \\"\\") { const refs = this.__owl__.refs; - const ref1 = (el) => refs[\`root\`] = el; + const ref1 = singleRefSetter(refs, \`root\`); let b2; let txt1 = ctx['props'].tree.value; if (ctx['props'].tree.child) { @@ -59,11 +61,33 @@ exports[`refs refs and recursive templates 1`] = ` }" `; +exports[`refs refs and t-key 1`] = ` +"function anonymous(app, bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, comment } = bdom; + let { singleRefSetter } = helpers; + + let block2 = createBlock(\`