Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to bind and run an async method on input change in Blazor

Tags:

c#

asp.net

blazor

So I am building a Blazor component where I want to type into an input and fire an AJAX request to get filtered data from the server. I tried this

<input type="text" @bind="NameFilter" @onchange="FilterChangedAsync" />

However this results in an error

The attribute 'onchange' is used two or more times for this element. Attributes must be unique (case-insensitive). The attribute 'onchange' is used by the '@bind' directive attribute.

I thought about calling the method in the NameFilter property setter but in this case I can't await it. What is the proper way to achieve the desired behavior?

like image 830
Stilgar Avatar asked Jan 14 '20 08:01

Stilgar


People also ask

How do you bind a value in Blazor?

Bind a property or field on other Document Object Model (DOM) events by including an @bind:event="{EVENT}" attribute with a DOM event for the {EVENT} placeholder. The following example binds the InputValue property to the <input> element's value when the element's oninput event ( input ) is triggered.

How do you take input in Blazor?

The input element value is updated by the @bind event in Blazor. To get the current input value, use the oninput native event of the input element and get the current input value.

How do you bind a label to value in Blazor?

You can use the bind attribute on any element to bind the value. In blazor, we'll have a property assigned some value in the functions and use the property in the HTML template. Let's get this done. So, when we run the app, the label tag will display “red” as a text in the label.

What does @bind do Blazor?

To use two-way binding on a parameter simply prefix the HTML attribute with the text @bind- . This tells Blazor it should not only push changes to the component, but should also observe the component for any changes and update its own state accordingly.


Video Answer


2 Answers

The @bind attribute is a compiler directive attribute instructing the compiler to create code that enables two way data binding, from a variable to the element, and from the element to the variable. Behind the scene, the compiler creates the onchange event handler whose role is to update the variable when the change event is triggered. Thus, you can't use the onchange twice. Instead you should do the following:

<input type="text" @bind="NameFilter" />

To retrieve the data entered define a property like this:

public string NameFilter { get; set; } 

In that case you can add a button control with a click event handler that can access the value of NameFilter, and use it for your filtering calls, like this:

<button class="btn btn-primary" @onclick="@FilterMe">Filter Me</button>

And,

private void FilterMe()
    {
        var filter = NameFilter;
    }

Or still better, bind the NameFilter variable to the value attribute, plus defining an event handler, like this:

<input type="text" value="@NameFilter" @onchange="FilterChangedAsync" />

But in that case it is your responsibility to update the bound variable, which you can do in the event handler itself, or using a lambada expression as the value of @onchange

 private void FilterChangedAsync(ChangeEventArgs args)
    {
        NameFilter = args.Value.ToString();
    }

This is how you update the NameFilter property with lambada expression:

<input type="text" value="@NameFilter" @onchange="@(( args ) => NameFilter = args.Value.ToString())" />

Note: The change event is triggered only when you tab out of the text box control, and this behavior may not suit your filtering requirements. The input event, on the other hand, occurs each time you type on the keyboard.

Using the input event:

<input type="text" @bind-value="@NameFilter" @bind-value:event="oninput" />

Or you can do it with an accompanying method like this:

<input type="text" value="@NameFilter" @oninput="@FilterChangedAsync" />

and

 private void FilterChangedAsync(ChangeEventArgs args)
    {
        NameFilter = args.Value.ToString();
    }

Good luck...

like image 139
enet Avatar answered Oct 10 '22 02:10

enet


>= Net7

Quoting Blazor data binding get/set/after modifiers

In .NET 7 you can now easily run async logic after a binding event has completed using the new @bind:after modifier:

<input @bind="searchText" @bind:after="PerformSearch" />

@code {
    string searchText;

    async Task PerformSearch()
    {
        // ... do something asynchronously with 'searchText' ...
    }
}

also useful:

<input @bind:get="Value" @bind:set="ValueChanged" />

@code {
    [Parameter] public TValue Value { get; set; }
    [Parameter] public EventCallback<TValue> ValueChanged { get; set; }
}
like image 3
dani herrera Avatar answered Oct 10 '22 02:10

dani herrera