شخصیسازی یک نوع نما¶
زیرکلاسسازی یک نمای موجود¶
فرض کنید نیاز داریم نسخهای سفارشی از یک نمای عمومی ایجاد کنیم. مثلاً یک نمای کانبان با یک ویجت اضافی شبیه روبان در بالا (برای نمایش برخی اطلاعات سفارشی خاص). در این صورت، این کار را میتوان در چند گام انجام داد:
controller/renderer/model کانبان را گسترش دهید و در رجیستری نما ثبت کنید.
custom_kanban_controller.js¶import { KanbanController } from "@web/views/kanban/kanban_controller"; import { kanbanView } from "@web/views/kanban/kanban_view"; import { registry } from "@web/core/registry"; // the controller usually contains the Layout and the renderer. class CustomKanbanController extends KanbanController { static template = "my_module.CustomKanbanView"; // Your logic here, override or insert new methods... // if you override setup(), don't forget to call super.setup() } export const customKanbanView = { ...kanbanView, // contains the default Renderer/Controller/Model Controller: CustomKanbanController, }; // Register it to the views registry registry.category("views").add("custom_kanban", customKanbanView);
در کانبان سفارشی ما، یک قالب جدید تعریف کردهایم. میتوانیم یا قالب کنترلر کانبان را ارثبری کرده و قطعات قالب خود را اضافه کنیم، یا یک قالب کاملاً جدید تعریف کنیم.
custom_kanban_controller.xml¶<?xml version="1.0" encoding="UTF-8" ?> <templates> <t t-name="my_module.CustomKanbanView" t-inherit="web.KanbanView"> <xpath expr="//Layout" position="before"> <div> Hello world ! </div> </xpath> </t> </templates>
از نما با ویژگی
js_classدر arch استفاده کنید.<kanban js_class="custom_kanban"> <templates> <t t-name="card"> <!--Your comment--> </t> </templates> </kanban>
امکانات گسترش نماها نامحدود است. در حالی که ما در اینجا فقط controller را گسترش دادهایم، میتوانید renderer را نیز برای افزودن دکمههای جدید، تغییر شیوهٔ ارائهٔ رکوردها یا سفارشیسازی dropdown گسترش دهید و همچنین کامپوننتهای دیگری مانند model و buttonTemplate را نیز گسترش دهید.
ایجاد یک نمای جدید از ابتدا¶
ایجاد یک نمای جدید موضوعی پیشرفته است. این راهنما تنها بر گامهای ضروری تأکید میکند.
controller را ایجاد کنید.
نقش اصلی یک controller، تسهیل هماهنگی بین کامپوننتهای مختلف یک نما، مانند Renderer، Model و Layout است.
beautiful_controller.js¶import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { Component, onWillStart, useState} from "@odoo/owl"; export class BeautifulController extends Component { static template = "my_module.View"; static components = { Layout }; setup() { this.orm = useService("orm"); // The controller create the model and make it reactive so whenever this.model is // accessed and edited then it'll cause a rerendering this.model = useState( new this.props.Model( this.orm, this.props.resModel, this.props.fields, this.props.archInfo, this.props.domain ) ); onWillStart(async () => { await this.model.load(); }); } }
قالب Controller، پنل کنترل را با Layout و همچنین renderer نمایش میدهد.
beautiful_controller.xml¶<?xml version="1.0" encoding="UTF-8"?> <templates xml:space="preserve"> <t t-name="my_module.View"> <Layout display="props.display" className="'h-100 overflow-auto'"> <t t-component="props.Renderer" records="model.records" propsYouWant="'Hello world'"/> </Layout> </t> </templates>
renderer را ایجاد کنید.
وظیفهٔ اصلی یک renderer، تولید نمایش بصری دادهها از طریق رندر نمایی است که شامل رکوردها است.
beautiful_renderer.js¶import { Component } from "@odoo/owl"; export class BeautifulRenderer extends Component { static template = "my_module.Renderer"; }
beautiful_renderer.xml¶<?xml version="1.0" encoding="UTF-8"?> <templates xml:space="preserve"> <t t-name="my_module.Renderer"> <t t-esc="props.propsYouWant"/> <t t-foreach="props.records" t-as="record" t-key="record.id"> // Show records </t> </t> </templates>
model را ایجاد کنید.
نقش model، بازیابی و مدیریت تمام دادههای ضروری در نما است.
beautiful_model.js¶import { KeepLast } from "@web/core/utils/concurrency"; export class BeautifulModel { constructor(orm, resModel, fields, archInfo, domain) { this.orm = orm; this.resModel = resModel; // We can access arch information parsed by the beautiful arch parser const { fieldFromTheArch } = archInfo; this.fieldFromTheArch = fieldFromTheArch; this.fields = fields; this.domain = domain; this.keepLast = new KeepLast(); } async load() { // The keeplast protect against concurrency call const { length, records } = await this.keepLast.add( this.orm.webSearchRead(this.resModel, this.domain, [this.fieldsFromTheArch], {}) ); this.records = records; this.recordsLength = length; } }
توجه
برای موارد پیشرفته، بهجای ایجاد یک model از ابتدا، میتوان از
RelationalModelکه توسط سایر نماها استفاده میشود، نیز استفاده کرد.arch parser را ایجاد کنید.
نقش arch parser، تجزیهٔ نمای arch است تا نما به اطلاعات دسترسی داشته باشد.
beautiful_arch_parser.js¶import { XMLParser } from "@web/core/utils/xml"; export class BeautifulArchParser extends XMLParser { parse(arch) { const xmlDoc = this.parseXML(arch); const fieldFromTheArch = xmlDoc.getAttribute("fieldFromTheArch"); return { fieldFromTheArch, }; } }
نما را ایجاد کنید و همهٔ قطعات را با هم ترکیب کنید، سپس نما را در رجیستری نماها ثبت کنید.
beautiful_view.js¶import { registry } from "@web/core/registry"; import { BeautifulController } from "./beautiful_controller"; import { BeautifulArchParser } from "./beautiful_arch_parser"; import { BeautifylModel } from "./beautiful_model"; import { BeautifulRenderer } from "./beautiful_renderer"; export const beautifulView = { type: "beautiful", display_name: "Beautiful", icon: "fa fa-picture-o", // the icon that will be displayed in the Layout panel multiRecord: true, Controller: BeautifulController, ArchParser: BeautifulArchParser, Model: BeautifulModel, Renderer: BeautifulRenderer, props(genericProps, view) { const { ArchParser } = view; const { arch } = genericProps; const archInfo = new ArchParser().parse(arch); return { ...genericProps, Model: view.Model, Renderer: view.Renderer, archInfo, }; }, }; registry.category("views").add("beautifulView", beautifulView);
نما را در arch اعلان کنید.
... <record id="my_beautiful_view" model="ir.ui.view"> <field name="name">my_view</field> <field name="model">my_model</field> <field name="arch" type="xml"> <beautiful fieldFromTheArch="res.partner"/> </field> </record> ...