Blazor bind-value:event oninput
Asked Answered
T

8

10

I am trying to trigger the model validation in Blazor by using EditForm.

For some reason, the oninput event doesn't seem to be called if using the InputText, but it works using a simple input element.

Have I missed something?

Here is an HTML sample:

<EditForm Model="@Model" OnValidSubmit="@OnValidSubmit" id="authorize">
    <h1 class="mb-3">
       <span class="d-block">Authorize</span>
    </h1>
    <DataAnnotationsValidator />
    <div class="form-group">
        <label class="sr-only" for="AuthorizeUsername">Username</label>
        <div class="input-group mb-2">
            <div class="input-group-prepend">
                <div class="input-group-text"><i class="fas fa-user"></i></div>
            </div>
            <InputText type="text" class="form-control" id="AuthorizeUsername" placeholder="Username" @bind-value="@Model.Username" @bind-value:event="oninput" />
        </div>
    </div>
    <div class="form-group">
        <label class="sr-only" for="AuthorizePassword">Password</label>
        <div class="input-group mb-2">
            <div class="input-group-prepend">
                <div class="input-group-text"><i class="fas fa-asterisk"></i></div>
            </div>
            <InputText type="password" class="form-control" id="AuthorizePassword" placeholder="Password" @bind-value="@Model.Password" @bind-value:event="oninput" />
        </div>
    </div>
    <div class="form-group">
        <ValidationSummary />
        <button type="submit" class="btn btn-outline-primary"><i class="fas fa-sign-in-alt mr-1"></i> Login</button>
    </div>
</EditForm>
Tele answered 26/6, 2019 at 13:50 Comment(5)
I found this issue which has some different ways and workarounds for the bind-value:event format you're using. Try using bind-value-oninput="@Model.Password"Knightly
Studio wont accept this anymore as syntax has changed, perhaps its a bug and should be posted on github ?Tele
It looks like it should work.. Any examples I can find look exactly the same as what you have besides the InputText. So yes it may be worth creating an issue for itKnightly
I came across the same problem and I found that using the input element instead of the InputText element worked for me.Dodi
Use a capital V in @bind-Value because Value is the name of a property on the C# class InputTextGreatnephew
M
15

If you need this for validation, see the answer for this:

How to make an EditForm Input that binds using oninput rather than onchange

Original Answer

TLDR: Blazor Input components do not support this out of the box. You need to roll your own by extending InputBase, and your Razor markup for your new component will put the input event binding directly on the input element.

It would be nice if this came as an out-of-the-box option, but at least there is a way to do it that isn't terrible. Be aware though that this quickly gets more complicated for more complicated input types. If you want your own InputBase<DateTime> derived class, for example, you need to be prepared to correctly handle DateTime formatting in the binding events.

The markup for your own version of InputText, lets call it MyInputTextCode that extends InputBase<string> would look something exactly like this:

@inherits MyInputTextCode;

<input type="text" id="@Id" class="@Class" @bind-value="CurrentValueAsString" @bind-value:event="oninput" />

where MyInputTextCode is the class name of your implementation of InputBase<string>

The usage would essentially be the same as InputText, but you would instead use the file name (witout the extension) of your .razor markup instead of InputText.

UPDATE 4-30-2020 I no longer recommend deriving from InputBase in your code-behind, instead you can simply @inherits an existing form component class such as InputText and override the markup in your .razor file. If this isn't clear please comment on this answer and I'll elaborate further in this update.

Minnie answered 1/8, 2019 at 19:0 Comment(4)
When doing this, I receive following exception: System.ArgumentException: Object of type 'Microsoft.AspNetCore.Components.ChangeEventArgs' cannot be converted to type 'System.String'. 🤔Chanukah
@WoIIe its hard to say why that might be happening from an exception alone, if you'd like to post a new question and link it here I'd be happy to take a look.Minnie
@WΩLLE-ˈvɔlə I don't think bind-Value:event="oninput" works on an <InputText> control. If you check the answer linked to in this answer it's very simple to create your own input control that updates the model value with each keystroke.Collimator
Thanks for the useful link at the beginning of your answer!Libava
G
7

It works on a simple input because you are binding to the html attribute "value".

InputText is a C# class. The property name you need to bind to is Value with a capital V.

Change all @bind-value occurrences to @bind-Value and it should work.

Greatnephew answered 27/1, 2020 at 21:49 Comment(1)
I receive the following error at runtime when I do this: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: Object of type 'Microsoft.AspNetCore.Components.ChangeEventArgs' cannot be converted to type 'System.String'Iyeyasu
U
6

Another workaround for this issue would be to add a handler to @oninput and set the value to the model inside this handler:

<EditForm Model="Input">
    <InputText @bind-Value="Input.Text" @oninput="HandleInputTextInput" />
</EditForm>

@{
    private InputModel Input { get; } = new();
    
    private void HandleInputTextInput(ChangeEventArgs e)
    {
        Input.Text = e.Value as string;
    }
    
    public class InputModel
    {
        public string? Text { get; set; }
    }
}

This way you don't need to create a new component and can still use <InputText />. Draw back of course is that this might bloat your code with handlers.

Unhallow answered 9/2, 2023 at 22:1 Comment(0)
L
3

As a workaround, I found that changing from Blazor components such as InputTextArea to plain HTML textarea tag and leveraging the binding on them can fix the problem:

<textarea @bind="@ViewModel.TargetProperty" @bind:event="oninput"/>

or for input tags:

<input type="email" @bind="@ViewModel.Email" @bind:event="oninput"/>

Works in .Net 5 Blazor WASM at least.

Libava answered 26/10, 2021 at 20:56 Comment(0)
F
1

A similar technique as Amir Mahdi said in another answer, I just wanted to point out that this is explained on the official docs also now for Aspnetcore 6.0 and 7.0. https://learn.microsoft.com/en-us/aspnet/core/blazor/forms-and-input-components?view=aspnetcore-6.0

See the heading 'InputText based on the input event'.

Here is how they suggest to use it, I however see the value of also being in charge of which client side event will trigger update (usually it will be 'oninput', but maybe you want to use another client side event?)

Just define a new reusable component like CustomInputText.razor with the following content :

@inherits InputText

    <input @attributes="AdditionalAttributes"
           class="@CssClass"
           @bind="CurrentValueAsString"
           @bind:event="@UpdateSourceTrigger" />
    
    
    @code {
        [Parameter]
        public string UpdateSourceTrigger { get; set; } = "oninput";
     }

To use it inside a razor view just use it like a regular InputText field, the only thing that is adjusted is that it automatically binds to the 'oninput' client side event. You can adjust which event also is bound to do an update. This can both be positive sine you see your changes on key stroke and negative in case updating the backend from the UI is slow, as every keyboard stroke will write data back to the bound property, possibly trigger additional processing too if you have bound it to an 'autosave' feature or similar.

I used the name UpdateSourceTrigger here for the property trigger event - as this reminds me a bit how we adjusted things in WPF when to write back to two way bound fields !

Fletcherfletcherism answered 10/12, 2022 at 22:5 Comment(0)
I
1

If you want to keep InputText default onchange event but still react to oninput I usually do it like this: @oninput="@(e => <bind-value variable> = e.Value.ToString())"

For example:

<InputText type="text" class="form-control" id="AuthorizeUsername" placeholder="Username" @bind-value="@Model.Username" @oninput="@(e => Model.Username = e.Value.ToString())" />

If you wish to use the oninput event instead of the onchange event then here is a complete example from https://learn.microsoft.com/ for .NET 7:

ExampleModel.cs:

using System.ComponentModel.DataAnnotations;

public class ExampleModel
{
    [Required]
    [StringLength(10, ErrorMessage = "Name is too long.")]
    public string? Name { get; set; }
}

Shared/CustomInputText.razor:

@inherits InputText

<input @attributes="AdditionalAttributes" 
       class="@CssClass" 
       @bind="CurrentValueAsString" 
       @bind:event="oninput" />

Pages/FormExample7.razor:

@page "/form-example-7"
@using Microsoft.Extensions.Logging
@inject ILogger<FormExample7> Logger

<EditForm Model="@exampleModel" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <CustomInputText @bind-Value="exampleModel.Name" />

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

<p>
    CurrentValue: @exampleModel.Name
</p>

@code {
    private ExampleModel exampleModel = new();

    private void HandleValidSubmit()
    {
        Logger.LogInformation("HandleValidSubmit called");

        // Process the valid form
    }
}

https://learn.microsoft.com/en-us/aspnet/core/blazor/forms-and-input-components?view=aspnetcore-7.0#inputtext-based-on-the-input-event

Iyeyasu answered 15/5, 2023 at 12:7 Comment(0)
V
0

I found this answer and a workaround:

https://github.com/dotnet/aspnetcore/issues/12657

Basically @bind-Value:event="oninput" is not supported on <InputText> but you can easily derive a new control from 'InputText' which does update on input.

Quoted from the original github post for reference:

Create MyInputText.razor containing:

@inherits Microsoft.AspNetCore.Components.Forms.InputText
<input @attributes="@AdditionalAttributes" class="@CssClass" @bind="@CurrentValueAsString" @bind:event="oninput" />

Now when you use <MyInputText @bind-Value="@someval" /> it will behave just like InputText except it updates on each keystroke.

Venuti answered 23/9, 2022 at 9:48 Comment(0)
L
0

Change @bind-value to @bind-Value

Leontineleontyne answered 21/7 at 6:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.