Joe Higley
Joe Higley

Reputation: 1842

How to change date input value on change in Blazor

I'm trying to force the date selected in a date input to the Sunday of the week of the date actually selected by the user. So if they pick Wednesday, it will actually change to the Sunday of the same week.

I've managed to do this but when I reselect a date in the same week again it doesn't work. As an example, when the user selects Wednesday, it successfully selects Sunday. But then when they go and select Tuesday instead, it keeps the displayed value as Tuesday instead of changing it to Sunday (which is what I'd want it to do)

Here's some example code

<input type="date" value="@overrideStart.ToString("yyyy-MM-dd")" @onchange="@SelectStartOfWeek" />

@code {
    private DateTime overrideStart = DateTime.Today;

    protected override async Task OnInitializedAsync()
    {
        overrideStart = GetStartOfWeek(overrideStart)
    }

    public async Task SelectStartOfWeek(ChangeEventArgs args)
    {
        var value = args.Value.ToString();
        overrideStart = value == string.Empty ? DateTime.Today : DateTime.Parse(value);

        overrideStart = await GetStartOfWeek(overrideStart);
    }
    private async Task<DateTime> GetStartOfWeek(DateTime date)
    {
        return date.AddDays(-(int)date.DayOfWeek);
    }
}

Obviously the issue is because it recognizes that overrideStart ends up with the same value after SelectStartOfWeek finishes. I've tried StateHasChanged() but it doesn't seem to have any effect.

Upvotes: 4

Views: 7161

Answers (2)

MrC aka Shaun Curtis
MrC aka Shaun Curtis

Reputation: 30036

Another approach using the setter on a property. This works standalone and the EditForm context.

@page "/MyDate"
<h3>MyDate Editor</h3>
<EditForm EditContext="editContext">
    <InputDate @bind-Value="model.MyDate"></InputDate>
</EditForm>
<input type="date" @bind-value="this.MyDate" />

@code {

    private dataModel model { get; set; } = new dataModel();
    private EditContext editContext;

    protected override Task OnInitializedAsync()
    {
        this.editContext = new EditContext(model);
        return base.OnInitializedAsync();
    }


    public class dataModel
    {
        public DateTime? MyDate
        {
            get => _myDate;
            set
            {
                if (value != null)
                {
                    var date = (DateTime)value;
                    _myDate = date.AddDays(-(int)date.DayOfWeek);
                }
            }
        }
        private DateTime? _myDate;
    }

    public DateTime? MyDate
    {
        get => _myDate;
        set
        {
            if (value != null)
            {
                var date = (DateTime)value;
                _myDate = date.AddDays(-(int)date.DayOfWeek);
            }
        }
    }
    private DateTime? _myDate;
}

Upvotes: 4

Mister Magoo
Mister Magoo

Reputation: 8964

You have correctly identified the issue, but I think there are only hacky ways of avoiding this optimisation.

One such way is to change something else on the element, like a @key which will force Blazor to replace the entire element.

<input 
    @key="@toggle"
    type="date" 
    value="@overrideStart.ToString("yyyy-MM-dd")" 
    @onchange="@SelectStartOfWeek" />

@code {
    bool toggle;
    private DateTime overrideStart = DateTime.Today;

    protected override async Task OnInitializedAsync()
    {        
        overrideStart = await GetStartOfWeek(overrideStart);
    }

    public async Task SelectStartOfWeek(ChangeEventArgs args)
    {
        var value = args.Value.ToString();
        overrideStart = value == string.Empty ? DateTime.Today : DateTime.Parse(value);

        overrideStart = await GetStartOfWeek(overrideStart);
        toggle = !toggle;

    }
    private ValueTask<DateTime> GetStartOfWeek(DateTime date)
    {
        return ValueTask.FromResult(date.AddDays(-(int)date.DayOfWeek));
    }
}

Upvotes: 2

Related Questions