havit / Havit.Blazor

Free Bootstrap 5 components for ASP.NET Blazor + optional enterprise-level stack for Blazor development (gRPC code-first, layered architecture, localization, auth, ...)
https://havit.blazor.eu
MIT License
490 stars 67 forks source link

[HxInputDate] Not invoke field change #83

Closed petrkasnal closed 2 years ago

petrkasnal commented 2 years ago

Hi, i maybe found little bug in component hxinputdate. But i'm not really sure if it is a bug. When is value changed component only notification validation state changed but don't notification field changed. Normally is invoke field change too. I use it for show/hide submit button. But maybe i haven't right and this is correct behaviour.

Thank you very much. :) image

hakenr commented 2 years ago

Hi @petrkasnal, the ValueChanged and editContext.NotifyFieldChanged callbacks are called from CurrentValue property setter (InputBase). These are called only when the value gets parsed correctly. See https://github.com/dotnet/aspnetcore/blob/e0110ad9ea7e7ba646aff35832fedb5a588c6e1d/src/Components/Web/src/Forms/InputBase.cs#L72-L81

petrkasnal commented 2 years ago

@hakenr thank you for response. I understand, but when you insert correctly date and after write something incorrect like text the NotifyFieldChange isn't invoke. And i can't update my property FormValid. I update button state on OnFieldChange, beacuse i found many tutorials on this. Or should i update FormValidate property another way? I tried update my property in event OnValidationStateChanged with method Validate But then it's called over and over again. Can you tell me how to do another way please? When i try your HxInputNumber it works just like that.

InputNumber: ezgif-2-bd4844f661

InputDate ezgif-2-a9086e5bd2

hakenr commented 2 years ago

Aah, I see. Unfortunately, you are hitting behavior we are currently trying to fix in Blazor itself. See https://github.com/dotnet/aspnetcore/issues/40097 and related PRs.

(The HxInputNumber currently has a built-in workaround/hack which helps with the behavior, but we want this to be solved properly and thus we are trying to fix Blazor InputBase itself.)

Anyway, the EditContext.OnFieldChanged is defined as

An event that is raised when a field value changes.

But the field value does not change when the input text is not valid. I think that OnValidationStateChanged should be a better fit. You said you tried that without success. How did your code looked like?

petrkasnal commented 2 years ago

Aaah ok thank you very much :) I'll look forward to it.

I try it like this. But it's logicaly again call this method to infinite. How i can do it correctly please? On google i can find only solution with field changed. Thank you image

hakenr commented 2 years ago

@jirikanda The bahavior of HxInputNumber and HxInputDate should be aligned.

petrkasnal commented 2 years ago

@jirikanda The bahavior of HxInputNumber and HxInputDate should be aligned.

Thank you very much :)

hakenr commented 2 years ago

Not fixed/verified yet, just a comment for my colleague. :-D

jirikanda commented 2 years ago

Implementation details:

The small difference can be hidden in this line in CurrentValue setter - it means when the value is fixed (modified) to the previosly valid value, CurrentValue does not notify the change.

But when you implement the form well, I believe it works as expected.

@page "/Issue83Test"

<h1>Issue 83</h1>

<EditForm EditContext="@numberEditContext">
    <HxInputNumber @bind-Value="@numberModel.Value" Label="Number" />
    <HxButton Text="Submit" Enabled="@(!numberEditContext.GetValidationMessages().Any())" Color="ThemeColor.Primary" />
</EditForm>

<EditForm EditContext="@dateEditContext">
    <HxInputDate @bind-Value="@dateModel.Value" Label="Date" />
    <HxButton Text="Submit" Enabled="@(!dateEditContext.GetValidationMessages().Any())" Color="ThemeColor.Primary" />
</EditForm>

@code
{
    private EditContext numberEditContext;
    private GenericModel<int> numberModel;

    private EditContext dateEditContext;
    private GenericModel<DateTime> dateModel;

    private void HandleValidationStateChanged(object sender, ValidationStateChangedEventArgs args)
    {
        StateHasChanged();
    }

    protected override void OnInitialized()
    {
        base.OnInitialized();

        numberModel = new GenericModel<int>();
        numberEditContext = new EditContext(numberModel);
        numberEditContext.OnValidationStateChanged += HandleValidationStateChanged;

        dateModel = new GenericModel<DateTime>();
        dateEditContext = new EditContext(numberModel);
        dateEditContext.OnValidationStateChanged += HandleValidationStateChanged;
    }

    private class GenericModel<T>
    {
        public T Value { get; set; }
    }
}