I'm using the built in ASPNETCORE.Component.Forms InputDate but when selecting a date it does not override the UI when assigning another value it's always the selectedDate.
<InputDate ValueExpression="@(()=>MyModel.TestDate)"
Value="MyModel.TestDate"
ValueChanged="@((DateTime value) => CheckDate(value))"/>
private void CheckDate(DateTime selectedDate)
{
if (selectedDate < DateTime.Now)
{
MyModel.TestDate = selectedDate;
}
else
{
MyModel.TestDate = DateTime.Now; // Issue here UI does not updates
}
StateHasChanged();
}
using WebAssembly 5.0.7
This is a difficult one to explain.
Starting point: The current displayed value is today, 7-Sep-2023.
When you change the data in the input to 8-Sep-2023 the new value gets passed back to InputDate
though the OnChange
event. At this point Value
in InputDate
is 7-Sep-2023: there's a data inconsistency. MyModel.TestDate
is also set to 7-Sep-2023, and the value held in the Renderer's ParameterView
is 7-Sep-2023.
In your CheckDate
code the new value is out of range, so you set MyModel.TestDate
to 7-Sep-2023. You don't need to, it's still 7-Sep-2023: you haven't changed it.
When the parent component renders, the value hasn't changed so 7-Sep-2023 is passed into the component as Value
. InputDate
will always render in the cascade as ValueExpression
and ValueExpression
are objects: as reference types the Renderer can't be sure if they have changed, so it renders anyway.
InputDate
still believes the value is 7-Sep-2023. Remember the data inconsistency in the first paragraph.
Important bit The virtual DOM also believes it's 7-Sep-2023, so the diffing process doesn't see a change, and therefore doesn't refresh the raw input [which is actually at 8-Sep-2023]. It stays on the new value.
The way to solve this dilemma is:
MyModel.TestDate
get set to the new valueawait Task.Delay(1)
which allows a render to reset the values to the new one in the render chain.Here's some demo code showing two ways to wire this up.
@page "/"
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
<InputDate class="mb-3" ValueExpression="@(()=>MyModel.TestDate)"
Value="MyModel.TestDate"
ValueChanged="@((DateTime value) => CheckDate(value))" />
<InputDate class="form-control mb-3" @bind-Value="this.MyModel.TestDate1" @bind-Value:after="this.ValidateDate" />
<div class="bg-dark text-white m-3 p-2">
<pre>Date : @MyModel.TestDate.ToShortDateString()</pre>
<pre>Date1 : @MyModel.TestDate1.ToShortDateString()</pre>
</div>
@code {
private Model MyModel = new();
private async Task ValidateDate()
{
await Task.Delay(1);
if (MyModel.TestDate1 >= DateTime.Now)
MyModel.TestDate1 = DateTime.Now; // Issue here UI does not updates
}
private async Task CheckDate(DateTime selectedDate)
{
MyModel.TestDate = selectedDate;
await Task.Delay(1);
if (selectedDate >= DateTime.Now)
MyModel.TestDate = DateTime.Now; // Issue here UI does not updates
}
public class Model
{
public DateTime TestDate { get; set; }
public DateTime TestDate1 { get; set; }
}
}