Section (layout)
Section là renderer runtime của 1 row ComponentGroup. Đặt component con vào DOM theo cấu hình DB.
Section là layout primitive trong Core. Mỗi row ComponentGroup trong DB trở thành 1 Section lúc runtime, và mỗi row Component bên trong group đó trở thành 1 EditableComponent con render vào element của section.
Nguồn:
Core/Components/Section.cs. Row dữ liệu:Core.Models.ComponentGroup.
Nó thực sự làm gì?
public class Section : EditableComponent
{
public ComponentGroup ComponentGroup { get; set; }
public override void Render()
{
if (elementType is null)
{
// Section được build quanh element có sẵn — đọc tag.
var tag = Element.TagName.ToLowerCase();
if (Enum.TryParse(tag, out ElementType type)) elementType = type;
}
else
{
// Section được cho ElementType — tạo tag đó.
Html.Take(ParentElement)
.Add(elementType.Value)
.ClassName(ComponentGroup is null ? null : ComponentGroup.ClassName);
Element = Html.Context;
}
// … duyệt ComponentGroup.Component và render từng child …
}
public void UpdateViewComponent()
{
DisposeChildren();
Html.Take(ParentElement).Clear();
elementType = null;
Render();
}
}
Hai chế độ construct:
// Chế độ 1: build element mới với tag chỉ định
new Section(ElementType.div) { ComponentGroup = group, ParentElement = parent };
// Chế độ 2: bọc element có sẵn (re-skin nó thành section)
new Section(existingElement) { ComponentGroup = group };
Field ComponentGroup chi phối render
| Field | Tác dụng |
|---|---|
ElementType | Tag HTML (div, tr, td, fieldset, …). |
ClassName | Class CSS gắn lên element render. |
Component | Children render bên trong. |
ParentId | Khác null → section này là con của section khác. |
Order | Thứ tự render giữa sibling. |
Lồng & cây
Section nest qua ComponentGroup.ParentId. Framework load list phẳng rồi BuildTree(...) ráp ChildGroup, sau đó Section.Render() walk cây.
ComponentGroup (root) ─► <div class="form">
├── ComponentGroup (header) ─► <div class="row">
│ ├── Component(Textbox) ─► <input ... />
│ └── Component(Datepicker) ─► <input type="date" />
└── ComponentGroup (body) ─► <fieldset class="body">
└── Component(GridView) ─► <table>...</table>
Update sau khi đổi cấu hình
Nếu cấu hình section thay đổi (toggle visibility 1 child), gọi UpdateViewComponent() — nó dispose children, clear DOM, render lại.
Update tinh hơn: giữ ref child cụ thể và toggle child.Show = false.
Chia cột (responsive grid)
Đây là cách chia layout 1 section thành N cột — tính năng built-in, không cần viết CSS riêng.
ComponentGroup có 5 field cấu hình số cột theo screen width:
| Field | Khi nào áp dụng | Breakpoint hằng số (EditableComponent) |
|---|---|---|
XsCol | Màn hình rất nhỏ (< 567px) | ExSmallScreen = 567 |
SmCol | Màn hình nhỏ (< 768px) | SmallScreen = 768 |
Column | Màn hình trung bình (< 992px) | MediumScreen = 992 |
LgCol | Màn hình lớn (< 1200px) | LargeScreen = 1200 |
XlCol | Màn hình rất lớn (< 1452px) | ExLargeScreen = 1452 |
Khi resolve, framework gọi EditForm.GetInnerColumn(group) đi từ nhỏ → lớn theo screen hiện tại để pick số cột phù hợp. Sau đó Section.RenderComponentResponsive set:
Html.Take(Element)
.ClassName("grid")
.Style($"grid-template-columns: repeat({innerCol}, 1fr)");
Tức là CSS Grid với N cột bằng nhau (1fr mỗi cột).
Ví dụ: form 2 cột trên desktop, 1 cột trên mobile
ComponentGroup:
Name: Header
ElementType: div
XsCol: 1 # mobile dọc
SmCol: 1
Column: 2 # tablet trở lên 2 cột
LgCol: 2
XlCol: 2
Bên trong section thêm các Component (Textbox, Number, …) → tự xếp vào lưới 2 cột.
Cho 1 component span nhiều cột
Component.Column (colSpan) — mỗi component có thể chiếm nhiều ô:
var colSpan = ui.Column ?? 2; // mặc định = 2 (Section.cs:759)
Ví dụ trong section 4 cột, đặt Component.Column = 4 cho 1 component → chiếm cả hàng.
Layout pattern thường gặp trong Core
| Mục đích | ClassName (set trên ComponentGroup) | Ghi chú |
|---|---|---|
| Form responsive grid | (để rỗng, dùng Column field) | Framework auto set grid + style. |
| Bootstrap row | row + child có col-md-6, … | Dùng khi tự kiểm soát cột. |
| Container fluid | container-fluid | Wrap toàn form full-width. |
| Ribbon collapsible | ribbon | Tự thêm icon collapse + dropdown. |
| Default panel | panel group | Style chuẩn của framework. |
| Ẩn mặc định | default-hide | Section ẩn ngay khi render. |
Pattern trực tiếp trong
Section.cs: nếuClassNamechứa"ribbon"thì render kiểu ribbon collapsible; chứa"default-hide"thì ẩn ngay; còn lại thêmpanelgroup.
Layout dạng table (ui-layout)
Khi cần label cố định cột trái + value cột phải kiểu form truyền thống, framework có pattern table-based:
Html.Instance.Table.ClassName("ui-layout").TBody.TRow.Render();
Tự động render <table class="ui-layout"> với <tr> cho mỗi component, cột trái là label (label-header), cột phải là widget. Pattern này active khi section có loại đặc biệt — xem RenderInputLabel trong Section.cs:483.
Layout custom thủ công
Nếu 5 field *Col chưa đủ, vẫn còn 2 đường:
-
Set
ClassNamethành CSS class do bạn tự define — viết flex/grid riêng trong file CSS dự án. Section render sẽ áp class đó lên element ngoài, mọi child component nhận layout từ class.ClassName: my-custom-layoutTrong file CSS:
.my-custom-layout { display: grid; grid-template-columns: 200px 1fr 200px; gap: 1rem; } -
Subclass
Section. OverrideRender()đặt children thủ công. SetComponentGroup.ComType = "MyCustomSection"để runtime instantiate subclass của bạn.
Ưu tiên dùng *Col field trước — DB-driven và responsive sẵn. CSS class custom khi cần layout đặc biệt (sidebar, masonry, …). Subclass Section chỉ khi không cách nào khác.
Visibility expression
ComponentGroup.Visibility (và Component.Visibility) chứa expression evaluate trên entity. False → ẩn section/component. Hữu ích cho “chỉ show panel khi status = Approved”.
Evaluator nằm trong EditableComponent.Extensions — xem đó để biết syntax.
Các kiểu section thường gặp
| Mục đích | ElementType | ClassName | Ghi chú |
|---|---|---|---|
| Form row | div | row | Chứa 1+ input đặt cạnh nhau. |
| Card / panel | div | card / panel | Heading + body section. |
| Cell trong table | td | (tuỳ) | 1 component cho cell grid. |
| Tab pane | div | tab-pane | Dùng với TabComponent strip. |
| Inline label group | fieldset | field-group | Wrap input liên quan + legend. |
Field DB Section thực dùng
(Trích từ Section.cs + EditForm.GetInnerColumn — chỉ field thực sự được đọc:)
ComponentGroup.ClassName— class CSS gắn lên element.ComponentGroup.ElementType— tag HTML render ra.ComponentGroup.Component— children.ComponentGroup.Label— text label (cho ribbon, fieldset).ComponentGroup.Visibility— expression ẩn/hiện theo entity.ComponentGroup.IsCollapsible— kết hợpribbonđể cho phép thu/mở.ComponentGroup.XsCol/SmCol/Column/LgCol/XlCol— số cột grid theo breakpoint.ComponentGroup.ParentId— section cha (cây).ComponentGroup.Order— thứ tự giữa siblings.
(Liên kết với FeatureId, load + BuildTree do framework xử lý, Section bản thân không touch.)
Tip
- Đừng nest quá sâu. Mỗi section là 1 element DOM + iteration. Phẳng-nhưng-có-class nhanh hơn sâu-mặc-định.
ComponentGroup.ClassNameđược append raw — tránh khoảng trắng trong field user-edit được.- Section render rỗng → kiểm tra children
Active = truevàFeatureIdkhớp parent feature.