Chapter 1: Fields and Views¶
In the previous chapter, we learned a range of skills, including how to create and use services, work with the Layout component, make the dashboard translatable, and lazy load a JavaScript library like Chart.js. Now, let's learn how to create new fields and views.
The solutions for each exercise of the chapter are hosted on the official Odoo tutorials repository. It is recommended not to look at them before trying the exercises.
Fields and views are among the most important concepts in the Odoo user interface. They are key to
many important user interactions, and should therefore work perfectly. In the context of the
JavaScript framework, fields are components specialized for visualizing/editing a specific field for
a given record. For example, a (Python) model may define a char field, which will be represented by
a field component CharField.
A field component is basically just a component registered in the fields registry. The field component may define some additional static keys (metadata), such
as displayName or supportedTypes, and the most important one: extractProps, which prepare the
base props received by the CharField.
Example: a simple field¶
Let us discuss a simplified implementation of a CharField. First, here is the template:
<t t-name="web.CharField" owl="1">
<t t-if="props.readonly">
<span t-esc="formattedValue" />
</t>
<t t-else="">
<input
class="o_input"
t-att-type="props.isPassword ? 'password' : 'text'"
t-att-placeholder="props.placeholder"
t-on-change="updateValue"
/>
</t>
</t>
It features a readonly mode and an edit mode, which is an input with a few attributes. Now, here is the JavaScript code:
export class CharField extends Component {
get formattedValue() {
return formatChar(this.props.value, { isPassword: this.props.isPassword });
}
updateValue(ev) {
let value = ev.target.value;
if (this.props.shouldTrim) {
value = value.trim();
}
this.props.update(value);
}
}
CharField.template = "web.CharField";
CharField.displayName = _lt("Text");
CharField.supportedTypes = ["char"];
CharField.extractProps = ({ attrs, field }) => {
return {
shouldTrim: field.trim && !archParseBoolean(attrs.password),
maxLength: field.size,
isPassword: archParseBoolean(attrs.password),
placeholder: attrs.placeholder,
};
};
registry.category("fields").add("char", CharField);
There are a few important things to notice:
The
CharFieldreceives its (raw) value in props. It needs to format it before displaying it.It receives an
updatefunction in its props, which is used by the field to notify the owner of the state that the value of this field has been changed. Note that the field does not (and should not) maintain a local state with its value. Whenever the change has been applied, it will come back (possibly after an onchange) by the way of the props.It defines an
extractPropsfunction. This is a step that translates generic standard props, specific to a view, to specialized props, useful to the component. This allows the component to have a better API, and may make it so that it is reusable.
Fields have to be registered in the fields registry. Once it's done, they can be used in some
views (namely: form, list, kanban) by using the widget attribute.
مثال
<field name="preview_moves" widget="account_resequence_widget"/>
1. An image_preview field¶
Each new order on the website will be created as an awesome_tshirt.order. This model has a
image_url field (of type char), which is currently only visible as a string. We want to be able
to see the image itself in the form view.
تمرین
Create a new
ImagePreviewcomponent and register it in the proper registry. Use theCharFieldcomponent in your template. You can use t-props to pass props received byImagePreviewtoCharField. Update the arch of the form view to use your new field by setting thewidgetattribute.Change the code of the
ImagePreviewcomponent so that the image is displayed below the URL.When the field is readonly, only the image should be displayed and the URL should be hidden.
توجه
It is possible to solve this exercise by inheriting CharField, but the goal of this exercise is
to create a field from scratch.
همچنین ببینید
2. Improving the image_preview field¶
We want to improve the field of the previous task to help the staff recognize orders for which some action should be done.
تمرین
Display a warning "MISSING TSHIRT DESIGN" in red if there is no image URL specified on the order.
3. Customizing a field component¶
Let's see how to use inheritance to extend an existing component.
There is a is_late, readonly, boolean field on the order model. That would be useful information
to see on the list/kanban/view. Then, let us say that we want to add a red word "Late!" next to it
whenever it is set to true.
تمرین
Create a new
LateOrderBooleanfield inheriting fromBooleanField. The template ofLateOrderBooleancan also inherit from theBooleanFieldtemplate.Use it in the list/kanban/form view.
Modify it to add a red
Latenext to it, as requested.
همچنین ببینید
4. Message for some customers¶
Odoo form views support a widget API, which is like a field, but more generic. It is useful to
insert arbitrary components in the form view. Let us see how we can use it.
تمرین
For a super efficient workflow, we would like to display an alert block with specific messages depending on some conditions:
If the
image_urlfield is not set, it should display "No image".If the
amountof the order is higher than 100 euros, it should display "Add promotional material".Make sure that your widget is updated in real time.
نکته
Try to evaluate props.record in the Console tab of your browser's dev tools.
5. Use markup¶
Let’s see how we can display raw HTML in a template. The t-out directive can be used for that
propose. Indeed, it generally acts like t-esc, unless the data has been marked explicitly with a
markup function. In that case, its value
is injected as HTML.
تمرین
Modify the previous exercise to put the
imageandmaterialwords in bold.The warnings should be markuped, and the template should be modified to use
t-out.Import the
markupfunction from Owl and, for each message, replace it with a call of the function with the message passed as argument.
توجه
This is an example of a safe use of t-out, since the string is static.
7. Auto-reload the kanban view¶
Bafien is upset: he wants to see the kanban view of the tshirt orders on his external monitor, but the view needs to be up-to-date. He is tired of clicking on the refresh icon every 30s, so he tasked you to find a way to do it automatically.
Just like the previous exercise, that kind of customization requires creating a new JavaScript view.
تمرین
Extend the kanban view/controller to reload its data every minute.
Register it in the view registry, under
awesome_tshirt.autoreloadkanban.Use it in the arch of the kanban view (with the
js_classattribute).
مهم
If you use setInterval or something similar, make sure that it is properly canceled when your
component is unmounted. Otherwise, you will introduce a memory leak.