odooqwebodoo-15

How to render a qweb template by action button?


I have Qweb template like this:

<template id="test_template">
    <h1>My template</h1>
    <script type="text/javascript">
        console.log('it works');
    </script>
    <div>
        <t t-foreach="my_items" t-as="item">
            ...
        </t>
    </div>
</template>

I can render it in website by a controller like this

@http.route('/test_template', type="http", auth="user", methods=['GET'], website=True)
    def test_template(self, **kw):
        return request.render('my_module.test_template', {'my_items': [1, 2, 3]})

but I want to be able to render this template not in a separate website tab, but in the framework itself directly, as it works with actions and views enter image description here

any ideas, how can I do this?


Solution

  • Odoo transforms a <template> element into a <record> (ir.ui.view in this case) and will not be available to the JavaScript qweb renderer function.

    You can define a client action and use _rpc to call a model function to render the template and return the result

    Example: Call ir.ui.view render template function

    return self.env["ir.ui.view"]._render_template("my_module.test_template", 
        {'my_items': items}
    )
    

    EDIT Add A custom view to render QWEB

    class ActWindowView(models.Model):
        _inherit = 'ir.actions.act_window.view'
    
        view_mode = fields.Selection(selection_add=[('qweb_view', "QWEB View")], ondelete={'qweb_view': 'cascade'})
    
    
    class View(models.Model):
        _inherit = 'ir.ui.view'
    
        type = fields.Selection(selection_add=[('qweb_view', "QWEB View")], ondelete={'qweb_view': 'cascade'})
    

    Add the following JS code under assets/web.assets_backend in the manifest file:

    /** @odoo-module **/
    
    import { Renderer, Controller, View } from 'web.qweb';
    import registry from 'web.view_registry';
    
    
    var QwebController = Controller.extend({
        init: function (parent, model, renderer, params) {
            params.withControlPanel = false;
            this._super.apply(this, arguments);
        },
    });
    
    var QwebRenderer = Renderer.extend({
        _render: function () {
            var self = this;
            return this._super.apply(this, arguments).then(function () {
                self.$el.html(self.state.body);
                $('head').append(self.$el.find('script'));
            });
        },
    });
    
    var QwebView = View.extend({
        config: _.extend({}, View.prototype.config, {
            Controller: QwebController,
            Renderer: QwebRenderer,
        }),
        viewType: 'qweb_view',
        groupable: false,
    });
    
    registry.add('qweb_view', QwebView);
    

    Define a qweb_view view to call your template and use it in the window action:

    <record model="ir.ui.view" id="company_structure_test">
       <field name="name">company.structure.qweb</field>
       <field name="model">res.company</field>
       <field name="mode">primary</field>
       <field name="arch" type="xml">
           <qweb_view>
                <t t-call="qweb_view.company_structure_test_template">
                    <t t-set="model" t-value="res_company"/>
                </t>
            </qweb_view>
        </field>
    </record>
            
    <record id="action_company_structure" model="ir.actions.act_window">
        <field name="name">Структура компанії</field>
        <field name="res_model">res.company</field>
        <field name="view_mode">qweb_view</field>
        <field name="view_id" ref="company_structure_test"/>
    </record>