diff --git a/src/core/qweb_vdom.ts b/src/core/qweb_vdom.ts index cdc5686f..07e12dce 100644 --- a/src/core/qweb_vdom.ts +++ b/src/core/qweb_vdom.ts @@ -95,7 +95,8 @@ export default class QWeb { elseDirective, elifDirective, ifDirective, - callDirective + callDirective, + onDirective ].forEach(d => this.addDirective(d)); } @@ -170,6 +171,9 @@ export default class QWeb { * @param {string} name the template should already have been added */ render(name: string, context: any = {}): VNode { + if (!(name in this.rawTemplates)) { + throw new Error(`Template ${name} does not exist`); + } const template = this.templates[name] || this._compile(name); return template(context); } @@ -617,4 +621,22 @@ const forEachDirective: Directive = { ctx.addLine("}"); return true; } -}; \ No newline at end of file +}; + +const onDirective: Directive = { + name: "on", + priority: 90, + atNodeCreation({ ctx, fullName, value, nodeID }) { + const eventName = fullName.slice(5); + let extraArgs; + let handler = value.replace(/\(.*\)/, function(args) { + extraArgs = args.slice(1, -1); + return ""; + }); + ctx.addLine( + `p${nodeID}.on = {${eventName}: context['${handler}'].bind(context${ + extraArgs ? ", " + extraArgs : "" + })}` + ); + } +}; diff --git a/tests/qweb_vdom.test.ts b/tests/qweb_vdom.test.ts index f7207bc2..9b49e864 100644 --- a/tests/qweb_vdom.test.ts +++ b/tests/qweb_vdom.test.ts @@ -5,10 +5,14 @@ import sdListeners from "../src/libs/snabbdom/src/modules/eventlisteners"; const patch = init([sdAttributes, sdListeners]); -function qwebRender(qweb: QWeb, t: string, context: EvalContext = {}): string { +function renderToDOM(qweb: QWeb, t: string, context: EvalContext = {}): HTMLElement { const vnode = qweb.render(t, context); const node = document.createElement(vnode.sel!); patch(node, vnode); + return node; +} +function qwebRender(qweb: QWeb, t: string, context: EvalContext = {}): string { + const node = renderToDOM(qweb, t, context); return node.outerHTML; } @@ -54,6 +58,13 @@ describe("error handling", () => { "A template should have one root node" ); }); + + test("nice warning if no template with given name", () => { + const qweb = new QWeb(); + expect(() => qweb.render('invalidname')).toThrow('does not exist'); + }); + + }); describe("t-esc", () => { @@ -518,3 +529,28 @@ describe("misc", () => { expect(qwebRender(qweb, "caller").trim()).toBe(expected); }); }); + +describe("t-on", () => { + test("can bind event handler", () => { + const qweb = new QWeb(); + qweb.addTemplate('test', ``); + let a = 1; + const node = renderToDOM(qweb, 'test', { + add() { a = 3} + }); + node.click(); + expect(a).toBe(3); + }); + + test("can bind handlers with arguments", () => { + const qweb = new QWeb(); + qweb.addTemplate('test', ``); + let a = 1; + const node = renderToDOM(qweb, 'test', { + add(n) { a = a + n} + }); + node.click(); + expect(a).toBe(6); + }); +}); +