Cấu hình Component.Events JSON map {<event>: <method>}. Quy tắc: DOM event lowercase, CustomEventType PascalCase. Xem Cấu hình UI → Events cho cú pháp.
A. DOM Events (EventType.*)
Viết lowercase trong JSON — vd "click": "OnClick".
Mouse / Click
| Event | Khi nào fire | Component thường dùng |
|---|
click | User click chuột trái lên element. | Button, Rating, Chart, ListViewItem, Pdf, DocumentWrite |
dblclick | Double click chuột. | Number, Textbox, Textarea, ImageUploader, ListViewItem, row của list/grid |
contextmenu | Click chuột phải (mở context menu). | GridView, ListView, SearchEntry |
mousedown / mouseup | Nhấn / nhả chuột (chưa thành click). | ImageUploader (drag), drag handle |
mousemove | Di chuyển chuột. | ImageUploader, MutiplePdfReport (drag) |
mouseenter / mouseleave | Chuột vào / ra khỏi element. | ListViewItem (highlight row hover) |
wheel | Cuộn chuột giữa. | ImageUploader (zoom) |
drop | Drop file/text vào element (drag-drop). | ImageUploader |
Keyboard
| Event | Khi nào fire | Component thường dùng |
|---|
keydown | Phím vừa được nhấn xuống. | Mọi input, SearchEntry, Datepicker |
keyup | Phím vừa được thả ra. | MutiplePdfReport, search field |
| Event | Khi nào fire | Component thường dùng |
|---|
input | Mỗi keystroke khi user gõ. Realtime — fire trước cả change. | Textbox, Number, AutocompleteTextbox, AIChat |
change | Value đã đổi và user blur ra (Enter / Tab / click ngoài). | Textbox, Number, Datepicker, Checkbox, SearchEntry, ImageUploader |
input vs change — dùng input khi cần realtime (autocomplete suggestion); dùng change khi chỉ cần phản ứng sau khi user đã hoàn thành nhập.
Focus
| Event | Khi nào fire | Component thường dùng |
|---|
focus | Element được focus (cursor đặt vào). | Datepicker, SearchEntry |
blur | Element mất focus. | SearchEntry, ListViewItem |
focusin | Giống focus nhưng bubble lên parent. | AutocompleteTextbox, ListViewItem, EditForm, Section |
focusout | Giống blur nhưng bubble lên parent. | AutocompleteTextbox, EditForm, Section |
| Event | Khi nào fire | Component thường dùng |
|---|
scroll | User cuộn nội dung. | AutocompleteTextbox, Datepicker |
resize | Window resize. | EditForm |
visibilitychange | Tab browser ẩn/hiện (visibilitychange API). | Textbox, Textarea |
show | Tab/popup được activate (DOM-style event mở-lại). | TabEditor |
Lifecycle
| Event | Khi nào fire | Component thường dùng |
|---|
DOMContentLoaded | DOM của widget đã render xong và mount vào tree. Giữ y nguyên case vì là tên chuẩn DOM. | EditForm, PdfReport, MutiplePdfReport, TabComponent, Section, base EditableComponent |
abort | Request hủy. | ListViewItem (load cancel) |
Print / Window
| Event | Khi nào fire | Component thường dùng |
|---|
beforeprint | Trước khi window.print() chạy. | EditForm |
afterprint | Sau khi window.print() xong. | EditForm |
B. Custom Events (CustomEventType.*)
Viết PascalCase y hệt enum trong JSON — vd "AfterCreated": "OnRowAdded".
Lifecycle row trong List/Grid
| Event | Khi nào fire | Component |
|---|
BeforeCreated | Trước khi tạo row mới (insert). Có thể mutate rowData. | ListView, GridView, ListViewItem |
AfterCreated | Sau khi insert row thành công. | ListView, GridView, SearchEntry |
BeforeCreatedList | Trước khi bulk insert (paste, import). | ListView |
AfterCreatedList | Sau bulk insert. | ListView |
BeforeEmptyRowCreated | Trước khi tạo row trống cuối grid (inline edit). | GridView |
AfterEmptyRowCreated | Sau khi tạo row trống. | GridView |
BeforeCreateAsync | Trước khi async insert (gọi API). | ListViewItem |
AfterCreateAsync | Sau async insert thành công. | ListViewItem |
Lifecycle update / patch
| Event | Khi nào fire | Component |
|---|
BeforePatchUpdate | Trước khi gửi PATCH update 1 cell. | ListViewItem |
ValidatePatchUpdate | Validate trước khi PATCH (return false để abort). | ListViewItem |
AfterPatchUpdate | Sau PATCH thành công. | ListViewItem |
BeforePatchCreate | Trước PATCH create row. | ListView |
Delete / Copy / Paste
| Event | Khi nào fire | Component |
|---|
BeforeDeleted | Trước khi xóa rows (có thể abort). | ListView |
AfterDeleted | Sau khi xóa thành công. | ListView |
BeforeCopied | Trước khi copy rows vào clipboard. | ListView |
AfterCopied | Sau khi copy. | ListView |
BeforePasted | Trước khi paste rows từ clipboard (có thể mutate data). | ListView, GridView |
AfterPasted | Sau khi paste thành công. | ListView, GridView |
Selection / Pointer trong row
| Event | Khi nào fire | Component |
|---|
Selected | Row được chọn (checkbox hoặc click). | ListView |
RowFocusIn | Cursor / focus vào 1 row. | ListViewItem |
RowFocusOut | Cursor / focus rời 1 row. | ListViewItem |
RowMouseEnter | Chuột vào row. | ListViewItem |
RowMouseLeave | Chuột rời row. | ListViewItem |
| Event | Khi nào fire | Component |
|---|
UpdateHeader | Sau khi reload column policy (vd user edit GridPolicy). | ListView |
AfterWebsocket | Khi WebSocket push 1 row update tới grid (realtime sync). | ListView |
Deactivated | Khi grid bị “deactivate” (tab ẩn, popup đóng tạm). | ListView |
OpenRef | User click vào reference link để mở popup detail của entity tham chiếu. | ListView, SearchEntry |
AfterRender | Sau khi render xong (riêng SearchEntry — sau khi value hiện trên DOM). | SearchEntry |
Save / Download / Report
| Event | Khi nào fire | Component |
|---|
SaveAs | User click “Save as” copy entity sang record mới. | ListView |
AfterDownload | Sau khi download file (PDF, Excel, Word) xong. | Pdf, MultipleButtonPdf |
Search / Date
| Event | Khi nào fire | Component |
|---|
DateSearch | User chọn date range trong search panel và submit. | AdvancedDateSearch (qua ParentListView.Events) |
AI / Chat
| Event | Khi nào fire | Component |
|---|
AfterChat | Sau khi AI parse / trả lời xong. | AIChat, ChatV2, ChatV3, ImageToJson |
Cheat sheet — chọn event nào?
| Tình huống | Event nên dùng |
|---|
| Reagree khi user gõ mỗi keystroke (autocomplete, validate live) | input |
| React khi user xong nhập (blur, Enter) | change |
| React khi user chọn option (Select2, SearchEntry) | change (DOM) |
| Click button | click |
| Double click row → mở popup edit | dblclick (trên ListViewItem của list cha) |
| Right-click row → menu | contextmenu (hoặc BodyContextMenuShow đã built-in) |
| Hook khi tab mới được activate | show (TabEditor) hoặc DOMContentLoaded (1 lần) |
| Hook khi row mới được tạo (validate, init default) | BeforeCreated (mutate trước insert) hoặc AfterCreated |
| Validate trước khi user save 1 cell | ValidatePatchUpdate (return false để abort) |
| Recalculate field tổng khi 1 cell đổi | change (trên cell input) hoặc AfterPatchUpdate (sau PATCH) |
| Setup default cho row mới (set FK, status mặc định) | BeforeCreated |
| Refresh UI sau khi xóa rows | AfterDeleted |
| Hook khi user paste từ clipboard | BeforePasted (validate / mutate) → AfterPasted (refresh) |
| Notify khi WebSocket sync 1 row mới | AfterWebsocket |
| AI chat hook | AfterChat |
| Custom date range search | DateSearch |
| Drilldown khi click data point trên chart | click (trên Chart) |
| Auto-fill các field khác khi user pick SearchEntry | change (trên picker, args (entity, matched, oldMatch, parent)) |
Method signature pattern
Tất cả method nhận object entity làm tham số đầu, args sau tùy event. Xem Tham chiếu component để biết chính xác từng signature.
public class MyFormBL : TabEditor
{
public MyFormBL() : base(nameof(MyEntity)) { }
// DOM event
public void OnClicked(object entity, object btn) { /* ... */ }
public async Task OnValueChanged(object entity, object newVal, object oldVal, object parent) { /* ... */ }
// CustomEventType
public void OnRowAdded(object rowData) { /* ... */ }
public async Task OnBeforeDelete(object deletedItems) { /* ... */ }
public void OnAfterChat(object taskComment, object result, object timeLine) { /* ... */ }
}
Bẫy hay gặp
- Sai case —
"Click" (capitalize) thay vì "click" (lowercase) → method không bao giờ chạy. Tương tự "aftercreated" (lowercase) thay vì "AfterCreated" (PascalCase) → không chạy.
- Method tên không khớp — case-sensitive.
OnClick ≠ onClick.
- Tham số không khớp số args — method declare 2 args mà event pass 4 → 2 args còn lại bị bỏ silently. Khai báo theo bảng Tham chiếu component.
- Async method không return Task —
async void chạy được nhưng exception bị nuốt. Dùng async Task<bool> hoặc async Task để Core await đúng cách.