I have a component that will pop-up a dialog asking if you're sure you want to discard changes when switching to a different page. I put it on each page as follows:
<ConfirmNavigation HasUnsavedChanges="@HasUnsavedChanges" />
And this component includes:
[Parameter]
public bool HasUnsavedChanges { get; set; }
private async Task OnBeforeInternalNavigation(LocationChangingContext context)
{
if (!HasUnsavedChanges)
return;
My problem is that in the parent page, handling the submit click, I have:
HasUnsavedChanges = false;
await Task.Delay(1);
Navigation.NavigateTo(gotoUrl);
That doesn't work. The method returns after those 2 lines of code and ConfirmNavigation
still considers HasUnsavedChanges
to be true.
Is there a way to do something so that the changed value of HasUnsavedChanges
makes it to ConfirmNavigation
? Is my best bet to add a method to ConfirmNavigation
that sets the value? I dislike that because it is going around the HasUnsavedChanges="@HasUnsavedChanges"
which violates how components are supposed to interact.
Your problem is this. When you set
HasUnsavedChanges = false;
in the parent you're assigning false
to a global variable in the parent.
That value only gets applied to the property HasUnsavedChanges
in the child when parameters.SetParameterProperties(this);
is called in SetParametersAsync
during a render cascade triggered by a render event in the parent.
bool
is a value type.
You can document the order of execution by adding this to ConfirmNavigation
public override Task SetParametersAsync(ParameterView parameters)
{
parameters.SetParameterProperties(this);
Console.WriteLine("ConfirmNavigation => SetParameterProperties called");
return base.SetParametersAsync(ParameterView.Empty);
}
And console logging to OnBeforeInternalNavigation
.
The simplest solution to your logic is to pass a mutable object as a parameter instead of a bool.
public sealed NavigationData
{
public bool HasUnsavedChanges {get; set;}
}
You're now passing a reference, so both components are looking at the same thing. You can almost certainly loose the await Task.Delay(1);
The whole prevent navigation operation is a little tricky to code. The handler registered in RegisterLocationChangingHandler
is called from the Navigation Manager. You have limited control over the execution order of code.
Adding console logging will show you the order in which the code executes.
I'm not a fan of lobbing in an await Task.Delay(1);
unless absolutely necessary, I can't think of a better way, and I understand exactly why.