odoo17核心概念view6——用js_class扩展formview

发布时间:2023年12月25日

这是view系列的第六篇文章,我们学习用js_class来扩展view
学习odoo的一大窍门就是抄,因为odoo本身就是一个庞大的代码库,抄过来,改改就能用

1、找一个js_class的案例

搜索js_class,出现一堆结果,随便看一个

<form string="Account Entry" js_class="account_move_form">

搜索account_move_form 找到对应的js文件

/** @odoo-module **/

import { registry } from "@web/core/registry";
import { createElement, append } from "@web/core/utils/xml";
import { Notebook } from "@web/core/notebook/notebook";
import { formView } from "@web/views/form/form_view";
import { FormCompiler } from "@web/views/form/form_compiler";
import { FormRenderer } from "@web/views/form/form_renderer";
import { FormController } from '@web/views/form/form_controller';
import { useService } from "@web/core/utils/hooks";

export class AccountMoveController extends FormController {
    setup() {
        super.setup();
        this.account_move_service = useService("account_move");
    }

    async deleteRecord() {
        if ( !await this.account_move_service.addDeletionDialog(this, this.model.root.resId)) {
            return super.deleteRecord(...arguments);
        }
    }
};

export class AccountMoveFormNotebook extends Notebook {
    async changeTabTo(page_id) {
        if (this.props.onBeforeTabSwitch) {
            await this.props.onBeforeTabSwitch(page_id);
        }
        this.state.currentPage = page_id;
    }
}
AccountMoveFormNotebook.template = "account.AccountMoveFormNotebook";
AccountMoveFormNotebook.props = {
    ...Notebook.props,
    onBeforeTabSwitch: { type: Function, optional: true },
}
export class AccountMoveFormRenderer extends FormRenderer {
    async saveBeforeTabChange() {
        if (this.props.record.isInEdition && await this.props.record.isDirty()) {
            const contentEl = document.querySelector('.o_content');
            const scrollPos = contentEl.scrollTop;
            await this.props.record.save();
            if (scrollPos) {
                contentEl.scrollTop = scrollPos;
            }
        }
    }
}
AccountMoveFormRenderer.components = {
    ...FormRenderer.components,
    AccountMoveFormNotebook: AccountMoveFormNotebook,
}
export class AccountMoveFormCompiler extends FormCompiler {
    compileNotebook(el, params) {
        const originalNoteBook = super.compileNotebook(...arguments);
        const noteBook = createElement("AccountMoveFormNotebook");
        for (const attr of originalNoteBook.attributes) {
            noteBook.setAttribute(attr.name, attr.value);
        }
        noteBook.setAttribute("onBeforeTabSwitch", "() => __comp__.saveBeforeTabChange()");
        const slots = originalNoteBook.childNodes;
        append(noteBook, [...slots]);
        return noteBook;
    }
}

export const AccountMoveFormView = {
    ...formView,
    Renderer: AccountMoveFormRenderer,
    Compiler: AccountMoveFormCompiler,
    Controller: AccountMoveController,
};

registry.category("views").add("account_move_form", AccountMoveFormView);

通过上面的代码,我们看到它扩展了Renderer,Compiler,Controller三个组件,
而其他的属性通过…formView 解构赋值,值得注意的是这一句一定要放在最上面,因为后面的值会覆盖前面的,最后将这个新的结构体注册到注册表中。

2、看看formView原版

我们看看原来的formView是怎么写的,从代码看,formView是一个字典,包含了诸多属性

    type: "form",			                          视图类型		
    display_name: "Form",                       显示名称
    multiRecord: false,                            是否支持多行
    searchMenuTypes: [],                         搜索菜单类型,什么鬼?
    Controller: FormController,                 Controller组件(重要)
    Renderer: FormRenderer,					renderer组件(重要)
    ArchParser: FormArchParser,				arch解析器,(重要)
    Model: RelationalModel,						model (重要)
    Compiler: FormCompiler,					编译器(将xml文件编译成qweb模板,重要)
    buttonTemplate: "web.FormView.Buttons",    button模板

通常对视图的扩展就是修改它的Controller和Render组件。修改完之后生成一个新的字典,然后生成一个新的名字注册到注册表中。 然后在js_class中指定这个名称,前端解析xml的时候就会根据这个js_class名称去注册表中查找对应的信息,然后渲染页面。

/** @odoo-module **/

import { registry } from "@web/core/registry";
import { RelationalModel } from "@web/model/relational_model/relational_model";
import { FormRenderer } from "./form_renderer";
import { FormArchParser } from "./form_arch_parser";
import { FormController } from "./form_controller";
import { FormCompiler } from "./form_compiler";

export const formView = {
    type: "form",					
    display_name: "Form",
    multiRecord: false,
    searchMenuTypes: [],
    Controller: FormController,
    Renderer: FormRenderer,
    ArchParser: FormArchParser,
    Model: RelationalModel,
    Compiler: FormCompiler,
    buttonTemplate: "web.FormView.Buttons",

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

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

registry.category("views").add("form", formView);

3、做一个对form视图简单的扩展

js文件

/** @odoo-module **/

import { registry } from "@web/core/registry";
import { formView } from "@web/views/form/form_view";
import { FormController } from '@web/views/form/form_controller';

export class DemoFormController extends FormController {
};

DemoFormController.template = "crax_demo.demo_form_controller"

export const CraxDemoFormView = {
    ...formView,
    Controller: DemoFormController,
};

registry.category("views").add("crax_demo_form_view", CraxDemoFormView);

xml文件

<?xml version="1.0" encoding="UTF-8"?>
<templates>
    <t t-name="crax_demo.demo_form_controller" t-inherit="web.FormView" t-inherit-mode="primary">
        <xpath expr="//div[hasclass('o_form_view_container')]" position="inside">
            <div style="color:red;">
                hello world
            </div>
        </xpath>

    </t>
</templates>

这里只是简单的在o_form_view_container里面加了一个红色的hello,world!
例子很简单,但是套路讲明白了。

文章来源:https://blog.csdn.net/jiafeitutu/article/details/135204180
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。