'Blazor: How to use the onchange event in <select> when using @bind also?
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.
Solution 1:[1]
<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
}
}
Solution 2:[2]
@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://docs.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-3.1
Solution 3:[3]
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;
}
Solution 4:[4]
Just add @bind-value and @bind-vale:event with @onchnage exactly 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>
Solution 5:[5]
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.
Solution 6:[6]
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(); } } }
Solution 7:[7]
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;
}
Solution 8:[8]
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:
Solution 9:[9]
<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
Solution 10:[10]
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
}
Solution 11:[11]
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow