Enable Dark Mode!
a-step-by-step-guide-for-creating-a-dynamic-modal-in-odoo-16.jpg
By: Aswin AK

A Step-by-Step Guide for Creating a Dynamic Modal in Odoo 16

Technical Odoo 16 Odoo Enterprises Odoo Community

Adding interactive elements like modals to your Odoo website can significantly enhance the user experience. Instead of forcing a user to navigate to a new page, you can display important information or collect data in a sleek pop-up window. In this blog post, we'll walk through how to create a reusable dynamic modal widget in Odoo 16, using a combination of Javascript and Qweb templates.

The Module Structure & Manifest File

Before we dive into the code, it's important to understand the file structure of a basic Odoo module. Your custom module, let's call it dynamic_modal, should have the following structure:

dynamic_modal/
+-- __init__.py
+-- __manifest__.py
+-- controllers/
¦   +-- __init__.py
¦   +-- main.py
+-- static/
¦   +-- src/
¦   Â¦   +-- js/
¦   Â¦   Â¦   +-- dynamic_modal.js
¦   Â¦   Â¦   +-- modal_starter.js
¦   Â¦   +-- xml/
¦   Â¦       +-- dynamic_modal_templates.xml
+-- views/
¦   +-- dynamic_modal_page.xml

The __manifest__.py file is the heart of your module, defining its metadata and dependencies. Here is what it should look like for our project:

{
    'name': "Dynamic Modal",
    'version': '16.0.1.0.0',
    'summary': 'A simple module to demonstrate dynamic modals on the website.',
    'sequence': 10,
    'description': """
        This module provides a basic example of how to create and use a dynamic
        modal pop-up on an Odoo website page.
    """,
    'category': 'Website/Website',
    'author': 'Your Name',
    'depends': ['website'],
    'data': [
        'views/dynamic_modal_page.xml',
    ],
    'assets': {
        'web.assets_frontend': [
            'dynamic_modal/static/src/js/dynamic_modal.js',
            'dynamic_modal/static/src/js/modal_starter.js',
            'dynamic_modal/static/src/xml/dynamic_modal_templates.xml',
        ],
    },
    'installable': True,
    'application': True,
    'license': 'LGPL-3',
}

The depends key is crucial as it tells Odoo that our module needs the website module to function. The data key lists our XML files, and the assets key ensures that our Javascript and Qweb template files are loaded on the website frontend.

The Javascript Widget: The Brains of the Operation

The core of our dynamic modal is a Javascript widget that handles all the logic. It defines how the modal looks, what it does when a button is clicked, and how it receives dynamic content.

Let's break down the code:

odoo.define('dynamic_modal.edit_modal', function (require) {
'use strict';
var publicWidget = require('web.public.widget');
const EditModal = publicWidget.Widget.extend({
    template: 'dynamic_modal.EditModal',
    events: {
        'click .confirm-button': '_onConfirm',
        'click .cancel-button': '_onCancel',
        'click .close': 'close',
    },
    init: function (parent, options) {
        this._super(parent);
        this.title = options.title || 'Title';
        this.confirmButtonText = options.confirmButtonText || 'Edit';
        this.cancelButtonText = options.cancelButtonText || 'Cancel';
    },
    start: function () {
        this.$modal = this.$el;
        this.$modal.modal('show');
        return this._super.apply(this, arguments);
    },
    _onConfirm: function () {
        // Handle confirm button click
        // Pass data from the modal back to the parent widget
        this.trigger_up('modal_confirm', {
            //pass the data here
        });
        this.close();
    },
    _onCancel: function () {
        // Handle cancel button click
        this.close();
    },
    close: function () {
        this.$modal.modal('hide');
        this.destroy();
    },
});
publicWidget.registry.EditModal = EditModal;
return EditModal;
});
  • publicWidget.Widget.extend: This line is crucial. It tells Odoo that our EditModal is a new website widget, inheriting from Odoo's base widget class.
  • template: 'dynamic_modal.EditModal': This links our Javascript to the Qweb template that defines the modal's HTML structure. We'll look at this next.
  • init function: This is where we make the modal dynamic. It accepts an options object, allowing us to pass in a title, confirmButtonText, and cancelButtonText when we create the widget.
  • start function: This function runs when the widget is initialized. It finds the modal element in the DOM and uses Bootstrap's .modal('show') to display it.
  • events: This maps a user action (like a click) to a Javascript function. For example, when a user clicks an element with the class confirm-button, the _onConfirm function is executed.
  • trigger_up('modal_confirm'): This is a powerful Odoo feature. It broadcasts an event up the widget hierarchy, allowing other parts of your code to listen for and react to the modal's confirmation.

The Qweb Template: The HTML Structure

The Qweb template defines the visual layout of our modal. It’s written in XML and uses special tags to render dynamic data from our Javascript widget.

<?xml version="1.0" encoding="UTF-8" ?>
<templates>
    <t t-name="dynamic_modal.EditModal">
        <div class="modal" tabindex="-1" role="dialog">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title"><t t-esc="widget.title"/> </h5>
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                            <span aria-hidden="true">&times;</span>
                        </button>
                    </div>
                    <div class="modal-body">
                        <p>Modal body text goes here.</p>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-primary confirm-button"><t t-esc="widget.confirmButtonText"/></button>
                        <button type="button" class="btn btn-secondary cancel-button" data-dismiss="modal"><t t-esc="widget.cancelButtonText"/>
                        </button>
                    </div>
                </div>
            </div>
        </div>
    </t>
</templates>

The key parts here are the <t t-esc="widget.title"/> and similar tags. They are placeholders that will be replaced with the values we passed to the Javascript widget's init function.

The Controller and Website Page

The controller is responsible for creating a new URL (/dynamic_modal) that will serve our website page. The page itself is a simple Odoo template.

from odoo import http
from odoo.http import request
class DynamicModalController(http.Controller):
    @http.route('/dynamic_modal', type='http', auth="public", website=True)
    def dynamic_modal_page(self, **kw):
        return request.render("dynamic_modal.dynamic_modal_page_template", {})

xml

<?xml version="1.0" encoding="UTF-8"?>
<odoo>
    <record id="menu_dynamic_modal" model="website.menu">
        <field name="name">Dynamic Modal</field>
        <field name="url">/dynamic_modal</field>
        <field name="parent_id" ref="website.main_menu"/>
        <field name="sequence" type="int">100</field>
    </record>
    <template id="dynamic_modal_page_template" name="Dynamic Modal Page">
        <t t-call="website.layout">
            <div id="wrap">
                <div class="container">
                    <h1>Dynamic Modal Page</h1>
                    <button id="open_modal_button" class="btn btn-primary">Open Modal</button>
                </div>
            </div>
        </t>
    </template>
</odoo>

This part sets up a simple website page with a single button that we'll use to open our dynamic modal.

Bringing It All Together: Opening and Handling the Modal

Finally, we need a small piece of Javascript that runs on our website page to listen for the button click, create an instance of our EditModal widget, and handle the events it triggers.

First, make sure to include your Javascript file in your website page template. You can do this by adding a line to your assets.xml file.

Then, you can use a simple script to open the modal and listen for the confirmation:

odoo.define('dynamic_modal.modal_starter', function (require) {
    'use strict';
    var publicWidget = require('web.public.widget');
    var EditModal = require('dynamic_modal.edit_modal');
    publicWidget.registry.ModalStarter = publicWidget.Widget.extend({
        selector: '#wrap',
        events: {
            'click #open_modal_button': '_onOpenModal',
        },
        _onOpenModal: function () {
            // Create a new instance of our modal widget
            // and pass in custom options
            var modalPopup = new EditModal(this, {
                title: "My Custom Modal Title",
                confirmButtonText: "Save",
                cancelButtonText: "Close"
            });
            // Append the modal to the document body to ensure it appears on top
            modalPopup.appendTo($('body'));
            // Listen for the `modal_confirm` event triggered by the modal
            modalPopup.on("modal_confirm", null, function (data) {
                // This is where you would write your logic
                // For example, you can handle the data passed from the modal
                console.log("Modal confirmed! Data received:", data);
                // Call an RPC, update a DOM element, etc.
            });
        },
    });
    return publicWidget.registry.ModalStarter;
});

This new widget listens for a click on the open_modal_button and, when it happens, creates a new EditModal with a custom title and button text. This is how you achieve a truly dynamic and reusable component. The new code then appends the modal to the body element and sets up a listener for the modal_confirm event, which is triggered when the user clicks the "Save" button in the modal. This is a very common and powerful pattern for communication between Odoo widgets.

Conclusion

By combining a custom Javascript widget with a Qweb template, we've created a powerful and reusable dynamic modal in Odoo 16. This approach keeps your code organized and allows you to create flexible UI components that can be used throughout your website.

To read more about Step-by-Step Guide to Creating Custom Effects in Odoo 18, refer to our blog Step-by-Step Guide to Creating Custom Effects in Odoo 18


If you need any assistance in odoo, we are online, please chat with us.



0
Comments



Leave a comment



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