Development Book V18: OWL field

In this example, we are creating a custom widget and integrating it into a form view. Specifically, we are building a date picker widget that supports the selection of multiple dates.

To begin, we add a new Char field to the res.partner model, which will be used in conjunction with our custom widget. This field will store the selected date values. Once the field is added, we can proceed with defining the widget and linking it to the form view.

                       from odoo import fields, models
class ResPartner(models.Model):
   _inherit = 'res.partner'
   test_field = fields.Char() 
                       

Next, include the newly added field in the form view by updating the XML definition. This ensures the field appears in the user interface, where it can be rendered using the custom widget.

    <field name="test_field" widget="multiple_datepicker"/>

Next, define the QWeb template for the custom field widget. This template will determine how the widget is displayed in the user interface, allowing for the desired layout and interaction—for example, selecting multiple dates.

    
<?xml version="1.0" encoding="UTF-8"?>
<templates>
   <t t-name="DatePickerField" owl="1">
       <input type="text"
              class="input_datepicker o-autocomplete--input o_input"
              t-ref="inputdate"
              t-on-click="(ev) => this._onSelectDateField(ev)"/>
   </t>
</templates>
    

Next, we'll define the CSS styles for the widget to control its appearance and layout. This styling ensures that the widget is visually consistent with the rest of the interface and provides a user-friendly experience when selecting multiple dates.

                       .datepicker-dropdown {
   top: 0;
   left: 0;
   padding: 4px
}
.datepicker table tr td,
.datepicker table tr th {
   text-align: center;
   width: 30px;
   height: 30px;
   border: none
}
.datepicker table tr td.day:hover,
.datepicker table tr td.focused {
   background: #eee;
   cursor: pointer;
   border-radius: 18px;
}
.datepicker table tr td.active.active,
.datepicker table tr td.active.highlighted.active,
.datepicker table tr td.active.highlighted:active,
.datepicker table tr td.active:active {
   color: #fff;
   background-color: #7C7BAD;
   border-radius:18px;
   border-color: #7C7BAD;
   background-radius:11px;
}
.datepicker table tr td span {
   display: block;
   width: 23%;
   height: 54px;
   line-height: 54px;
   float: left;
   margin: 1%;
   cursor: pointer;
}
.datepicker table tr td span.active,
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active.disabled:hover,
.datepicker table tr td span.active:hover {
   color: #fff;
   background-color: #7C7BAD;
   border-color: #2e6da4;
   text-shadow: 0 -1px 0 rgba(0, 0, 0, .25)
}
.datepicker .datepicker-switch {
   width: 145px;
   background:#7C7BAD;
   color:white;
}
.datepicker .datepicker-switch,
.datepicker .next,
.datepicker .prev,
.datepicker tfoot tr th {
   cursor: pointer;
   background:#7C7BAD;
   color:white;
}


                       

Next, you need to define the widget as a component using OWL. This involves creating a JavaScript class that extends Component from OWL, where you’ll implement the logic for rendering the widget and handling user interactions, such as selecting and updating multiple dates.

/** @odoo-module **/
import { registry } from "@web/core/registry";
import { useInputField } from "@web/views/fields/input_field_hook";
import { Component,useRef } from "@odoo/owl";
import { _t } from "@web/core/l10n/translation";
import { standardFieldProps } from "@web/views/fields/standard_field_props";
export class DatePickerField extends Component {
   static template = 'DatePickerField'
   setup() {
       this.input = useRef("inputdate");
       useInputField({
           getValue: () => this.props.record.data[this.props.name] || "",
           refName: "inputdate"
       });
   }
   _onSelectDateField(ev) {
       var dateFormat = "MM/DD/YYYY";
       dateFormat = dateFormat.toLowerCase()
       if (this.input.el) {
           if (this.input.el.value) {
               this.props.record.update({
                   [this.props.name]: this.input.el.value
               })
               }
           $(this.input.el).datepicker({
               multidate: true,
               format: dateFormat,
           }).trigger('focus');
       }
   }
}
DatePickerField.props = {
   ...standardFieldProps,
}
export const datepickerField = {
   component: DatePickerField,
   supportedTypes: ["char"],
};
registry.category("fields").add("multiple_datepicker", datepickerField);



                       

Next, include the JavaScript, XML, and CSS files in your module’s __manifest__.py file to ensure they are loaded properly. Here's how you can define them:

                       'assets': {
   'web.assets_backend': [
       '/owl_test/static/src/scss/style.scss',
       '/owl_test/static/src/js/owl_test.js',
       '/owl_test/static/src/js/lib/bootstrap-datepicker.min.js',
       '/owl_test/static/src/xml/owl_test.xml',
   ],
},
                       

Now, the field is ready to support multiple date selections using the custom widget. Users can interact with the field to choose multiple dates, which will be reflected in the form view accordingly.

odoo-development

In this way, multiple dates can be added seamlessly using the DatePicker widget, enhancing the form's functionality with an interactive and user-friendly interface.

whatsapp_icon
location

Calicut

Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635

location

Kochi

Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.

location

Bangalore

Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message