Odoo Mengubah Widget Javascript

Odoo memiliki banyak widget yang siap dipakai, seperti many2many_tags, image, html, handle dll. Pennggunaanya pun mudah. Tapi dari semua widget yang dimiliki Odoo menurut saya many2many_tags ini sedikit aneh. Kenapa ? Karena tidak bisa diklik.

Maksud saya jika diklik tidak diarahkan ke halaman lain, tidak seperti saudaranya many2one. Pada artikel ini saya akan berbagi bagaimana mengubah widget Odoo, lebih tepatnya mengubah widget many2many_tags agar bisa diklik seperti many2one.

Dimana source code widget ?

Widget biasanya ditulis dalam bentuk file javascript dan xml di module web. Widget many2many_tags ditulis di /web/static/src/js/fields/relational_fields.js, lihat bagian FieldMany2ManyTags . Sedangkan file xml atau templatenya berada di /web/static/src/xml/base.xml, lihat bagian FieldMany2ManyTag.

Template

Template adalah file xml yang dirender jika widget dijalankan. Buat file xml dengan nama template.xml atau terserah anda di folder module_anda/static/src/xml dan copy paste kode dibawah ini.

<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
    <t t-name="FieldMany2ManyTagsLink">
        <t t-foreach="elements" t-as="el">
            <t t-set="color" t-value="el[colorField] || 0"/>
            <t t-set="colornames" t-value="['No color', 'Red', 'Orange', 'Yellow', 'Light blue', 'Dark purple', 'Salmon pink', 'Medium blue', 'Dark blue', 'Fushia', 'Green', 'Purple']"/>
            <div t-attf-class="badge badge-pill dropdown o_tag_color_#{color}" t-att-data-color="color" t-att-data-index="el_index" t-att-data-id="el.id" t-attf-title="Tag color: #{colornames[color]}">
                <t t-set="_badge_text">
                    <a href="#" class="o_external_link" t-att-modelid="el.id">
                        <span class="o_badge_text" t-att-title="el.display_name" ><span role="img" t-attf-aria-label="Tag color: #{colornames[color]}"/><t t-esc="el.display_name"/></span>
                    </a>
                </t>
                <t t-if="colorField">
                    <a href="#" class="dropdown-toggle o-no-caret" data-toggle="dropdown">
                        <t t-raw="_badge_text"/>
                    </a>
                </t>
                <t t-else="">
                    <t t-raw="_badge_text"/>
                </t>
                <a t-if="!readonly" href="#" class="fa fa-times o_delete" title="Delete" aria-label="Delete"></a>
            </div>
        </t>
    </t>
</templates>

Kode diatas sebenarnya tidak jauh berbeda dengan template asli many2many_tags, hanya saya ubah namanya jadi FieldMany2ManyTagsLink , menambah class o_external_link sebagai trigger jika diklik, dan menambah attribute modelid untuk menyimpan id model.

Selanjutnya buat file javascript di module_anda/static/src/js/ dengan nama bebas seperti widget.js

Define Module

Module javascript sebaiknya anda define dulu dengan memanggil kode seperti dibawah ini.

odoo.define('many2many_tags_link.widget', function (require) {
"use strict";

    // letakkan kode anda disini

});

Perhatikan parameter pertama pada function define diatas. Rumusnya adalah nama_module_anda.teks_bebas_biasanya_nama_file_js. Maksud kode diatas adalah agar module yang anda tulis mudah jika ingin di-override oleh module lain, dan agar kode anda urutan dijalankan-nya oleh odoo tepat. Lihat bagian selanjutnya.

Dependensi

Depedensi ini seperti fungsi import di python atau jika kode anda membutuhkan jquery. Jadi jquery harus anda load dulu sebelum kode anda. Jika sebaliknya tentu saja kode anda tidak jalan. Caranya seperti ini

odoo.define('many2many_tags_link.widget', function (require) {
"use strict";

    var core = require('web.core');
    var AbstractField = require('web.AbstractField');
    var registry = require('web.field_registry');
    var relational_fields = require('web.relational_fields');

});

Dari kode diatas kode anda tidak akan diload oleh Odoo sebelum kode web.core, web.AbstractField dll selesai diload. Inilah depedensi di Odoo.

Perhatian variabel relational_fields. Jika anda perhatikan web.relational_fields adalah kode yang ditulis di file /web/static/src/js/fields/relational_fields.js. Jadi pada Odoo depedensi tidak ditulis berdasarkan di file mana kode ditulis. Tapi pada teks apa yang anda masukkan sebagai parameter di function odoo.define.

Include atau Extend

Include digunakan jika kita ingin mengubah fungsi suatu widget disemua tempat, atau bisa disebut juga overriding method super. Sedangkan extend sama dengan inheritance, kita bisa menentukan dimana saja perubahan ini diterapkan. Perhatikan kode dibawah.

// define module baru dengan rumus nama_module.teks_bebas_atau_nama_file
odoo.define('many2many_tags_link.widget', function (require) {
"use strict";
    
    // load dependensi yang dibutuhkan, anggap saja sama dengan fungsi import di python
    var core = require('web.core');
    var AbstractField = require('web.AbstractField');
    var registry = require('web.field_registry');
    var relational_fields = require('web.relational_fields');

    var _t = core._t;
    var qweb = core.qweb;

    // mulai override module relational_fields dengan memanggil fungsi include atau extend
    // variabel relational_fields ini memiliki banyak objeck, jika perlu coba console.log
    // pada kode ini kita coba overide object FieldMany2ManyTags 
    // jika ingin menggunakan fungsi include dimana perubahan terjadi di semua tempat, gunakan kode ini

    // var FieldMany2ManyTagsLink = relational_fields.FieldMany2ManyTags.include

    // disini kita menggunakan fungsi extend karena kita ingin perubahan terjadi pada tempat tertentu saja

    var FieldMany2ManyTagsLink = relational_fields.FieldMany2ManyTags.extend({
        tag_template: "FieldMany2ManyTagsLink", // panggil template / file xml yang sudah kita tulis
        events: _.extend({}, AbstractField.prototype.events, { // ini adalah daftar event / action 
            'click .o_delete': '_onDeleteTag', // ini bawaan odoo
            'click .o_external_link': '_openRelated', // ini custom, untuk menghandle jika widget diklik akan memanggil fungsi _openRelated
        }),
        _openRelated: function (event) {         
            // fungsi ini bebas
            // aslinya nyontoh dari function _onClick object FieldMany2One
            // di file yang sama dimana kode asli widget many2many_tag ditulis
            // lihat file /web/static/src/js/fields/relational_fields.js
            event.preventDefault();
            event.stopPropagation();
            var self = this;
            
            var modelid = parseInt(event.currentTarget.getAttribute('modelid'));   

            if (this.mode === 'readonly' &amp;amp;amp;&amp;amp;amp; !this.noOpen &amp;amp;amp;&amp;amp;amp; modelid) {              
                this._rpc({
                        model: this.field.relation,
                        method: 'get_formview_action',
                        args: [[modelid]],
                        context: this.record.getContext(this.recordParams),
                    })
                    .then(function (action) {
                        self.trigger_up('do_action', {action: action});
                    });
            }
        },    

    });

    // ini agar widget yang kita buat bisa dipanggil dengan cara menulis
    // <field name="sales_person_ids" widget="many2many_tags_link"/>
    // di file xml erp
    // jika menggunakan fungsi extend dan kode ini tidak ditulis, widget tidak bisa digunakan
    registry
    .add('many2many_tags_link', FieldMany2ManyTagsLink);

    // ini agar widget yang kita tulis bisa dijadikan depedensi oleh module lain dan dapat diverride
    // widget tetap jalan jika tidak ditulis
    return {
        FieldMany2ManyTagsLink: FieldMany2ManyTagsLink,
    }

});

Selanjutnya silakan load file javascript dan xml yang sudah anda buat. Lebih detailnya silakan download DI SINI dan perhatikan file manifest.py dan views/view.xml

Tulisan Serupa

Leave a Reply

Your email address will not be published. Required fields are marked *