diff --git a/doc/learning/tutorial_todoapp.md b/doc/learning/tutorial_todoapp.md index 17a85a55..7f606a0a 100644 --- a/doc/learning/tutorial_todoapp.md +++ b/doc/learning/tutorial_todoapp.md @@ -174,9 +174,9 @@ class Root extends Component { ``` The template contains a [`t-foreach`](../reference/templates.md#loops) loop to iterate -through the tasks. It can find the `tasks` list from the component, since the -component is the rendering context. Note that we use the `id` of each task as a -`t-key`, which is very common. There are two css classes: `task-list` and `task`, +through the tasks. It can find the `tasks` list from the component, since the rendering +context contains the properties of the component. Note that we use the `id` of each task +as a `t-key`, which is very common. There are two css classes: `task-list` and `task`, that we will use in the next section. Finally, notice the use of the `t-att-checked` attribute: diff --git a/doc/reference/templates.md b/doc/reference/templates.md index 1cd613ca..73143d66 100644 --- a/doc/reference/templates.md +++ b/doc/reference/templates.md @@ -115,7 +115,7 @@ It is useful to explain the various rules that apply on these expressions:

NOT valid

``` -2. it can use anything in the rendering context (typically, the component): +2. it can use anything in the rendering context (which typically contains the properties of the component): ```xml

Happy bithday!

@@ -541,9 +541,8 @@ This can be used to define variables scoped to a sub template: ``` Note: by default, the rendering context for a sub template is simply the current -rendering context (so, the current component). However, it may be useful to be -able to specify a specific object as context. This can be done by using the -`t-call-context` directive: +rendering context. However, it may be useful to be able to specify a specific +object as context. This can be done by using the `t-call-context` directive: ```xml diff --git a/src/compiler/inline_expressions.ts b/src/compiler/inline_expressions.ts index adcde781..d9e866b1 100644 --- a/src/compiler/inline_expressions.ts +++ b/src/compiler/inline_expressions.ts @@ -28,7 +28,7 @@ import { OwlError } from "../runtime/error_handling"; //------------------------------------------------------------------------------ const RESERVED_WORDS = - "true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,this,eval,void,Math,RegExp,Array,Object,Date".split( + "true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,eval,void,Math,RegExp,Array,Object,Date".split( "," ); diff --git a/src/runtime/component_node.ts b/src/runtime/component_node.ts index aa4ec0c3..d94452ad 100644 --- a/src/runtime/component_node.ts +++ b/src/runtime/component_node.ts @@ -114,7 +114,8 @@ export class ComponentNode

implements VNodelucas

\`); return function template(ctx, node, key = \\"\\") { - const v1 = ctx['value']; - let hdlr1 = [()=>this.update(v1), ctx]; + const v1 = ctx['this']; + const v2 = ctx['value']; + let hdlr1 = [()=>v1.update(v2), ctx]; return block1([hdlr1]); } }" diff --git a/tests/compiler/event_handling.test.ts b/tests/compiler/event_handling.test.ts index c79e2d08..11b98738 100644 --- a/tests/compiler/event_handling.test.ts +++ b/tests/compiler/event_handling.test.ts @@ -284,6 +284,9 @@ describe("t-on", () => { expect(this).toBe(owner); expect(val).toBe(444); }, + get this() { + return owner; + }, value: 444, }; diff --git a/tests/components/__snapshots__/error_handling.test.ts.snap b/tests/components/__snapshots__/error_handling.test.ts.snap index c61822c0..4cea9784 100644 --- a/tests/components/__snapshots__/error_handling.test.ts.snap +++ b/tests/components/__snapshots__/error_handling.test.ts.snap @@ -940,9 +940,10 @@ exports[`can catch errors catching error, rethrow, render parent -- a main comp for (let i1 = 0; i1 < l_block1; i1++) { ctx[\`cp\`] = v_block1[i1]; const key1 = ctx['cp'].id; - const v1 = ctx['cp']; + const v1 = ctx['this']; + const v2 = ctx['cp']; const ctx1 = capture(ctx); - c_block1[i1] = withKey(comp2({onError: ()=>this.cleanUp(v1.id),slots: markRaw({'default': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__2__\${key1}\`, node, this, null), key1); + c_block1[i1] = withKey(comp2({onError: ()=>v1.cleanUp(v2.id),slots: markRaw({'default': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__2__\${key1}\`, node, this, null), key1); } return list(c_block1); } @@ -1014,13 +1015,14 @@ exports[`can catch errors catching in child makes parent render 1`] = ` return function template(ctx, node, key = \\"\\") { ctx = Object.create(ctx); - const [k_block1, v_block1, l_block1, c_block1] = prepareList(Object.entries(this.elements));; + const [k_block1, v_block1, l_block1, c_block1] = prepareList(Object.entries(ctx['this'].elements));; for (let i1 = 0; i1 < l_block1; i1++) { ctx[\`elem\`] = v_block1[i1]; const key1 = ctx['elem'][0]; - const v1 = ctx['elem']; + const v1 = ctx['this']; + const v2 = ctx['elem']; const ctx1 = capture(ctx); - c_block1[i1] = withKey(comp2({onError: (_error)=>this.onError(v1[0],_error),slots: markRaw({'default': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__2__\${key1}\`, node, this, null), key1); + c_block1[i1] = withKey(comp2({onError: (_error)=>v1.onError(v2[0],_error),slots: markRaw({'default': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__2__\${key1}\`, node, this, null), key1); } return list(c_block1); } @@ -1155,7 +1157,7 @@ exports[`can catch errors onError in class inheritance is called if rethrown 2`] return function template(ctx, node, key = \\"\\") { let b2,b3; if (!ctx['state'].error) { - b2 = text(this.will.crash); + b2 = text(ctx['this'].will.crash); } else { b3 = text(ctx['state'].error); } @@ -1186,7 +1188,7 @@ exports[`can catch errors onError in class inheritance is not called if no rethr return function template(ctx, node, key = \\"\\") { let b2,b3; if (!ctx['state'].error) { - b2 = text(this.will.crash); + b2 = text(ctx['this'].will.crash); } else { b3 = text(ctx['state'].error); } @@ -1218,7 +1220,7 @@ exports[`errors and promises a rendering error in a sub component will reject th let block1 = createBlock(\`
\`); return function template(ctx, node, key = \\"\\") { - let txt1 = this.will.crash; + let txt1 = ctx['this'].will.crash; return block1([txt1]); } }" @@ -1232,7 +1234,7 @@ exports[`errors and promises a rendering error will reject the mount promise 1`] let block1 = createBlock(\`
\`); return function template(ctx, node, key = \\"\\") { - let txt1 = this.will.crash; + let txt1 = ctx['this'].will.crash; return block1([txt1]); } }" @@ -1277,7 +1279,7 @@ exports[`errors and promises a rendering error will reject the render promise 1` return function template(ctx, node, key = \\"\\") { let b2; if (ctx['flag']) { - b2 = text(this.will.crash); + b2 = text(ctx['this'].will.crash); } return block1([], [b2]); } diff --git a/tests/components/__snapshots__/slots.test.ts.snap b/tests/components/__snapshots__/slots.test.ts.snap index 4eab0079..cf61d22a 100644 --- a/tests/components/__snapshots__/slots.test.ts.snap +++ b/tests/components/__snapshots__/slots.test.ts.snap @@ -1992,7 +1992,8 @@ exports[`slots slot content is bound to caller (variation) 1`] = ` ctx = Object.create(ctx); ctx[isBoundary] = 1 setContextValue(ctx, \\"var\\", 1); - let hdlr1 = [()=>this.inc(), ctx]; + const v1 = ctx['this']; + let hdlr1 = [()=>v1.inc(), ctx]; return block1([hdlr1]); } @@ -2359,7 +2360,8 @@ exports[`slots slots are properly bound to correct component 2`] = ` ctx = Object.create(ctx); ctx[isBoundary] = 1 setContextValue(ctx, \\"var\\", 1); - let hdlr1 = [()=>this.increment(), ctx]; + const v1 = ctx['this']; + let hdlr1 = [()=>v1.increment(), ctx]; let txt1 = ctx['state'].value; return block1([hdlr1, txt1]); } diff --git a/tests/components/__snapshots__/style_class.test.ts.snap b/tests/components/__snapshots__/style_class.test.ts.snap index cafd236a..77665f4d 100644 --- a/tests/components/__snapshots__/style_class.test.ts.snap +++ b/tests/components/__snapshots__/style_class.test.ts.snap @@ -363,7 +363,7 @@ exports[`style and class handling error in subcomponent with class 2`] = ` return function template(ctx, node, key = \\"\\") { let attr1 = ctx['props'].class; - let txt1 = this.will.crash; + let txt1 = ctx['this'].will.crash; return block1([attr1, txt1]); } }" diff --git a/tests/components/__snapshots__/t_call.test.ts.snap b/tests/components/__snapshots__/t_call.test.ts.snap index f56af038..7cffa0ae 100644 --- a/tests/components/__snapshots__/t_call.test.ts.snap +++ b/tests/components/__snapshots__/t_call.test.ts.snap @@ -109,7 +109,8 @@ exports[`t-call handlers are properly bound through a dynamic t-call 2`] = ` let block1 = createBlock(\`

lucas

\`); return function template(ctx, node, key = \\"\\") { - let hdlr1 = [()=>this.update(), ctx]; + const v1 = ctx['this']; + let hdlr1 = [()=>v1.update(), ctx]; return block1([hdlr1]); } }" @@ -168,8 +169,9 @@ exports[`t-call handlers with arguments are properly bound through a t-call 2`] let block1 = createBlock(\`

lucas

\`); return function template(ctx, node, key = \\"\\") { - const v1 = ctx['a']; - let hdlr1 = [()=>this.update(v1), ctx]; + const v1 = ctx['this']; + const v2 = ctx['a']; + let hdlr1 = [()=>v1.update(v2), ctx]; return block1([hdlr1]); } }" @@ -287,7 +289,7 @@ exports[`t-call recursive t-call binding this -- static t-call 2`] = ` ctx[isBoundary] = 1 let b2; if (ctx['level']<2) { - let hdlr1 = [\\"stop\\", ctx['onClicked'].bind(this), ctx]; + let hdlr1 = [\\"stop\\", ctx['onClicked'].bind(ctx['this']), ctx]; let txt1 = ctx['level']; const b3 = block3([hdlr1, txt1]); ctx = Object.create(ctx); @@ -538,7 +540,6 @@ exports[`t-call t-call-context: ComponentNode is not looked up in the context 2` let block2 = createBlock(\`
outside slot
\`); let block4 = createBlock(\`
I'm the default slot
\`); let block5 = createBlock(\`
\`); - let block6 = createBlock(\`
\`); function slot1(ctx, node, key = \\"\\") { const refs = this.__owl__.refs; @@ -547,11 +548,9 @@ exports[`t-call t-call-context: ComponentNode is not looked up in the context 2` ctx[isBoundary] = 1 const b4 = block4([ref2]); setContextValue(ctx, \\"test\\", 3); - let txt1 = this.__owl__.name; + let txt1 = ctx['test']; const b5 = block5([txt1]); - let txt2 = ctx['test']; - const b6 = block6([txt2]); - return multi([b4, b5, b6]); + return multi([b4, b5]); } return function template(ctx, node, key = \\"\\") { @@ -559,8 +558,8 @@ exports[`t-call t-call-context: ComponentNode is not looked up in the context 2` const ref1 = (el) => refs[\`myRef\`] = el; const b2 = block2([ref1]); const ctx1 = capture(ctx); - const b7 = comp1({prop: bind(this, ctx['method']),slots: markRaw({'default': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null); - return multi([b2, b7]); + const b6 = comp1({prop: bind(this, ctx['method']),slots: markRaw({'default': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__1\`, node, this, null); + return multi([b2, b6]); } }" `; @@ -624,3 +623,27 @@ exports[`t-call t-call-context: slots don't make component available again when } }" `; + +exports[`t-call t-call-context: this is not available inside t-call-context 1`] = ` +"function anonymous(app, bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, comment } = bdom; + const callTemplate_1 = app.getTemplate(\`someTemplate\`); + + return function template(ctx, node, key = \\"\\") { + let ctx1 = {}; + return callTemplate_1.call(this, ctx1, node, key + \`__1\`); + } +}" +`; + +exports[`t-call t-call-context: this is not available inside t-call-context 2`] = ` +"function anonymous(app, bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, comment } = bdom; + + return function template(ctx, node, key = \\"\\") { + return text(ctx['this']); + } +}" +`; diff --git a/tests/components/__snapshots__/t_on.test.ts.snap b/tests/components/__snapshots__/t_on.test.ts.snap index 5b30afd3..9d710f37 100644 --- a/tests/components/__snapshots__/t_on.test.ts.snap +++ b/tests/components/__snapshots__/t_on.test.ts.snap @@ -111,8 +111,9 @@ exports[`t-on t-on method call in t-foreach 1`] = ` const key1 = ctx['val']; let txt1 = ctx['val_index']; let txt2 = ctx['val']+''; - const v1 = ctx['val']; - let hdlr1 = [()=>this.addVal(v1), ctx]; + const v1 = ctx['this']; + const v2 = ctx['val']; + let hdlr1 = [()=>v1.addVal(v2), ctx]; c_block2[i1] = withKey(block3([txt1, txt2, hdlr1]), key1); } const b2 = list(c_block2); @@ -197,8 +198,9 @@ exports[`t-on t-on on components and t-foreach 1`] = ` for (let i1 = 0; i1 < l_block1; i1++) { ctx[\`name\`] = v_block1[i1]; const key1 = ctx['name']; - const v1 = ctx['name']; - const hdlr1 = [()=>this.log(v1), ctx]; + const v1 = ctx['this']; + const v2 = ctx['name']; + const hdlr1 = [()=>v1.log(v2), ctx]; c_block1[i1] = withKey(catcher1(comp1({value: ctx['name']}, key + \`__1__\${key1}\`, node, this, null), [hdlr1]), key1); } return list(c_block1); @@ -293,8 +295,9 @@ exports[`t-on t-on on components, with a handler update 1`] = ` ctx = Object.create(ctx); ctx[isBoundary] = 1 setContextValue(ctx, \\"name\\", ctx['state'].name); - const v1 = ctx['name']; - const hdlr1 = [()=>this.log(v1), ctx]; + const v1 = ctx['this']; + const v2 = ctx['name']; + const hdlr1 = [()=>v1.log(v2), ctx]; return catcher1(comp1({value: ctx['name']}, key + \`__1\`, node, this, null), [hdlr1]); } }" @@ -393,7 +396,8 @@ exports[`t-on t-on on t-set-slots 1`] = ` function slot1(ctx, node, key = \\"\\") { const b6 = block6(); const b7 = block7(); - const hdlr1 = [()=>this.state.count++, ctx]; + const v1 = ctx['this']; + const hdlr1 = [()=>v1.state.count++, ctx]; return catcher1(multi([b6, b7]), [hdlr1]); } @@ -450,7 +454,8 @@ exports[`t-on t-on on t-slots 2`] = ` const b2 = text(\` [\`); const b3 = text(ctx['state'].count); const b4 = text(\`] \`); - const hdlr1 = [()=>this.state.count++, ctx]; + const v1 = ctx['this']; + const hdlr1 = [()=>v1.state.count++, ctx]; const b5 = catcher1(callSlot(ctx, node, key, 'default', false, {}), [hdlr1]); return multi([b2, b3, b4, b5]); } diff --git a/tests/components/t_call.test.ts b/tests/components/t_call.test.ts index 9a425677..3e70dd6e 100644 --- a/tests/components/t_call.test.ts +++ b/tests/components/t_call.test.ts @@ -345,14 +345,13 @@ describe("t-call", () => {
I'm the default slot
-
`, }); expect(fixture.innerHTML).toBe( - "
outside slot
I'm the default slot
Root
3
" + "
outside slot
I'm the default slot
3
" ); expect(Object.keys(child.__owl__.refs)).toEqual([]); expect(Object.keys(root.__owl__.refs)).toEqual(["myRef", "myRef2"]); @@ -383,4 +382,20 @@ describe("t-call", () => { }); expect(fixture.innerHTML).toBe(""); }); + + test("t-call-context: this is not available inside t-call-context", async () => { + class Root extends Component { + static template = xml``; + } + + await mount(Root, fixture, { + templates: ` + + + + + `, + }); + expect(fixture.innerHTML).toBe(""); + }); }); diff --git a/tests/misc/__snapshots__/portal.test.ts.snap b/tests/misc/__snapshots__/portal.test.ts.snap index 19b2f544..a920d8da 100644 --- a/tests/misc/__snapshots__/portal.test.ts.snap +++ b/tests/misc/__snapshots__/portal.test.ts.snap @@ -646,7 +646,7 @@ exports[`Portal portal destroys on crash 2`] = ` let block1 = createBlock(\`\`); return function template(ctx, node, key = \\"\\") { - let txt1 = ctx['props'].error&&this.will.crash; + let txt1 = ctx['props'].error&&ctx['this'].will.crash; return block1([txt1]); } }"