Files
chapter-organizer/WebApp/Components/Shared/Components/FormChangeTracker.razor
T

94 lines
2.8 KiB
Plaintext

@namespace WebApp.Components.Shared.Components
@implements IDisposable
@inject IDialogService DialogService
@inject NavigationManager NavigationManager
@code {
[CascadingParameter]
private EditContext? EditContext { get; set; }
[Parameter]
public EditContext? ExplicitEditContext { get; set; }
[Parameter]
public bool Enabled { get; set; } = true;
private bool _isDirty = false;
private bool _allowNavigation = false;
private IDisposable? _navigationRegistration;
protected override void OnInitialized()
{
var contextToUse = ExplicitEditContext ?? EditContext;
if (contextToUse == null)
{
throw new InvalidOperationException("FormChangeTracker requires an EditContext. Either provide it as a cascading parameter or through the ExplicitEditContext parameter.");
}
// Subscribe to field changes to detect when form becomes dirty
contextToUse.OnFieldChanged += HandleFieldChanged;
// Register navigation handler to intercept navigation attempts
_navigationRegistration = NavigationManager.RegisterLocationChangingHandler(OnLocationChanging);
}
private void HandleFieldChanged(object? sender, FieldChangedEventArgs e)
{
if (Enabled)
{
_isDirty = true;
}
}
private async ValueTask OnLocationChanging(LocationChangingContext context)
{
// Allow navigation if form isn't dirty, navigation is explicitly allowed, or tracking is disabled
if (!_isDirty || _allowNavigation || !Enabled)
{
return;
}
// Show confirmation dialog
var result = await DialogService.ShowMessageBox(
"Unsaved Changes",
"You have unsaved changes. Are you sure you want to leave this page?",
yesText: "Leave",
cancelText: "Stay");
// If user chooses to stay (result is null or false), prevent navigation
if (result != true)
{
context.PreventNavigation();
}
}
/// <summary>
/// Call this method before programmatic navigation to bypass the unsaved changes warning.
/// Use this when the form has been successfully saved or when the user explicitly cancels.
/// </summary>
public void AllowNavigation()
{
_allowNavigation = true;
}
/// <summary>
/// Reset the dirty state of the form. This marks the form as clean and resets the navigation flag.
/// </summary>
public void MarkClean()
{
_isDirty = false;
_allowNavigation = false;
}
public void Dispose()
{
var contextToUse = ExplicitEditContext ?? EditContext;
if (contextToUse != null)
{
contextToUse.OnFieldChanged -= HandleFieldChanged;
}
_navigationRegistration?.Dispose();
}
}