Blazorise: EditContext.OnFieldChanged not fired for Blazorise inputs?

Created on 19 Jun 2020  ·  11Comments  ·  Source: stsrki/Blazorise

Razor code

<EditForm Model="person" Context="editContext">
    @{
        editContext.OnFieldChanged += (sender, eventArgs) =>
        {
            Console.WriteLine("OnFieldChanged for FieldName = " + eventArgs.FieldIdentifier.FieldName);
        };
    }

    <Field>
        <NumericEdit @bind-Value="person.Age"></NumericEdit>
    </Field>

    <Column ColumnSize="ColumnSize.Is2">
        <InputNumber @bind-Value="person.Age" />
    </Column>

    <button type="submit">Save</button>
</EditForm>

Problem

The OnFieldChanged-event is not fired when NumericEdit is changed. But it's fired when InputNumber is changed.

Feature Request ⛱

Most helpful comment

It would be very nice if the Blazorise Input Components could utilize EditContext/EditForm if it exists.

I personally have a ton of Fluent Validation validators and for this reason I am sticking to EditForm. (Which makes the Blazorise Input Components/Validations far less appealing - but using everything else provided by Blazorise and enjoying it!).

There's also the point of being easier to integrate third party components since they are very likely to depend on EditForm.

All 11 comments

Blazorise does not use EditForm so it cannot fire the OnFieldChanged event. Internally it only uses EditContext, but only partially to make the data annotations work with validation. I don't have any plan to support EditForm at this moment.

Hello @stsrki,

Is there any other clever way of making the OnFieldChanged work for any Blazorise edit component?

I got this workaround:
Razor

<NumericEdit TValue="int" Value="person.Age" ValueChanged="@((v) => ValueChanged(v, editContext))" ></NumericEdit>

````
&
c#
``` c#
void ValueChanged(int value, EditContext context)
    {
        Console.WriteLine("OnFieldChanged !! " + value);

        person.Age = value;

        context.NotifyFieldChanged(new FieldIdentifier(person, "Age"));
    }

But this is just a work-acound to use ValueChanged to notify the context that a field has been changed (e.g. so I can execute my custom valiation)

That seems like a valid approach, if you want to use EditForm.

Is there any reason why you dont use Blazorise Validations component?

  1. It's valid code, however I don't want to add that ValueChanged to all my input fields, it's very verbose

  2. Using a EditForm is not mandatory, however this is a component which defines the EditContext I believe? And I want to use that EditContext.

  3. This question is related to : https://github.com/stsrki/Blazorise/issues/995
    I want to use one of these packages to use automatic FluentValidation, so not coding all Validations manually.

<PackageReference Include="Blazored.FluentValidation" Version="1.3.0" />
<PackageReference Include="Accelist.FluentValidation.Blazor" Version="2.1.0" />

To tell you the truth I don't see much value from using FluentValidation instead of built-in support for validators or data annotations. But, I understand if that is something people wish to use.

Now back to our problem here. From what I can see the biggest issue is that EditContext if not rightly shared between components. Internally it is used, and it calls EditContext.NotifyFieldChanged( fieldIdentifier ); but I will need to figure why it's not working with EditForm.

I did try something: extending the NumericEdit 👍
w
``` c#
public class NumericEdit2 : NumericEdit
{
[CascadingParameter]
EditContext CascadedEditContext { get; set; }

    protected FieldIdentifier FieldIdentifier { get; set; }

    protected override void OnInitialized()
    {
        FieldIdentifier = FieldIdentifier.Create(ValueExpression);

        base.OnInitialized();
    }

    protected async override Task OnInternalValueChanged(TValue value)
    {
        await base.OnInternalValueChanged(value);

        if (CascadedEditContext != null)
        {
            CascadedEditContext.NotifyFieldChanged(FieldIdentifier);
        }
    }
}

```

with this code change, the EditContext (if it's there) will be notified.

maybe you can add this logic to your base-class ?

Thanks I will try it.

It would be very nice if the Blazorise Input Components could utilize EditContext/EditForm if it exists.

I personally have a ton of Fluent Validation validators and for this reason I am sticking to EditForm. (Which makes the Blazorise Input Components/Validations far less appealing - but using everything else provided by Blazorise and enjoying it!).

There's also the point of being easier to integrate third party components since they are very likely to depend on EditForm.

It would be very nice if the Blazorise Input Components could utilize EditContext/EditForm if it exists.

I personally have a ton of Fluent Validation validators and for this reason I am sticking to EditForm. (Which makes the Blazorise Input Components/Validations far less appealing - but using everything else provided by Blazorise and enjoying it!).

There's also the point of being easier to integrate third party components since they are very likely to depend on EditForm.

I would like that change as well, in the meantime, you can create a FluentValidator yourself, which can be called from the Blazorsie InputFields albeit it being a bit ugly ^^

 public class FluentValidator
    {
        public Tuple<ValidationStatus, string> Validate(IValidator validator, IFluentValidatableModel model,
            string propertyName)
        {
            var properties = new[] {propertyName};
            var context = new ValidationContext(model, new PropertyChain(),
                new MemberNameValidatorSelector(properties));
            var validationResult = validator.Validate(context);
            if (validationResult.IsValid) return Tuple.Create<ValidationStatus, string>(ValidationStatus.Success, null);

            return Tuple.Create(ValidationStatus.Error, validationResult.Errors.FirstOrDefault()?.ErrorMessage);
        }
    }

This will make it possible to validate against a Validator like so:

<Validation Validator="@(e => (e.Status, e.ErrorText) = FluentValidator.Validate(_validator, Actor, nameof(ActorModel.MarketRole) + "." + nameof(ActorModel.MarketRole.Id)))">
        <SelectRole MarketRole="@Actor.MarketRole" SelectedValueChanged="@StateHasChanged"/>
</Validation>

<Validation> is the Validation component from Blazorise.

@niem94 Thanks for your suggestion. I'll try this.
However, when this needs to be done for all the fields separately, it's a lot of typing.

@niem94 Thanks for your suggestion. I'll try this.
However, when this needs to be done for all the fields separately, it's a lot of typing.

@StefH True, it's not ideal. Hope it helps you out until a better solution surfaces :-)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

danielheddelin picture danielheddelin  ·  5Comments

Andy74 picture Andy74  ·  4Comments

smilyte picture smilyte  ·  3Comments

njannink picture njannink  ·  4Comments

stsrki picture stsrki  ·  3Comments