mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] compiler: t-model supports radio group in t-foreach
Have a radio group defined inside a t-foreach:
```xml
<t t-foreach="values" t-as="val" t-key="val">
<input name="radiogroup" t-att-value="val" t-model="state.radioGroup" />
</t>
```
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.
This commit is contained in:
committed by
Géry Debongnie
parent
a69f8a39e7
commit
cea82e945d
@@ -632,7 +632,15 @@ export class CodeGenerator {
|
|||||||
|
|
||||||
let idx: number;
|
let idx: number;
|
||||||
if (specialInitTargetAttr) {
|
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;
|
attrs[`block-attribute-${idx}`] = specialInitTargetAttr;
|
||||||
} else if (hasDynamicChildren) {
|
} else if (hasDynamicChildren) {
|
||||||
const bValueId = generateId("bValue");
|
const bValueId = generateId("bValue");
|
||||||
|
|||||||
@@ -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(\`<div id=\\"get_data\\" block-handler-0=\\"click\\"><block-child-0/></div>\`);
|
||||||
|
let block3 = createBlock(\`<input type=\\"radio\\" name=\\"radio_group\\" block-attribute-0=\\"value\\" block-attribute-1=\\"id\\" block-attribute-2=\\"checked\\" block-handler-3=\\"click\\"/>\`);
|
||||||
|
|
||||||
|
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`] = `
|
exports[`t-model directive two inputs in a div alternating with a t-if 1`] = `
|
||||||
"function anonymous(app, bdom, helpers
|
"function anonymous(app, bdom, helpers
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -644,4 +644,35 @@ describe("t-model directive", () => {
|
|||||||
const input = fixture.querySelector("input")!;
|
const input = fixture.querySelector("input")!;
|
||||||
await editInput(input, "Beam me up, Scotty");
|
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`
|
||||||
|
<div t-on-click="getData" id="get_data">
|
||||||
|
<t t-foreach="options" t-as="opt" t-key="opt">
|
||||||
|
<input type="radio" name="radio_group" t-model="state.group" t-att-value="opt" t-att-id="opt"/>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
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"]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user