});
Finally, if a widget does not logically have a parent (ie: because it’s the first widget you instantiate in an application), you can give null as a parent instead:
new instance.oepetstore.GreetingsWidget(null);
4.4.4 Destroying Widgets
If you can display content to your users, you should also be able to erase it. This can simply be done using the destroy()method:
greeting.destroy();
When a widget is destroyed it will first call destroy() on all its children. Then it erases itself from the DOM. The recursive call to destroy from parents to children is very useful to clean properly complex structures of widgets and avoid memory leaks that can easily appear in big JavaScript applications.
4.5 The QWeb Template Engine
The previous part of the guide showed how to define widgets that are able to display HTML to the user. The example GreetingsWidgetused a syntax like this:
this.$el.append("<div>Hello dear OpenERP user!</div>");
This technically allow use to display any HTML, even it is very complex and require to be generated by code. Although generating text using pure JavaScript is not very nice, that would necessitate to copy-paste a lot of HTML lines inside our JavaScript source file, add the " character at the beginning and the end of each line, etc...
The problem is exactly the same in most programming languages needing to generate HTML. That’s why they typically use template engines. Example of template engines are Velocity, JSP (Java), Mako, Jinja (Python), Smarty (PHP), etc...
In OpenERP we use a template engine developed specifically for OpenERP’s web client. Its name is QWeb.
QWeb is an XML-based templating language, similar toGenshi,ThymeleaforFaceletswith a few peculiarities:
• It’s implemented fully in JavaScript and rendered in the browser.
• Each template file (XML files) contains multiple templates, where template engine usually have a 1:1 mapping between template files and templates.
• It has special support in OpenERP Web’s instance.web.Widget, though it can be used outside of Open-ERP’s web client (and it’s possible to use instance.web.Widget without relying on QWeb).
The rationale behind using QWeb instead of existing javascript template engines is that its extension mechanism is very similar to the OpenERP view inheritance mechanism. Like OpenERP views a QWeb template is an XML tree and therefore XPath or DOM manipulations are easy to performs on it.
34 Chapter 4. OpenERP Web Framework
OpenERP Web Training, Release 1.0
4.5.1 Using QWeb inside a Widget
First let’s define a simple QWeb template in oepetstore/static/src/xml/petstore.xml file, the exact meaning will be explained later:
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="HomePageTemplate">
<div style="background-color: red;">This is some simple HTML</div>
</t>
</templates>
Now let’s modify the HomePage class. Remember that enigmatic line at the beginning the the JavaScript source file?
var QWeb = instance.web.qweb;
This is a line we recommend to copy-paste in all OpenERP web modules. It is the object giving access to all templates defined in template files that were loaded by the web client. We can use the template we defined in our XML template file like this:
Calling the QWeb.render() method asks to render the template identified by the string passed as first parameter.
Another possibility commonly seen in OpenERP code is to use Widget‘s integration with QWeb:
instance.oepetstore.HomePage = instance.web.Widget.extend({
When you put a template class attribute in a widget, the widget knows it has to call QWeb.render() to render that template.
Please note there is a difference between those two syntaxes. When you use Widget‘s QWeb integration the QWeb.render()method is called before the widget calls start(). It will also take the root element of the rendered template and put it as a replacement of the default root element generated by the Widget class. This will alter the behavior, so you should remember it.
QWeb Context
Like with all template engines, QWeb templates can contain code able to manipulate data that is given to the template.
To pass data to QWeb, use the second argument to QWeb.render():
<t t-name="HomePageTemplate">
<div>Hello <t t-esc="name"/></div>
</t>
QWeb.render("HomePageTemplate", {name: "Nicolas"});
Result:
4.5. The QWeb Template Engine 35
<div>Hello Nicolas</div>
When you use Widget‘s integration you can not pass additional data to the template. Instead the template will have a unique widget variable which is a reference to the current widget:
<t t-name="HomePageTemplate">
<div>Hello <t t-esc="widget.name"/></div>
</t>
instance.oepetstore.HomePage = instance.web.Widget.extend({
template: "HomePageTemplate", init: function(parent) {
this._super(parent);
this.name = "Nicolas";
},
start: function() { },
});
Result:
:: <div>Hello Nicolas</div>
Template Declaration
Now that we know everything about rendering templates we can try to understand QWeb’s syntax.
All QWeb directives use XML attributes beginning with the prefix t-. To declare new templates, we add a <t t-name="...">element into the XML template file inside the root element <template>:
<templates>
<t t-name="HomePageTemplate">
<div>This is some simple HTML</div>
</t>
</templates>
t-namesimply declares a template that can be called using QWeb.render().
Escaping
To put some text in the HTML, use t-esc:
<t t-name="HomePageTemplate">
<div>Hello <t t-esc="name"/></div>
</t>
This will output the variable name and escape its content in case it contains some characters that looks like HTML.
Please note the attribute t-esc can contain any type of JavaScript expression:
<t t-name="HomePageTemplate">
<div><t t-esc="3+5"/></div>
</t>
Will render:
<div>8</div>
36 Chapter 4. OpenERP Web Framework
OpenERP Web Training, Release 1.0
Outputting HTML
If you know you have some HTML contained in a variable, use t-raw instead of t-esc:
<t t-name="HomePageTemplate">
<div><t t-raw="some_html"/></div>
</t>
If
The basic alternative block of QWeb is t-if:
<t t-name="HomePageTemplate">
Although QWeb does not contains any structure for else.
Foreach
To iterate on a list, use t-foreach and t-as:
<t t-name="HomePageTemplate">
Setting the Value of an XML Attribute
QWeb has a special syntax to set the value of an attribute. You must use t-att-xxx and replace xxx with the name of the attribute:
To Learn More About QWeb
This guide does not pretend to be a reference for QWeb, please see the documentation for more information:
https://doc.openerp.com/trunk/web/qweb/.
4.5. The QWeb Template Engine 37
Exercise
Exercise - Usage of QWeb in Widgets
Create a widget whose constructor contains two parameters aside from parent: product_names and color. product_names is a list of strings, each one being a name of product. color is a string con-taining a color in CSS color format (ie: #000000 for black). That widget should display the given product names one under the other, each one in a separate box with a background color with the value of color and a border. You must use QWeb to render the HTML. This exercise will necessitate some CSS that you should put in oepetstore/static/src/css/petstore.css. Display that widget in the HomePage widget with a list of five products and green as the background color for boxes.
Solution:
var products = new instance.oepetstore.ProductsWidget(this, ["cpu", "mouse", "keyboard", "graphic card", "screen"], "#00FF00");
products.appendTo(this.$el);
}, });
instance.oepetstore.ProductsWidget = instance.web.Widget.extend({
template: "ProductsWidget",
init: function(parent, products, color) { this._super(parent);
<span class="oe_products_item" t-att-style="’background-color: ’ + widget.color + ’;’"><t t-esc="product"/></span><br/>
</t>
38 Chapter 4. OpenERP Web Framework
OpenERP Web Training, Release 1.0
border-radius: 3px;
}