[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.
The `t-on` directive allows to prebind some arguments. For example,
```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)
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
`event.preventDefault`) and let them focus on data logic, _modifiers_ can be
+10 -3
View File
@@ -1,8 +1,15 @@
# 🦉 Tags 🦉
## Content
- [Overview](#overview)
- [`xml` tag](#xml-tag)
## Overview
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,
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
@@ -31,8 +38,8 @@ With tags, this process is slightly simplified. The name is uniquely generated,
and the template is automatically registered:
```js
import { Component } from 'owl'
import { xml } from 'owl/tags'
const { Component } = owl;
const { xml } = owl.tags;
class MyComponent extends Component {
static template = xml`
+18 -4
View File
@@ -60,12 +60,21 @@ useful to compare various performance metrics on some tasks.
## Single File Component
If you want to have `xml` syntax highlighting while using the `xml` helper which
helps you define inline templates, there is a VS Code addon `Comment tagged template`
which, if installed, does exactly that. To enable it, you need to add a comment,
like this:
It is very useful to group code by feature instead of by type of file. It makes
it easier to scale application to larger size.
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
const { Component } = owl;
const { xml } = owl.tags;
// -----------------------------------------------------------------------------
// TEMPLATE
// -----------------------------------------------------------------------------
@@ -85,3 +94,8 @@ class MyComponent extends 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}];`);
} else {
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 += `}`;
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"/>
</div>`;
static components = { Child };
state = useState({counter: 0});
state = useState({ counter: 0 });
get handler() {
this.state.counter++;
return () => {};
@@ -2152,12 +2152,12 @@ describe("other directives with t-component", () => {
await parent.mount(fixture);
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];
child.trigger("ev");
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 () => {
@@ -2171,18 +2171,18 @@ describe("other directives with t-component", () => {
<Child t-on-ev="state.counter++"/>
</div>`;
static components = { Child };
state = useState({counter: 0});
state = useState({ counter: 0 });
}
const parent = new Parent(env);
await parent.mount(fixture);
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];
child.trigger("ev");
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 () => {
+7 -5
View File
@@ -1044,8 +1044,8 @@ describe("t-on", () => {
qweb.addTemplate("test", `<button t-on-click="state.counter++">Click</button>`);
let owner = {
state: {
counter: 0,
},
counter: 0
}
};
const node = renderToDOM(qweb, "test", owner, { handlers: [] });
expect(owner.state.counter).toBe(0);
@@ -1058,8 +1058,10 @@ describe("t-on", () => {
let owner = {
state: {
counter: 0,
incrementCounter: (inc) => { owner.state.counter += inc; },
},
incrementCounter: inc => {
owner.state.counter += inc;
}
}
};
const node = renderToDOM(qweb, "test", owner, { handlers: [] });
expect(owner.state.counter).toBe(0);
@@ -1223,7 +1225,7 @@ describe("t-on", () => {
);
const node = renderToDOM(qweb, "test", {}, { handlers: [] });
node.addEventListener('click', (e) => {
node.addEventListener("click", e => {
expect(e.defaultPrevented).toBe(true);
});