Bài trước là server action — chạy logic ở máy chủ. Giờ sang phía ngược lại: client action (ir.actions.client) là một màn hình do JavaScript (OWL) tự vẽ ngay trên trình duyệt. Khi list/kanban/form đều không dựng nổi thứ bạn muốn — một dashboard số liệu, một màn hình quy trình riêng — client action là lối ra. Bài này viết một Component OWL thật, cắm vào Odoo, và nó lấy dữ liệu thật để hiển thị.
Component OWL + đăng ký vào registry
Một client action gồm hai mảnh: một Component OWL (JS) và một bản ghi ir.actions.client có tag trỏ tới Component đó. Component đăng ký vào registry.category("actions"):

Hình 1: dashboard.js định nghĩa QuanDashboard (OWL Component). Trong setup(), useService("orm") cho phép gọi ORM; onWillStart chạy trước khi vẽ để lấy dữ liệu thật (searchRead). Cuối file: registry.category("actions").add("quan_ca_phe.dashboard", QuanDashboard). Bản ghi ir.actions.client có tag khớp đúng key đó.
Ba điểm cốt lõi của Odoo 19 OWL:
registry.category("actions").add(tag, Component)— cách "công bố" Component để action tìm thấy nó quatag.useService("orm")+onWillStart— lấy dữ liệu từ máy chủ trước khi render, không cần view.useState— state phản ứng: đổistate.tonglà giao diện tự vẽ lại.
Màn hình tự vẽ chạy thật
Template QWeb-OWL (.xml) và file JS đều khai vào web.assets_backend. Mở action qua menu, đây là kết quả:

Hình 2: Client action đang chạy — một màn hình không phải list/kanban/form nào cả, do OWL tự vẽ. Ba con số là thật, lấy từ ORM: 4 thẻ, tổng 385 điểm (150+150+85+0), 1 thẻ Vàng. Đổi dữ liệu dưới CSDL rồi mở lại là số tự cập nhật.
Cái hay: bạn có toàn quyền trên HTML/CSS/JS của màn hình này, mà vẫn ở trong Odoo — dùng chung ORM, service, session, điều hướng. Đây là cách các dashboard tuỳ biến, màn hình POS, trình xử lý đặc thù được xây.
Khi nào cần client action
- Cần khi giao diện không map vào một model/record theo kiểu view: dashboard tổng hợp nhiều nguồn, một wizard nhiều bước phức tạp, một màn hình đồ hoạ riêng.
- Không cần khi list/kanban/form/pivot đã đủ — đừng viết JS chỉ để hiện một danh sách; view chuẩn rẻ hơn và bền hơn.
- Cân nhắc chi phí bảo trì: JS/OWL cần build asset, dễ vỡ khi nâng cấp hơn view khai bằng XML. Chỉ dùng khi thật sự cần.
Vài lưu ý
- Lỗi JS chỉ hiện ở trình duyệt. Như bài kanban,
-ucó thể xanh nhưng Component vẫn nổOwlErrorlúc render — kiểm bằng DevTools/console (hoặc Playwright bắtpageerror). tagphải khớp tuyệt đối giữaregistry...add(tag, ...)và<field name="tag">— lệch một ký tự là action mở ra màn hình trống.- Import từ đúng module:
@odoo/owlcho OWL,@web/core/...cho hạ tầng Odoo. Sai đường dẫn import là không build được. - Template QWeb-OWL khai trong assets dưới dạng file
.xml;static template = "..."của Component phải trỏ đúngt-name.
Ba ý mang về
- Client action (
ir.actions.client) là màn hình do OWL tự vẽ ở trình duyệt — dùng khi list/kanban/form không đủ; gồm một Component đăng ký vàoregistry.category("actions")và một action cótagkhớp key. - Component OWL lấy dữ liệu thật qua
useService("orm")+onWillStart, dùnguseStatecho state phản ứng — toàn quyền HTML/CSS/JS mà vẫn trong Odoo. - Cân nhắc trước khi dùng: chỉ khi giao diện không map vào view chuẩn; nhớ lỗi JS chỉ hiện ở trình duyệt và
tagphải khớp tuyệt đối.
Action mở view, chạy code, vẽ màn hình JS. Còn một loại nữa đơn giản mà hữu ích: Phần sau về URL action — action chỉ mở một đường link (trang ngoài, tài liệu, báo cáo) trong tab mới, không cần view hay code.