Core Docs

PopupEditor (modal popup)

Dùng PopupEditor khi muốn 1 form mở chồng lên màn hình hiện tại — sửa 1 record, dialog confirm, picker.

Khi nào dùng PopupEditor?

Dùng khi user không rời màn hình hiện tại — chỉ mở 1 form chồng lên để làm 1 việc nhanh, xong đóng quay về.

Ví dụ điển hình:

  • Sửa 1 record: list xe hiển thị → double-click row → popup edit chi tiết xe.
  • Dialog confirm: hỏi “có chắc muốn xóa?” + textarea lý do.
  • Picker phức tạp: chọn khách hàng có filter nhiều trường (search nâng cao).

→ Cần màn hình đứng độc lập mà user có thể mở nhiều cùng lúc → dùng TabEditor thay vì PopupEditor.

Khai báo class

using Core.Components.Forms;
using TMS.API.Models;

namespace TMS.UI.Business.Freight
{
    public class CustomerDetailBL : PopupEditor
    {
        public CustomerDetailBL() : base(nameof(Customer))
        {
            Title = "Sửa khách hàng";
            Icon  = "icons/edit.png";
        }
    }
}

Y hệt cách viết TabEditor, chỉ khác kế thừa PopupEditor. Core sẽ render thành modal có backdrop + draggable header thay vì tab.

Mở popup từ code

// Helper Popup() — mở 1 popup
await this.Popup(nameof(Customer), () => new CustomerDetailBL
{
    Entity = customer,   // pass entity vào để edit
});

Nếu cần ID ổn định (để mở popup cùng record 2 lần thì focus popup cũ):

await this.OpenTab(
    "Customer_" + customer.Id,
    "Customer",
    () => new CustomerDetailBL { Entity = customer },
    popup: true);

Property hay set

Giống TabEditor, plus:

PropertyMục đích
TitleTiêu đề trên header popup.
EntityEntity được edit. Quan trọng: PopupEditor mặc định ShouldLoadEntity = false — bạn phải tự set Entity trong factory hoặc bật ShouldLoadEntity = true để Core load.
IconIcon trên header.
ChildFormTrue → khi đóng, không refresh parent (mặc định false sẽ refresh).

Pattern: list mở popup edit

Đây là pattern thường gặp nhất — list TabEditor mở chi tiết PopupEditor:

public class CustomerListBL : TabEditor
{
    public CustomerListBL() : base(nameof(Customer))
    {
        Title = "Khách hàng";
        DOMContentLoaded += () =>
        {
            var grid = this.FindComponentByName<GridView>("Grid");
            if (grid != null)
            {
                grid.DblClick = row =>
                {
                    var customer = (Customer)row;
                    this.OpenTab("Customer_" + customer.Id, "CustomerEditor",
                        () => new CustomerDetailBL { Entity = customer },
                        popup: true);
                };
            }
        };
    }

    // Button "Thêm mới" — config row Component có Events="AddNew"
    public void AddNew(object arg)
    {
        this.Popup(nameof(Customer), () => new CustomerDetailBL
        {
            Entity = new Customer { Active = true }
        });
    }
}

Đóng popup

User tự đóng qua nút X trên header. Hoặc auto đóng sau khi save:

public class CustomerDetailBL : PopupEditor
{
    public CustomerDetailBL() : base(nameof(Customer))
    {
        Title = "Sửa khách hàng";
        AfterSaved = ok => { if (ok) Dispose(); };  // đóng nếu save success
    }
}

ConfirmDialog — popup nhỏ chuyên biệt

Cho yes/no đơn giản, không cần viết hẳn 1 class PopupEditor — dùng ConfirmDialog có sẵn:

var confirm = new ConfirmDialog
{
    Title     = "Xác nhận",
    Content   = "Bạn có chắc muốn xóa các dòng đã chọn?",
    NeedAnswer = false,    // true → có thêm textarea nhập lý do
    TabEditor = TabEditor, // anchor vào tab/popup hiện tại
};
confirm.YesConfirmed += async () =>
{
    // user bấm Yes
    await DeleteRows();
    Toast.Success("Đã xóa");
};
confirm.Render();

→ Pattern thực từ TMS.UI/Business/Freight/CoordinationContainerBL.cs.

Bẫy hay gặp

  • Quên set Entity trong factory → form trống. PopupEditor không auto-load (default ShouldLoadEntity = false).
  • Pop-up trong pop-up trong pop-up → UX rất khó dùng. Cân nhắc lại design (thường dùng grid inline edit hoặc panel side-by-side thay vì 3 cấp popup).
  • Quên confirm.Render() với ConfirmDialog → dialog không hiện. (Sự khác biệt với Popup() extension — ConfirmDialog cần gọi Render() thủ công.)

Pattern thực từ TMS.UI

  • TMS.UI/Business/Freight/DriverContainerDetailBL.cs — popup chi tiết tài xế-container, override Save validate, AfterSaved refresh, mở popup con khác (TruckStopHistory).
  • TMS.UI/Business/Freight/DriverTruckDetailBL.cs — popup chi tiết tài xế-xe.

Core Docs · Astro · Core.API/wwwRoot/docs