97

I need to be able to run a function after a selection in made in a <select>. The issue is I'm also binding with @bind and I get a error when I try to use @onchange stating that it is already in use by the @bind. I tried using @onselectionchange, but that does nothing(doesn't run the function). I could forget the @bind and just assign @onchange to a function, but I'm not sure how to pass the selected value to the function.

I have the following code:

<select @bind="@SelectedCustID" @ @onchange="@CustChanged" class="form-control">
    @foreach (KeyGuidPair i in CustList)
    {
        <option value="@i.Value">@i.Text</option>
    }
</select>

Thanks.

3
  • 1
    just a side note: you can use @bind=SelectedCustID instead of @bind="@SelectedCustID". its much cleaner :) Commented Sep 27, 2019 at 3:22
  • 1
    One character @ seems to be redundant. Commented Jul 28, 2020 at 10:19
  • see stackoverflow.com/questions/58452319/… Commented Nov 11, 2020 at 8:51

14 Answers 14

59

@bind is essentially equivalent to the having both value and @onchange, e.g.:

<input @bind="CurrentValue" />

Is equivalent to:

<input value="@CurrentValue" @onchange="@((ChangeEventArgs e) => CurrentValue = e.Value.ToString())" />

Since you've already defined @onchange, instead of also adding @bind, just add value to prevent the clash:

<select value="@SelectedCustID" @onchange="@CustChanged" class="form-control">
    @foreach (KeyGuidPair i in CustList)
    {
        <option value="@i.Value">@i.Text</option>
    }
</select>

Source: https://learn.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-3.1

Sign up to request clarification or add additional context in comments.

1 Comment

Just to mention you explanation where you said "is equivalent to" has helped me figure out how to pass multiple parameters on the onchange event of a blazor select . Thank you.
49
<select @bind="MyProperty">
<option>Your Option<option>
</select>

@code  {
    private string myVar;

    public string MyProperty
    {
        get { return myVar; }
        set
        {
            myVar = value;
            SomeMethod();
        }
    }

    private void SomeMethod()
    {
        //Do something
    }
}

5 Comments

this works but will be a problem if you need to do some asyn call, a database update for example....
@Alexandre, I think you can convert an an asynchronous call to synchronous by using .Wait(). See here.
It should be select not input as user asked for select code.
Invoke the event rather than calling a method to keep setter „lean”. Then You can use async void and update state manually at the end with StateHasChanged()
This only works when the field loses focus. Not while typing.
26

Starting from .NET 7 Preview 7, the recommended way to handle this issue is to use the bind:after modifier.

Here is a small example (partially borrowed from the docs):

<p>
    <label>
        Select one or more cities:
        <select @bind="SelectedCities" multiple @bind:after="DoSomething">
            <option value="bal">Baltimore</option>
            <option value="la">Los Angeles</option>
            <option value="pdx">Portland</option>
            <option value="sf">San Francisco</option>
            <option value="sea">Seattle</option>
        </select>
    </label>
</p>

<span>
    Selected Cities: @string.Join(", ", SelectedCities)
</span>

@code {
    public string[] SelectedCities { get; set; } = new[] { "bal", "sea" };

    // Run your logic here after a binding event
    private void DoSomething()
    {
        Console.WriteLine(string.Join(',', SelectedCities));
    }
}

1 Comment

Starting from .Net 7 was the key. Using latest .Net Core made all previous answers invalid it seems. @bindafter works. Thanks Jesse.
20

Just add @bind-value and @bind-value:event="oninput" with @onchange as below. Note the lower case letters. This works for me without any issue.

<select @bind-value="variablenametokeepselectedvalue" @onchange="yourmethodname" @bind-value:event="oninput">
 <option value="1">Test</option>
</select>

Comments

14

This seems to be a popular confusion. Firstly you cant use @onchange since it would internally be used by @bind. You should be able to access the selected value from the setter of your CustChanged property. Based on what you are trying to do with your CustChanged, you may not even need to manually check when this value is updated. For instance, if your intent is to use CustChanged in your UI directly or indirectly (within Linq or something), the UI would automatically update with CustChanged value when your <select> is changed. Hence, for most use cases I don't see the need to check when it was updated.

To use @onchange, you can bind it to a function something like this:

public void OnUpdated(ChangeEventArgs e)
{
    var selected = e.Value;
}

2 Comments

This is the correct answer to the question asked.
annoyingly this seems to actually give the option text selected, not the option value
6

You can avoid @bind altogether (if you're using a foreach):

<select @onchange=@(handleChange)>
    @foreach (var option in _options){
        <option [email protected] selected=@(SelectedId == option.Id)>@option.Name</option>
    }
</select>

@code {
    public record Person(int Id, string Name);
    public int SelectedId { get; set; }
    public List<Person> _options = new List<Person>() {
        new Person(1,"A"),
        new Person(2,"B"),
        new Person(3,"C")
    };

    public void handleChange(ChangeEventArgs args) {
        Console.WriteLine(args.Value);
        SelectedId = Int32.Parse(args.Value.ToString());
    }

}

Some sordid details: I was getting some weird behavior when trying to use F# with server-side Blazor. In short, setting the List of options to the result of an Entity Framework query (mapped to a list of records) wouldn't @bind properly, but using a dummy list of options that were C# classes and not F# records did work. It wasn't due to it being records though, because if I set the list to the EF query and then immediately set it to a dummy list of records, it still didn't @bind properly - but it did work if I commented out the EF line.

4 Comments

true or false to selected attribute is not valid stackoverflow.com/questions/1033944/…
@Alexandre True. However, Blazor converts the selected=true/false to valid HTML. i.imgur.com/QEDQceP.png The same works for other attributes too, like disabled: stackoverflow.com/questions/55002514/… also blazor-university.com/components/code-generated-html-attributes
Hi DharmaTurlte could you please elaborate on the @onchange=@(x => ...). What purpose has the lambda expression. What code do I have to write there (a Methode Call? How?). Thx
@nogood I filled in the lambda. LMK if you're still confused.
3

Please check this example. It is using @bind but upon setting the value it triggers @onchange event

<div class="form-group">
    <label for="client">Client Name</label>
    <select id="client" @bind="CheckSelected" class="form-control">
       <option value="selected1">selected1</option>
       <option value="selected2">selected2</option>
    </select>
</div>
@code {

    private string selectedItem {get; set;}

    private string CheckSelected
    {
        get
        {
            return selectedItem;
        }
        set
        {
            ChangeEventArgs selectedEventArgs = new ChangeEventArgs();
            selectedEventArgs.Value = value;
            OnChangeSelected(selectedEventArgs);
        }
    }

    private void OnChangeSelected(ChangeEventArgs e)
    {
        if (e.Value.ToString() != string.Empty)
        {
            selectedItem = e.Value.ToString();
        }
    }

}

1 Comment

Worth to notice this solution works with blazor EditForm (stackoverflow.com/questions/61756167/…), as InputSelect does not bind event properly in a following way: <InputSelect Id="Source" @bind-Value="@model.Source" Class="form-control" @onchange="HandleSourceOptionChanged">.
2

According to Microsoft's documentation, this is their preferred way of handling this problem:

<InputText Value="@NewPaymentAmount" class="mdl-textfield__input"
           ValueExpression="() => NewPaymentAmount"
           ValueChanged="(string value) => ValidateAmount(value)" />



private void ValidateAmount(string amount)
{
    NewPaymentAmount = amount;
    
    // Do validation or whatever
}

Or the async way:

<InputText Value="@NewPaymentAmount" class="mdl-textfield__input"
           ValueExpression="() => NewPaymentAmount"
           ValueChanged="async (string value) => await ValidateAmountAsync(value)" />



private async Task ValidateAmountAsync(string amount)
{
    NewPaymentAmount = amount;
    
    // Do validation or whatever
}

2 Comments

No need to await inside ValueChanged as this creates a useless state machine. When the code that actually invokes ValueChanged wants to await the return value it can do it no matter if it is awaited also in the ValueChanged method body.
Thanks, this is exactly what I needed in order to get it working with validation also!
2

Please check below code for reference how we use select tag with bind value and call function onselection value change in blazor

<InputSelect class="form-control mb-0" ValueExpression="@(()=>request.Id)" Value="request.Id" 
ValueChanged="@((string value) => SelectedValueChange(value))">
@if (dropdownResponses != null)
{
   @foreach (var item in dropdownResponses)
   {
     <option value="@item.Id.ToString()">@item.Name</option>
   }
}
</InputSelect>

use <InputSelect> tag instead of <select> tag and use ValueChanged method for getting call on select value change

here is the code of ValueChanged function

internal void SelectedValueChange(string value)
{
   string NewValue = value;
}

Comments

1

My recommendation is, if possible, use an EditForm wrapper around your form elements. Then you can detect a change of any of the form elements, in one place. This is good for, for example, a bunch of search filters. Any change in any of the filters should trigger another query of the data, etc.

Example of how to trigger event on form changes is here:

blazor editform change events

Comments

0

<div class="form-group">
    <label for="client">Client Name</label>
    <select class="form-control" @onchange="@((e) => { myVar = e.Value.ToString(); MyMethod(); })">
       <option value="val1">val1</option>
       <option value="val2">val2</option>
    </select>
</div>

This is how I was able to set the property while calling for a method in the @onchange event.

-Blazor Server -Dotnet Core 3.1

Comments

0

I use oninput to essentially have bind and onchange.

oninput triggers when the input value is changed whereas bind/onchange triggers when the element loses focus and the input has changed.

This might not fit every scenario however as it wll trigger on every input while typing, depending on your need or for inputs such as selects, radios, etc. it should be suitable.

Comments

0

This code works for me.

<div class="col-md-6 mb-3">
    <label>Title</label>
    <InputSelect class="form-control" ValueExpression="() => currentPatient.PatientTitle" Value="@currentPatient.PatientTitle"
                 ValueChanged="@((Title value) => OnTitleChange(value))">
        @foreach (var title in Enum.GetValues(typeof(Title)))
        {
            <option value="@title">@title.</option>
        }
    </InputSelect>
</div>

    private void OnTitleChange(Title value)
{
    Title selectedTitle = value;
    currentPatient.PatientTitle = value;

    // Automatically update gender based on the selected title
    switch (selectedTitle)
    {
        case Title.Mr:
            currentPatient.PatientGender = Gender.M;
            break;
        case Title.Mrs:
        case Title.Miss:
        case Title.Ms:
            currentPatient.PatientGender = Gender.F;
            break;
        default:
            currentPatient.PatientGender = Gender.O;
            break;
    }
}

1 Comment

Thank you for contributing to the Stack Overflow community. This may be a correct answer, but it’d be really useful to provide additional explanation of your code so developers can understand your reasoning. This is especially useful for new developers who aren’t as familiar with the syntax or struggling to understand the concepts. Would you kindly edit your answer to include additional details for the benefit of the community?
0

A word of caution: there is a difference between using <select> and <InputSelect>

I was using <InputSelect>, and went in circles for a few hours trying to get @onchange and @bind:after to work. Finally, using @bind-value:get and @bind-value:set is what ended up working.

This is for .Net 7, circa 2025.

<InputSelect 
    @bind-value:get="@_viewModel.YourVariableAAA"
    @bind-value:set="@((x) => SomeUpdateMethodAAA(x))">
    <option value=""></option>
    @foreach (var item in ListOfItemsForDropDownAAA)
    {
        <option value="@item.Id">@item.Name</option>
    }
</InputSelect>

The reason for needing the call to SomeUpdateMethod(x) was that the UI had 3 dropdown menus, and the selections in dropdown BBB have to change based on the selection in dropdown AAA.

So in the SomeUpdateMethodAAA(x), I update the items in ListofItemsForDropdownBBB, and set the _viewModel.YourVariableBBB = string.Empty which clears the selected item in the BBB dropdown.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.