noel
noel

Reputation: 543

How can I use the MudBlazor DatePicker EventCallback?

I´m trying to use MudBlazor DatePicker in my web application.

When I´m using it with @bind-Date the way it´s described in the documentation

Note: Always use the two-way binding @bind-Date to bind to a field of type DateTime?

like this...

<MudDatePicker
            Editable="true"
            @bind-Date="@InternalDate"
            Clearable=true           
            DateFormat="@CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern"
            Mask="@(new DateMask(CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern))" />

it works as I expect it to.

Except this way I can´t invoke anything when InternalDate changes...the way I´ve set up my form fields is that I actually need to invoke my own EventCallBack<DateTime?>, which will then be used by the encapsulation component to set property values through reflection and trigger stuff like validating the model.

With all other MudBlazor entry field components I could simply pass down some Value and ValueChanged properties and everything worked, but if I try that with DatePicker like this...

<MudDatePicker
            Editable="true"
            Date="@InternalDate"
            DateChanged="InternalDateChanged"
            Clearable=true           
            DateFormat="@CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern"
            Mask="@(new DateMask(CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern))" />

I get weird behavior. It then only works when picking with the calendar. Editing the date directly in text causes InternalDateChanged to be invoked twice. Once with the correct value, once with the old previous value.

The behavior is the same if I try to invoke from the setter. The setter gets called twice.

private DateTime? InternalDate 
{
    get => Value;
    set {
        Value = value;
        ValueChanged.InvokeAsync(value);
    }
}

It stops doing the second unwanted invokation if I remove the DateFormat and Mask...but that's not really a solution...

Is there anything else I can do to have this component work and still get some kind of notification when InternalDate changes?

Upvotes: 1

Views: 3336

Answers (1)

MrC aka Shaun Curtis
MrC aka Shaun Curtis

Reputation: 30036

As a starting point to identify your problem here are several implementations of the MudDatePicker with different ways of setting values and driving events that I used to try and produce a "minimum reproducable example" of your issue.

They all work as I expect them to. What am I missing? Can you use this code to reproduce your issue?

@page "/"
@using System.Globalization
<PageTitle>Index</PageTitle>

<MudText Typo="Typo.h3" GutterBottom="true">Date Test</MudText>

<div class="m-2">
    <MudDatePicker Editable="true"
                   @bind-Date="@date1"
                   Clearable=true
                   DateFormat="@CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern"
                   Mask="@(new DateMask(CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern))" />

    <MudDatePicker Editable="true"
                   Date=@date2
                   DateChanged=@OnDateChanged
                   Clearable=true
                   DateFormat="@CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern"
                   Mask="@(new DateMask(CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern))" />

    <MudDatePicker Editable="true"
                   @bind-Date="@date3"
                   Clearable=true
                   DateFormat="@CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern"
                   Mask="@(new DateMask(CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern))" />
</div>

<MudAlert Severity="Severity.Normal" class="mt-4">
    Date1 :@date1
</MudAlert>

<MudAlert Severity="Severity.Info" class="mt-4">
    Date2: @date2
</MudAlert>

<MudAlert Severity="Severity.Warning" class="mt-4">
    Date3: @date3
</MudAlert>

<MudAlert Severity="Severity.Success" class="mt-4">
    @message
</MudAlert>

@code {
    DateTime? date1 = DateTime.Today;
    DateTime? date2 = DateTime.Today;

    DateTime? _date3 = DateTime.Today;
    DateTime? date3 {
        get => _date3;
        set {
            if (!_date3.Equals(value))
            {
                _date3 = value;
                ValueChanged?.Invoke(value);
            }
        }
    }

    private Action<DateTime?>? ValueChanged;

    private string message = $"Not Set";

    public Index()
        => ValueChanged = this.SetValue;

    private Task OnDateChanged(DateTime? value)
    {
        date2 = value;
        message = $"Current date set to {date2?.ToString("dd-MMM-yyyy")}";
        // Do something Async
        return Task.Delay(10);
    }

    private void SetValue(DateTime? value)
    => message = $"Current date set to {value?.ToString("dd-MMM-yyyy")}";

}

Upvotes: 1

Related Questions