BÀI 04Tương tác
EditForm
Tạo biểu mẫu có kiểm tra dữ liệu, hiển thị lỗi đúng chỗ và xử lý khi người dùng gửi thông tin.
Giải thích, ví dụ & thực hành
Tất cả bài học
Thử cả dữ liệu đúng và dữ liệu sai
Gửi một form trống để xem thông báo lỗi, sau đó điền đủ thông tin và gửi lại. Mỗi ví dụ có trạng thái và nút đặt lại riêng để bạn dễ đối chiếu.
01 · EditForm cơ bản và thông báo lỗi
Status: none
Xem code
@page "/editform-demo"
<EditForm Model="@BasicModel"
OnValidSubmit="Basic_OnValidSubmit"
OnInvalidSubmit="Basic_OnInvalidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<InputText class="form-control" @bind-Value="BasicModel.Name" />
<ValidationMessage For="@(() => BasicModel.Name)" />
<InputText class="form-control" @bind-Value="BasicModel.Email" />
<ValidationMessage For="@(() => BasicModel.Email)" />
<button type="submit">Submit</button>
</EditForm>
@code {
private BasicUser BasicModel = new();
private string BasicStatus = "none";
private void Basic_OnValidSubmit()
=> BasicStatus = $"✅ Valid: {BasicModel.Name} - {BasicModel.Email}";
private void Basic_OnInvalidSubmit()
=> BasicStatus = "❌ Invalid submit";
private void Basic_Reset()
{
BasicModel = new();
BasicStatus = "reset";
}
public class BasicUser
{
[Required, StringLength(30)]
public string Name { get; set; } = "";
[Required, EmailAddress]
public string Email { get; set; } = "";
}
}
02 · Các loại input và kết quả gửi form
Xem code
<EditForm Model="@FullModel"
OnValidSubmit="Full_OnValidSubmit"
OnInvalidSubmit="Full_OnInvalidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<InputText class="form-control" @bind-Value="FullModel.Username" />
<ValidationMessage For="@(() => FullModel.Username)" />
<InputNumber class="form-control" @bind-Value="FullModel.Age" />
<ValidationMessage For="@(() => FullModel.Age)" />
<InputSelect class="form-select" @bind-Value="FullModel.Role">...</InputSelect>
<ValidationMessage For="@(() => FullModel.Role)" />
<InputDate class="form-control" @bind-Value="FullModel.Birthday" />
<ValidationMessage For="@(() => FullModel.Birthday)" />
<InputText type="password" class="form-control" @bind-Value="FullModel.Password" />
<ValidationMessage For="@(() => FullModel.Password)" />
<InputText type="password" class="form-control" @bind-Value="FullModel.ConfirmPassword" />
<ValidationMessage For="@(() => FullModel.ConfirmPassword)" />
<InputCheckbox class="form-check-input" @bind-Value="FullModel.Accepted" />
<ValidationMessage For="@(() => FullModel.Accepted)" />
<button type="submit">Submit</button>
</EditForm>
@code {
private FullUser FullModel = new();
private string FullStatus = "none";
private void Full_OnValidSubmit() => FullStatus = "✅ Valid submit";
private void Full_OnInvalidSubmit() => FullStatus = "❌ Invalid submit";
private void Full_Reset()
{
FullModel = new();
FullStatus = "reset";
}
public class FullUser
{
[Required, StringLength(20, MinimumLength = 3)]
public string Username { get; set; } = "";
[Range(18, 60)]
public int Age { get; set; } = 18;
[Required]
public string Role { get; set; } = "";
[Required]
public DateTime? Birthday { get; set; } = DateTime.Today;
[Required, MinLength(6)]
public string Password { get; set; } = "";
[Compare(nameof(Password), ErrorMessage = "Passwords do not match")]
public string ConfirmPassword { get; set; } = "";
[Range(typeof(bool), "true", "true", ErrorMessage = "You must accept terms")]
public bool Accepted { get; set; }
}
}
03 · EditContext — theo dõi trường đã thay đổi
Xem code
<EditForm EditContext="@TrackContext" OnSubmit="Track_OnSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<InputText class="form-control" @bind-Value="TrackModel.Title" />
<ValidationMessage For="@(() => TrackModel.Title)" />
<InputNumber class="form-control" @bind-Value="TrackModel.Quantity" />
<ValidationMessage For="@(() => TrackModel.Quantity)" />
<button type="submit">Submit</button>
</EditForm>
@code {
private TrackItem TrackModel = new();
private EditContext TrackContext = default!;
private HashSet<string> DirtyFields = new();
private string TrackStatus = "none";
protected override void OnInitialized()
{
TrackContext = new EditContext(TrackModel);
TrackContext.OnFieldChanged += Track_OnFieldChanged;
}
private void Track_OnFieldChanged(object? sender, FieldChangedEventArgs e)
=> DirtyFields.Add(e.FieldIdentifier.FieldName);
private void Track_OnSubmit()
{
var ok = TrackContext.Validate(); // validate thủ công
TrackStatus = ok ? "✅ Valid" : "❌ Invalid";
}
private void Track_Reset()
{
DirtyFields.Clear();
TrackStatus = "reset";
TrackContext.OnFieldChanged -= Track_OnFieldChanged;
TrackModel = new TrackItem();
TrackContext = new EditContext(TrackModel);
TrackContext.OnFieldChanged += Track_OnFieldChanged;
}
public class TrackItem
{
[Required]
public string Title { get; set; } = "";
[Range(1, 999)]
public int Quantity { get; set; } = 1;
}
}
04 · Kiểm tra riêng bằng ValidationMessageStore
Xem code
<EditForm EditContext="@CustomContext" OnSubmit="Custom_OnSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<InputText class="form-control" @bind-Value="CustomModel.Username" />
<ValidationMessage For="@(() => CustomModel.Username)" />
<button type="submit">Submit</button>
</EditForm>
@code {
private CustomUser CustomModel = new();
private EditContext CustomContext = default!;
private ValidationMessageStore CustomStore = default!;
private string CustomStatus = "none";
protected override void OnInitialized()
{
CustomContext = new EditContext(CustomModel);
CustomStore = new ValidationMessageStore(CustomContext);
}
private void Custom_OnSubmit()
{
// 1) Clear lỗi custom cũ
CustomStore.Clear();
// 2) Validate theo DataAnnotations
var ok = CustomContext.Validate();
// 3) Rule custom: username bị trùng
var taken = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{ "admin", "root" };
if (!string.IsNullOrWhiteSpace(CustomModel.Username) && taken.Contains(CustomModel.Username))
{
ok = false;
CustomStore.Add(
CustomContext.Field(nameof(CustomModel.Username)),
"Username already exists."
);
// báo Blazor cập nhật validation UI
CustomContext.NotifyValidationStateChanged();
}
CustomStatus = ok ? "✅ Valid" : "❌ Invalid";
}
private void Custom_Reset()
{
CustomModel = new CustomUser();
CustomStatus = "reset";
CustomContext = new EditContext(CustomModel);
CustomStore = new ValidationMessageStore(CustomContext);
}
public class CustomUser
{
[Required, StringLength(20, MinimumLength = 3)]
public string Username { get; set; } = "";
}
}