From cea82e945d17dc26e93a52667bede67623fd7f2c Mon Sep 17 00:00:00 2001 From: Lucas Perais Date: Wed, 18 Jan 2023 15:46:16 +0100 Subject: [PATCH] [FIX] compiler: t-model supports radio group in t-foreach Have a radio group defined inside a t-foreach: ```xml ``` Before this commit the algorithm that set the "checked" attribute on the current active radio button according to the state did not support having a dynamic value (`t-att-value`) After this commit, this use case works as we go look in the dynamic attributes too. --- src/compiler/code_generator.ts | 10 +++++- .../__snapshots__/t_model.test.ts.snap | 30 ++++++++++++++++++ tests/components/t_model.test.ts | 31 +++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/compiler/code_generator.ts b/src/compiler/code_generator.ts index 136aa81d..6e638223 100644 --- a/src/compiler/code_generator.ts +++ b/src/compiler/code_generator.ts @@ -632,7 +632,15 @@ export class CodeGenerator { let idx: number; if (specialInitTargetAttr) { - idx = block!.insertData(`${fullExpression} === '${attrs[targetAttr]}'`, "attr"); + let targetExpr = targetAttr in attrs && `'${attrs[targetAttr]}'`; + if (!targetExpr && ast.attrs) { + // look at the dynamic attribute counterpart + const dynamicTgExpr = ast.attrs[`t-att-${targetAttr}`]; + if (dynamicTgExpr) { + targetExpr = compileExpr(dynamicTgExpr); + } + } + idx = block!.insertData(`${fullExpression} === ${targetExpr}`, "attr"); attrs[`block-attribute-${idx}`] = specialInitTargetAttr; } else if (hasDynamicChildren) { const bValueId = generateId("bValue"); diff --git a/tests/components/__snapshots__/t_model.test.ts.snap b/tests/components/__snapshots__/t_model.test.ts.snap index 411c7f65..4070e142 100644 --- a/tests/components/__snapshots__/t_model.test.ts.snap +++ b/tests/components/__snapshots__/t_model.test.ts.snap @@ -569,6 +569,36 @@ exports[`t-model directive t-model with dynamic values on select options in fore }" `; +exports[`t-model directive t-model with radio button group in t-foreach 1`] = ` +"function anonymous(app, bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, comment } = bdom; + let { prepareList, toNumber, withKey } = helpers; + + let block1 = createBlock(\`
\`); + let block3 = createBlock(\`\`); + + return function template(ctx, node, key = \\"\\") { + let hdlr1 = [ctx['getData'], ctx]; + ctx = Object.create(ctx); + const [k_block2, v_block2, l_block2, c_block2] = prepareList(ctx['options']);; + for (let i1 = 0; i1 < l_block2; i1++) { + ctx[\`opt\`] = v_block2[i1]; + const key1 = ctx['opt']; + let attr1 = new String((ctx['opt']) || \\"\\"); + let attr2 = ctx['opt']; + const bExpr1 = ctx['state']; + const expr1 = 'group'; + let attr3 = bExpr1[expr1] === ctx['opt']; + let hdlr2 = [(ev) => { bExpr1[expr1] = ev.target.value; }]; + c_block2[i1] = withKey(block3([attr1, attr2, attr3, hdlr2]), key1); + } + const b2 = list(c_block2); + return block1([hdlr1], [b2]); + } +}" +`; + exports[`t-model directive two inputs in a div alternating with a t-if 1`] = ` "function anonymous(app, bdom, helpers ) { diff --git a/tests/components/t_model.test.ts b/tests/components/t_model.test.ts index 940e4418..e1a978e3 100644 --- a/tests/components/t_model.test.ts +++ b/tests/components/t_model.test.ts @@ -644,4 +644,35 @@ describe("t-model directive", () => { const input = fixture.querySelector("input")!; await editInput(input, "Beam me up, Scotty"); }); + + test("t-model with radio button group in t-foreach", async () => { + expect.assertions(6); + const steps: string[] = []; + class SomeComponent extends Component { + static template = xml` +
+ + + +
+ `; + state = useState({ group: "scotty" }); + options = ["beam", "scotty"]; + + getData() { + steps.push(`group: ${this.state.group}`); + } + } + await mount(SomeComponent, fixture); + const divEl = fixture.querySelector("#get_data") as HTMLElement; + expect(fixture.querySelector("input:checked")!.getAttribute("id")).toBe("scotty"); + divEl.click(); + expect(steps).toEqual(["group: scotty"]); + fixture.querySelector("input")!.click(); + expect(steps).toEqual(["group: scotty", "group: beam"]); + await nextTick(); + expect(fixture.querySelector("input:checked")!.getAttribute("id")).toBe("beam"); + divEl.click(); + expect(steps).toEqual(["group: scotty", "group: beam", "group: beam"]); + }); });