Chương 2: Tạo chế độ xem thư viện¶
Chúng ta hãy xem cách người ta có thể tạo một chế độ xem mới, hoàn toàn từ đầu. Theo một cách nào đó, việc này không khó thực hiện nhưng không có nguồn tài nguyên thực sự tốt về cách thực hiện. Lưu ý rằng hầu hết các tình huống cần được giải quyết bằng cách tùy chỉnh chế độ xem hiện có hoặc bằng hành động của khách hàng.
Đối với bài tập này, giả sử rằng chúng ta muốn tạo một chế độ xem bộ sưu tập
, đây là chế độ xem cho phép chúng ta thể hiện một tập hợp các bản ghi bằng một trường hình ảnh.
Vấn đề chắc chắn có thể được giải quyết bằng chế độ xem kanban, nhưng điều này có nghĩa là không thể có chế độ xem kanban thông thường và chế độ xem thư viện trong cùng một hành động.
Hãy để chúng tôi thực hiện một cái nhìn xem thư viện. Mỗi chế độ xem thư viện sẽ được xác định bởi thuộc tính image_field
trong vòm của nó:
<gallery image_field="some_field"/>
Để hoàn thành các nhiệm vụ trong chương này, bạn sẽ cần cài đặt tiện ích bổ sung awesome_gallery. Tiện ích bổ sung này bao gồm các tệp máy chủ cần thiết để thêm chế độ xem mới.
Mục tiêu

Giải pháp cho mỗi bài tập của chương được lưu trữ trên kho lưu trữ hướng dẫn chính thức của SoOn.
1. Tạo một thế giới quan xin chào¶
Bước đầu tiên là tạo một triển khai JavaScript với một thành phần đơn giản.
Tạo các tệp
gallery_view.js
,gallery_controller.js
vàgallery_controller.xml
trongstatic/src
.Triển khai thành phần hello world đơn giản trong
gallery_controller.js
.Trong
gallery_view.js
, nhập bộ điều khiển, tạo đối tượng chế độ xem và đăng ký nó trong sổ đăng ký chế độ xem dưới têngallery
.Example
Dưới đây là một ví dụ về cách xác định đối tượng xem:
import { registry } from "@web/core/registry"; import { MyController } from "./my_controller"; export const myView = { type: "my_view", display_name: "MyView", icon: "oi oi-view-list", multiRecord: true, Controller: MyController, }; registry.category("views").add("my_controller", myView);
Thêm
gallery
làm một trong các loại chế độ xem trong hành độngcontacts.action_contacts
.Đảm bảo rằng bạn có thể thấy thành phần hello world khi chuyển sang chế độ xem thư viện.


2. Sử dụng thành phần Layout¶
Cho đến nay, chế độ xem thư viện của chúng tôi trông không giống chế độ xem tiêu chuẩn. Hãy sử dụng thành phần Layout
để có các tính năng tiêu chuẩn như các chế độ xem khác.
Nhập thành phần
Layout
và thêm nó vàothành phần
củaGalleryController
.Cập nhật mẫu để sử dụng
Layout
. Nó cần một propdisplay
, có thể tìm thấy trongprops.display
.

3. Phân tích vòm¶
Hiện tại, chế độ xem thư viện của chúng tôi không có tác dụng gì nhiều. Hãy bắt đầu bằng cách đọc thông tin có trong vòm của khung nhìn.
Quá trình phân tích cú pháp một vòm thường được thực hiện bằng ArchParser
, dành riêng cho từng chế độ xem. Nó kế thừa từ một lớp XMLParser
chung.
Example
Đây là một ví dụ về giao diện của ArchParser:
export class MyCustomArchParser {
parse(xmlDoc) {
const myAttribute = xmlDoc.getAttribute("my_attribute")
return {
myAttribute,
}
}
}
Tạo lớp
ArchParser
trong tệp riêng của nó.Sử dụng nó để đọc thông tin
image_field
.Cập nhật mã xem
thư viện
để thêm nó vào đạo cụ mà bộ điều khiển nhận được.
Ghi chú
Làm như vậy có lẽ hơi quá mức cần thiết, vì về cơ bản chúng ta chỉ cần đọc một thuộc tính từ vòm, nhưng đó là một thiết kế được mọi chế độ xem odoo khác sử dụng, vì nó cho phép chúng ta trích xuất một số xử lý trả trước từ bộ điều khiển.
4. Tải một số dữ liệu¶
Bây giờ chúng ta hãy lấy một số dữ liệu thực từ máy chủ. Để làm được điều đó, chúng ta phải sử dụng webSearchRead
từ dịch vụ orm.
Example
Dưới đây là ví dụ về webSearchRead
để lấy bản ghi từ một mô hình:
const { length, records } = this.orm.webSearchRead(this.resModel, domain, {
specification: {
[this.fieldToFetch]: {},
[this.secondFieldToFetch]: {},
},
context: {
bin_size: true,
}
})
Thêm phương thức
loadImages(domain) {...}
vàoGalleryController
. Nó sẽ thực hiện lệnh gọiwebSearchRead
từ dịch vụ orm để tìm nạp các bản ghi tương ứng với miền và sử dụngimageField
nhận được trong đạo cụ.Nếu không thêm
bin_size
vào ngữ cảnh của cuộc gọi, bạn sẽ nhận được trường hình ảnh được mã hóa ở base64. Đảm bảo đặtbin_size
trong ngữ cảnh để nhận kích thước của trường hình ảnh. Chúng tôi sẽ hiển thị hình ảnh sau.Sửa đổi mã
setup
để gọi phương thức đó trong hookonWillStart
vàonWillUpdateProps
.Sửa đổi mẫu để hiển thị id và kích thước của từng hình ảnh bên trong vị trí mặc định của thành phần
Layout
.
Ghi chú
Mã dữ liệu tải sẽ được chuyển sang mô hình phù hợp trong bài tập tiếp theo.

5. Giải quyết vấn đề đồng thời¶
Hiện tại, mã của chúng tôi không phải là bằng chứng đồng thời. Nếu một người thay đổi tên miền hai lần, nó sẽ kích hoạt loadImages(domain)
hai lần. Do đó, chúng tôi có hai yêu cầu có thể đến vào thời điểm khác nhau tùy thuộc vào các yếu tố khác nhau. Việc nhận phản hồi cho yêu cầu đầu tiên sau khi nhận được phản hồi cho yêu cầu thứ hai sẽ dẫn đến trạng thái không nhất quán.
Nguyên hàm KeepLast
của SoOn giải quyết vấn đề này, nó quản lý danh sách các tác vụ và chỉ giữ cho tác vụ cuối cùng hoạt động.
Nhập
KeepLast
từ@web/core/utils/concurrency
.Khởi tạo đối tượng
KeepLast
trong mô hình.Thêm lệnh gọi
webSearchRead
vàoKeepLast
để chỉ lệnh gọi cuối cùng được giải quyết.
Xem thêm
6. Sắp xếp lại mã¶
Chế độ xem thực tế có tổ chức hơn một chút. Điều này có thể là quá mức cần thiết trong ví dụ này nhưng nó nhằm mục đích tìm hiểu cách cấu trúc mã trong SoOn. Ngoài ra, điều này sẽ mở rộng quy mô tốt hơn với các yêu cầu thay đổi.
Di chuyển tất cả mã mô hình vào lớp
GalleryModel
của chính nó.Di chuyển tất cả mã kết xuất trong thành phần
GalleryRenderer
.Nhập
GalleryModel
vàGalleryRenderer
trongGalleryController
để làm cho nó hoạt động.
7. Làm cho chế độ xem có thể mở rộng¶
Để mở rộng chế độ xem, người ta có thể nhập đối tượng chế độ xem thư viện để sửa đổi nó theo sở thích của họ. Vấn đề là hiện tại, không thể xác định mô hình hoặc trình kết xuất tùy chỉnh vì nó được mã hóa cứng trong bộ điều khiển.
Nhập
GalleryModel
vàGalleryRenderer
trong tệp xem thư viện.Thêm khóa
Model
vàRenderer
vào đối tượng chế độ xem thư viện và gán chúng choGalleryModel
vàGalleryRenderer
. TruyềnModel
vàRenderer
làm đạo cụ cho bộ điều khiển.Loại bỏ quá trình nhập mã hóa cứng trong bộ điều khiển và lấy chúng từ đạo cụ.
Sử dụng t-comComponent để có thành phần phụ động.
Ghi chú
Đây là cách giờ đây ai đó có thể mở rộng chế độ xem thư viện bằng cách sửa đổi trình kết xuất:
/** @odoo-module */
import { registry } from '@web/core/registry';
import { galleryView } from '@awesome_gallery/gallery_view';
import { GalleryRenderer } from '@awesome_gallery/gallery_renderer';
export class MyExtendedGalleryRenderer extends GalleryRenderer {
static template = "my_module.MyExtendedGalleryRenderer";
setup() {
super.setup();
console.log("my gallery renderer extension");
}
}
registry.category("views").add("my_gallery", {
...galleryView,
Renderer: MyExtendedGalleryRenderer,
});
8. Hiển thị hình ảnh¶
Cập nhật trình kết xuất để hiển thị hình ảnh theo cách đẹp mắt nếu trường này được đặt. Nếu image_field
trống, thay vào đó hãy hiển thị một hộp trống.
Mẹo
Có một bộ điều khiển cho phép lấy hình ảnh từ một bản ghi. Bạn có thể sử dụng đoạn mã này để xây dựng liên kết:
import { url } from "@web/core/utils/urls";
const url = url("/web/image", {
model: resModel,
id: image_id,
field: imageField,
});

9. Chuyển sang chế độ xem biểu mẫu khi nhấp chuột¶
Cập nhật trình kết xuất để phản ứng với một lần nhấp vào hình ảnh và chuyển sang chế độ xem biểu mẫu. Bạn có thể sử dụng chức năng switchView
từ dịch vụ hành động.
Xem thêm
10. Thêm chú giải công cụ tùy chọn¶
Sẽ rất hữu ích nếu có thêm một số thông tin về việc di chuột.
Cập nhật mã để cho phép một thuộc tính bổ sung tùy chọn trên vòm:
<gallery image_field="some_field" tooltip_field="some_other_field"/>
Khi di chuột, hiển thị nội dung của trường chú giải công cụ. Nó sẽ hoạt động nếu trường là trường char, trường số hoặc trường many2one. Để đặt chú giải công cụ vào phần tử html, bạn có thể đặt chuỗi vào thuộc tính
data-tooltip
của phần tử.Cập nhật khung xem thư viện khách hàng để thêm khách hàng làm trường chú giải công cụ.

Xem thêm
Ví dụ: cách sử dụng t-att-data-tooltip <https://github.com/odoo/odoo/blob/145fe958c212ddef9fab56a232c8b2d3db635c8e/addons/survey/static/src/views/widgets/survey_question_trigger/survey_question_trigger.xml#L8>
_
11. Thêm phân trang¶
Hãy thêm một máy nhắn tin trên bảng điều khiển và quản lý tất cả phân trang như trong chế độ xem SoOn thông thường.

12. Xác thực lượt xem¶
Chúng tôi có một cái nhìn tốt đẹp và hữu ích cho đến nay. Nhưng trong thực tế, chúng tôi có thể gặp vấn đề với việc người dùng mã hóa không chính xác arch
của chế độ xem Thư viện của họ: nó hiện chỉ là một đoạn XML không có cấu trúc.
Hãy để chúng tôi thêm một số xác nhận! Trong SoOn, tài liệu XML có thể được mô tả bằng tệp RN (Relax NG file), sau đó được xác thực.
Thêm tệp RNG mô tả ngữ pháp hiện tại:
Thuộc tính bắt buộc
image_field
.Thuộc tính tùy chọn:
tooltip_field
.
Thêm một số mã để đảm bảo tất cả các chế độ xem đều được xác thực đối với tệp RNG này.
Trong khi thực hiện việc đó, hãy đảm bảo rằng
image_field
vàtooltip_field
là các trường từ mô hình hiện tại.
Vì việc xác thực tệp RNG không hề đơn giản nên đây là đoạn trích để trợ giúp:
# -*- coding: utf-8 -*-
import logging
import os
from lxml import etree
from odoo.loglevels import ustr
from odoo.tools import misc, view_validation
_logger = logging.getLogger(__name__)
_viewname_validator = None
@view_validation.validate('viewname')
def schema_viewname(arch, **kwargs):
""" Check the gallery view against its schema
:type arch: etree._Element
"""
global _viewname_validator
if _viewname_validator is None:
with misc.file_open(os.path.join('modulename', 'rng', 'viewname.rng')) as f:
_viewname_validator = etree.RelaxNG(etree.parse(f))
if _viewname_validator.validate(arch):
return True
for error in _viewname_validator.error_log:
_logger.error(ustr(error))
return False
13. Tải hình ảnh lên¶
Chế độ xem thư viện của chúng tôi không cho phép người dùng tải hình ảnh lên. Hãy để chúng tôi thực hiện điều đó.
Thêm nút trên mỗi hình ảnh bằng cách sử dụng thành phần
FileUploader
.Thành phần
FileUploader
chấp nhận propsonUploaded
, được gọi khi người dùng tải hình ảnh lên. Đảm bảo gọiwebSave
từ dịch vụ orm để tải lên hình ảnh mới.Bạn có thể nhận thấy rằng hình ảnh đã được tải lên nhưng nó không được trình duyệt hiển thị lại. Điều này là do liên kết hình ảnh không thay đổi nên trình duyệt không tìm nạp lại chúng. Bao gồm
write_date
từ bản ghi vào url hình ảnh.Đảm bảo rằng việc nhấp vào nút tải lên không kích hoạt switchView.

14. Mẫu chú giải công cụ nâng cao¶
Hiện tại, chúng tôi chỉ có thể chỉ định trường chú giải công cụ. Nhưng nếu chúng ta muốn cho phép viết một mẫu cụ thể cho nó thì sao?
Example
Đây là ví dụ về chế độ xem vòm thư viện sẽ hoạt động sau bài tập này.
<record id="contacts_gallery_view" model="ir.ui.view">
<field name="name">awesome_gallery.orders.gallery</field>
<field name="model">res.partner</field>
<field name="arch" type="xml">
<gallery image_field="image_1920" tooltip_field="name">
<field name="email"/> <!-- Specify to the model that email should be fetched -->
<field name="name"/> <!-- Specify to the model that name should be fetched -->
<tooltip-template> <!-- Specify the owl template for the tooltip -->
<p class="m-0">name: <field name="name"/></p> <!-- field is compiled into a t-esc-->
<p class="m-0">e-mail: <field name="email"/></p>
</tooltip-template>
</gallery>
</field>
</record>
Thay thế chế độ xem vòm thư viện
res.partner
trongawesome_gallery/views/views.xml
bằng vòm trong ví dụ trên. Đừng lo lắng nếu nó không vượt qua được quá trình xác thực rng.Sửa đổi trình xác thực thư viện rng để chấp nhận cấu trúc vòm mới.
Mẹo
Bạn có thể sử dụng đoạn mã rng này để xác thực thẻ mẫu chú giải công cụ
<rng:define name="tooltip-template"> <rng:element name="tooltip-template"> <rng:zeroOrMore> <rng:text/> <rng:ref name="any"/> </rng:zeroOrMore> </rng:element> </rng:define> <rng:define name="any"> <rng:element> <rng:anyName/> <rng:zeroOrMore> <rng:choice> <rng:attribute> <rng:anyName/> </rng:attribute> <rng:text/> <rng:ref name="any"/> </rng:choice> </rng:zeroOrMore> </rng:element> </rng:define>
Trình phân tích cú pháp vòm sẽ phân tích các trường và mẫu chú giải công cụ. Nhập
visitXML
từ@web/core/utils/xml
và sử dụng nó để phân tích tên trường và mẫu chú giải công cụ.Đảm bảo rằng mô hình gọi
webSearchRead
bằng cách đưa tên trường được phân tích cú pháp vào đặc tả.Trình kết xuất (hoặc bất kỳ thành phần phụ nào bạn đã tạo cho nó) sẽ nhận được mẫu chú giải công cụ được phân tích cú pháp. Thao tác với mẫu này để thay thế phần tử
<field>
thành phần tử<t t-esc="x">
.Mẹo
Mẫu là một đối tượng
Element
nên nó có thể được thao tác giống như một phần tử HTML.Đăng ký mẫu vào Owl nhờ hàm
xml
từ@odoo/owl
.Sử dụng hook
useTooltip
từ@web/core/tooltip/tooltip_hook
để hiển thị chú giải công cụ. Móc này lấy làm đối số là mẫu Owl và biến mà mẫu đó cần.
