[DOC] add more info on xml tag and single file component

closes #401
This commit is contained in:
Géry Debongnie
2019-10-26 08:55:38 +02:00
parent e026f537ae
commit 9dfcfda365
6 changed files with 49 additions and 23 deletions
+5 -4
View File
@@ -677,7 +677,6 @@ to event `menu-loaded` will receive the payload in its `someMethod` handler
By convention, we use KebabCase for the name of _business_ events. By convention, we use KebabCase for the name of _business_ events.
The `t-on` directive allows to prebind some arguments. For example, The `t-on` directive allows to prebind some arguments. For example,
```xml ```xml
@@ -695,10 +694,12 @@ One can also directly specify inline statements. For example,
Here, `state` must be defined in the rendering context (typically the component) Here, `state` must be defined in the rendering context (typically the component)
as it will be translated to: as it will be translated to:
```js
button.addEventListener("click", () => { component.state.counter++; });
```
```js
button.addEventListener("click", () => {
component.state.counter++;
});
```
In order to remove the DOM event details from the event handlers (like calls to In order to remove the DOM event details from the event handlers (like calls to
`event.preventDefault`) and let them focus on data logic, _modifiers_ can be `event.preventDefault`) and let them focus on data logic, _modifiers_ can be
+10 -3
View File
@@ -1,8 +1,15 @@
# 🦉 Tags 🦉 # 🦉 Tags 🦉
## Content
- [Overview](#overview)
- [`xml` tag](#xml-tag)
## Overview
Tags are very small helpers to make it easy to write inline templates. There is Tags are very small helpers to make it easy to write inline templates. There is
only one currently available tag: `xml`, but we plan to add other tags later, only one currently available tag: `xml`, but we plan to add other tags later,
such as a `css` tag, which will be used to write single file components. such as a `css` tag, which will be used to write [single file components](tooling.md#single-file-component).
## XML tag ## XML tag
@@ -31,8 +38,8 @@ With tags, this process is slightly simplified. The name is uniquely generated,
and the template is automatically registered: and the template is automatically registered:
```js ```js
import { Component } from 'owl' const { Component } = owl;
import { xml } from 'owl/tags' const { xml } = owl.tags;
class MyComponent extends Component { class MyComponent extends Component {
static template = xml` static template = xml`
+18 -4
View File
@@ -60,12 +60,21 @@ useful to compare various performance metrics on some tasks.
## Single File Component ## Single File Component
If you want to have `xml` syntax highlighting while using the `xml` helper which It is very useful to group code by feature instead of by type of file. It makes
helps you define inline templates, there is a VS Code addon `Comment tagged template` it easier to scale application to larger size.
which, if installed, does exactly that. To enable it, you need to add a comment,
like this: To do so, Owl currently has a small helper that makes it easy to define a
template inside a javascript (or typescript) file: the [`xml`](tags.md#xml-tag)
helper. With this, a template is automatically registered to [QWeb](qweb.md).
This means that the template and the javascript code can be defined in the same
file. It is not currently possible to add css to the same file, but Owl may
get a `css` tag helper later.
```js ```js
const { Component } = owl;
const { xml } = owl.tags;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// TEMPLATE // TEMPLATE
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -85,3 +94,8 @@ class MyComponent extends Component {
// rest of component... // rest of component...
} }
``` ```
Note that the above example has an inline xml comment, just after the `xml` call.
This is useful for some editor plugins, such as the VS Code addon
`Comment tagged template`, which, if installed, add syntax highlighting to the
content of the template string.
+3 -1
View File
@@ -58,7 +58,9 @@ QWeb.addDirective({
ctx.addLine(`p${nodeID}.on['${eventName}'] = extra.handlers['${eventName}' + ${nodeID}];`); ctx.addLine(`p${nodeID}.on['${eventName}'] = extra.handlers['${eventName}' + ${nodeID}];`);
} else { } else {
const handlerKey = `handler${ctx.generateID()}`; const handlerKey = `handler${ctx.generateID()}`;
ctx.addLine(`const ${handlerKey} = context['${handlerName}'] && context['${handlerName}'].bind(${params});`); ctx.addLine(
`const ${handlerKey} = context['${handlerName}'] && context['${handlerName}'].bind(${params});`
);
handler += `if (${handlerKey}) { ${handlerKey}(e); } else { context.${value}; }`; handler += `if (${handlerKey}) { ${handlerKey}(e); } else { context.${value}; }`;
handler += `}`; handler += `}`;
ctx.addLine(`p${nodeID}.on['${eventName}'] = ${handler};`); ctx.addLine(`p${nodeID}.on['${eventName}'] = ${handler};`);
+6 -6
View File
@@ -2142,7 +2142,7 @@ describe("other directives with t-component", () => {
<Child t-on-ev="handler"/> <Child t-on-ev="handler"/>
</div>`; </div>`;
static components = { Child }; static components = { Child };
state = useState({counter: 0}); state = useState({ counter: 0 });
get handler() { get handler() {
this.state.counter++; this.state.counter++;
return () => {}; return () => {};
@@ -2152,12 +2152,12 @@ describe("other directives with t-component", () => {
await parent.mount(fixture); await parent.mount(fixture);
expect(env.qweb.templates[Parent.template].fn.toString()).toMatchSnapshot(); expect(env.qweb.templates[Parent.template].fn.toString()).toMatchSnapshot();
expect(fixture.innerHTML).toBe('<div>0<span></span></div>'); expect(fixture.innerHTML).toBe("<div>0<span></span></div>");
let child = children(parent)[0]; let child = children(parent)[0];
child.trigger("ev"); child.trigger("ev");
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe('<div>1<span></span></div>'); expect(fixture.innerHTML).toBe("<div>1<span></span></div>");
}); });
test("t-on with inline statement", async () => { test("t-on with inline statement", async () => {
@@ -2171,18 +2171,18 @@ describe("other directives with t-component", () => {
<Child t-on-ev="state.counter++"/> <Child t-on-ev="state.counter++"/>
</div>`; </div>`;
static components = { Child }; static components = { Child };
state = useState({counter: 0}); state = useState({ counter: 0 });
} }
const parent = new Parent(env); const parent = new Parent(env);
await parent.mount(fixture); await parent.mount(fixture);
expect(env.qweb.templates[Parent.template].fn.toString()).toMatchSnapshot(); expect(env.qweb.templates[Parent.template].fn.toString()).toMatchSnapshot();
expect(fixture.innerHTML).toBe('<div>0<span></span></div>'); expect(fixture.innerHTML).toBe("<div>0<span></span></div>");
let child = children(parent)[0]; let child = children(parent)[0];
child.trigger("ev"); child.trigger("ev");
await nextTick(); await nextTick();
expect(fixture.innerHTML).toBe('<div>1<span></span></div>'); expect(fixture.innerHTML).toBe("<div>1<span></span></div>");
}); });
test("t-on with no handler (only modifiers)", async () => { test("t-on with no handler (only modifiers)", async () => {
+7 -5
View File
@@ -1044,8 +1044,8 @@ describe("t-on", () => {
qweb.addTemplate("test", `<button t-on-click="state.counter++">Click</button>`); qweb.addTemplate("test", `<button t-on-click="state.counter++">Click</button>`);
let owner = { let owner = {
state: { state: {
counter: 0, counter: 0
}, }
}; };
const node = renderToDOM(qweb, "test", owner, { handlers: [] }); const node = renderToDOM(qweb, "test", owner, { handlers: [] });
expect(owner.state.counter).toBe(0); expect(owner.state.counter).toBe(0);
@@ -1058,8 +1058,10 @@ describe("t-on", () => {
let owner = { let owner = {
state: { state: {
counter: 0, counter: 0,
incrementCounter: (inc) => { owner.state.counter += inc; }, incrementCounter: inc => {
}, owner.state.counter += inc;
}
}
}; };
const node = renderToDOM(qweb, "test", owner, { handlers: [] }); const node = renderToDOM(qweb, "test", owner, { handlers: [] });
expect(owner.state.counter).toBe(0); expect(owner.state.counter).toBe(0);
@@ -1223,7 +1225,7 @@ describe("t-on", () => {
); );
const node = renderToDOM(qweb, "test", {}, { handlers: [] }); const node = renderToDOM(qweb, "test", {}, { handlers: [] });
node.addEventListener('click', (e) => { node.addEventListener("click", e => {
expect(e.defaultPrevented).toBe(true); expect(e.defaultPrevented).toBe(true);
}); });