1

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?

Wald Sin
  • 158
  • 11

3 Answers3

1

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>
Wald Sin
  • 158
  • 11
Kenly
  • 24,317
  • 7
  • 44
  • 60
  • thanks for your reply, I found a solution to my question and described it below in a separate answer. But with such an implementation, the js does not work in the web template. Perhaps you have faced such a problem before? – Wald Sin Jun 10 '23 at 20:25
  • 1
    No, I didn't use qweb templates with window actions. You can create a custom qweb view and use `t-call` directive to render the template. This will let you execute custom js code directly from the view controller – Kenly Jun 12 '23 at 13:08
  • can you please write an example, how to achieve this? – Wald Sin Jun 12 '23 at 17:12
  • I've added a minimal example – Kenly Jun 13 '23 at 08:47
  • thank you very much for your hard work, everything works great except for one point that simple js code for example is not executed either in the qweb_view or in the – Wald Sin Jun 13 '23 at 12:12
  • 1
    The script will be executed when the template is rendered from a controller. For the qweb view, you can create a custom renderer and override the `_render` function to move the script to the header. Check my edit – Kenly Jun 13 '23 at 12:49
  • oh my god, it really works. my respect and boundless gratitude to you for the work you had done. – Wald Sin Jun 13 '23 at 14:55
0

you a typical view to be inherit the settings view base.res_config_settings_view_form. like the following:

<record id="res_config_settings_view_form" model="ir.ui.view">
  <field name="name">res.config.settings.view.form.inherit.account</field>
  <field name="model">res.config.settings</field>
  <field name="priority" eval="40"/>
  <field name="inherit_id" ref="base.res_config_settings_view_form"/>
  <field name="arch" type="xml">
    <xpath expr="//div[hasclass('settings')]" position="inside">
      <div class="app_settings_block" data-string="Invoicing" string="Invoicing" data-key="account" >
      
        <!-- Here all your code for sub-views -->


      </div>
    </xpath>
  </field>
</record>
kerbrose
  • 1,095
  • 2
  • 11
  • 22
0

ok guys, I spent almost a month searching for a solution, unfortunately the answers were a bit off about what I was trying to implement, but I got it at some point.

We can use ir.actions.act_window with "qweb" view_mode to get this job done.

<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</field>
    <field name="view_id" ref="tada.company_structure_test"/>
</record>

here is my test template

<template id="company_structure_test">
    <h1>qweb works</h1>
    <t t-set="test_data" t-value="model.get_company_structure_data()"/>
    <p t-esc="test_data"/>
    <p t-esc="test_data['test_str']"/>
    <p t-esc="test_data['test_list'][-1]"/>
    
    <script type="text/javascript">
        console.log('this don`t work');
    </script>
</template>

and result: enter image description here I'm under the impression that it shouldn't work at all, but somehow it does in this format. The panel at the top can be simply hidden using a js script, if necessary

but there is a problem if you want to use js. I tried but it didn't work. i encountered the same problem when using request.render('my_template',{}). If you render your template in website, js works. If in odoo itself or on empty page, js didn`t work. there is no console.log in browser console.

Wald Sin
  • 158
  • 11