Development Book V17: New View Creation

We all know that views are used to describe records to users. The user cannot get the information correctly without an appropriate vision. Odoo's view includes form, tree, kanban, graph, pivot, calendar, dashboard, search, grid, cohort, and many more.

Adding a new view is a more sophisticated topic. This guide focuses primarily on the most important stages.

1. Create the controller.

A controller's major function is to assist coordination between multiple view components such as the Renderer, Model, and Layout.

Create custom_controller.js

/** @odoo-module */

import { Layout } from "@web/search/layout";
import { useService } from "@web/core/utils/hooks";
import { Component, onWillStart, useState} from "@odoo/owl";

export class CustomController extends Component {
   setup() {
       this.orm = useService("orm");

       // The controller create the model and make it reactive so whenever this.model is
       // accessed and edited then it'll cause a rerendering
       this.model = useState(
           new this.props.Model(
               this.orm,
               this.props.resModel,
               this.props.fields,
               this.props.archInfo,
               this.props.domain
           )
       );

       onWillStart(async () => {
           await this.model.load();
       });
   }
}

CustomController.template = "custom_view.View";
CustomController.components = { Layout };

The Controller template shows the control panel with Layout as well as the renderer.

Create custom_controller.xml

<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
   <t t-name="custom_view.View">
       <Layout display="props.display" className="'h-100 overflow-auto'">
           <t t-component="props.Renderer" records="model.records" propsYouWant="'Hello world'"/>
       </Layout>
   </t>
</templates>

2. Create the renderer.

Create custom_renderer.js

A renderer's principal role is to provide a visual representation of data by displaying the view that contains records.

/** @odoo-module */

import { Component } from "@odoo/owl";

export class CustomRenderer extends Component {}

CustomRenderer.template = "custom_view.Renderer";

Create custom_renderer.xml


    <?xml version="1.0" encoding="UTF-8"?>
    <templates xml:space="preserve">
       <t t-name="my_module.Renderer">
           <t t-esc="props.propsYouWant"/>
       </t>
    </templates>

3. Create the model.

The model's function is to retrieve and handle all of the data required in the view.

Create custom_model.js

/** @odoo-module */

import { KeepLast } from "@web/core/utils/concurrency";

export class CustomModel {
   constructor(orm, resModel, fields, archInfo, domain) {
       this.orm = orm;
       this.resModel = resModel;
       // We can access arch information parsed by the beautiful arch parser
       const { fieldFromTheArch } = archInfo;
       this.fieldFromTheArch = fieldFromTheArch;
       this.fields = fields;
       this.domain = domain;
       this.keepLast = new KeepLast();
   }

   async load() {
       // The keeplast protect against concurrency call
       const { length, records } = await this.keepLast.add(
           this.orm.webSearchRead(this.resModel, this.domain, [this.fieldsFromTheArch], {})
       );
              this.records = records;
       this.recordsLength = length;
   }
}

4. Create the arch parser.

The arch parser's function is to parse the arch view so that the view may access the information.

Create custom_arch_parser.js

/** @odoo-module */

import { XMLParser } from "@web/core/utils/xml";

export class GanttArchParser {
   parse(arch) {
       const xmlDoc = this.parseXML(arch);
       const fieldFromTheArch = xmlDoc.getAttribute("fieldFromTheArch");
       return {
           fieldFromTheArch,
       };
   }
}

5. Create the view by assembling all of its components, and then registering it in the views registry.

Create custom_view.js

/** @odoo-module */

import { registry } from "@web/core/registry";
import { CustomController } from "./custom_controller";
import { CustomArchParser } from "./custom_arch_parser";
import { CustomModel } from "./custom_model";
import { CustomRenderer } from "./custom_renderer";

export const customView = {
   type: "custom_view",
   display_name: "Custom",
   icon: "fa fa-picture-o", // the icon that will be displayed in the Layout panel
   multiRecord: true,
   Controller: CustomController,
   ArchParser: CustomArchParser,
   Model: CustomModel,
   Renderer: CustomRenderer,

   props(genericProps, view) {
       const { ArchParser } = view;
       const { arch } = genericProps;
       const archInfo = new ArchParser().parse(arch);

       return {
           ...genericProps,
           Model: view.Model,
           Renderer: view.Renderer,
           archInfo,
       };
   },
};

registry.category("views").add("custom_view", customView);

6. Add it to the manifest file

'assets': {
   'web.assets_backend': [
       'custom_view/static/src/js/custom_arch_parser.js',
       'custom_view/static/src/js/custom_controller.js',
       'custom_view/static/src/js/custom_model.js',
       'custom_view/static/src/js/custom_renderer.js',
       'custom_view/static/src/js/custom_view.js',
       'custom_view/static/src/xml/custom_controller.xml',
       'custom_view/static/src/xml/custom_renderer.xml',
   ],
},

7. Add the created view to the view mode


    from odoo import fields, models

    class IrActionsActWindowView(models.Model):
   _inherit = 'ir.actions.act_window.view'

   view_mode = fields.Selection(
       selection_add=[('custom_view', "Custom")],
       ondelete={'custom_view': 'cascade'}
   )

8. Add to the type in ir.ui.view

class IrUiView(models.Model):
   _inherit = 'ir.ui.view'

   type = fields.Selection(
       selection_add=[('custom_view', "Custom")]
   )

Now let’s check how to add the custom_view to view lists. Here we are adding to the My tasks view in Project module of Odoo

 
<record id="project_task_custom_view" model="ir.ui.view">
    <field name="name">project.task.custom_view</field>
    <field name="model">project.task</field>
    <field name="arch" type="xml">
        <custom_view/>
    </field>
 </record>
 
 <record id="action_view_all_task"
        model="ir.actions.act_window">
    <field name="view_mode">kanban,tree,form,custom_view</field>
 </record>
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