'How to send an object through @change="" (instead of sending value) when using select element
new to Blazor and I have a simple question
In my Blazor app, I have a simple select element:
<select class="form-select" aria-label="Default select example" @onchange="ItemSelected">
<option selected>Open this select menu</option>
@foreach(var item in Items)
{
<option value="@item.Id"> @item.Name </option>
}
</select>
The idea is when a user selects an option, I want to get the object instead of the key, here is the function:
List<object> ItemContainer = new List<object>();
private void ItemSelected(ChangeEventArgs obj) {
...
ItemContainer.Add(obj);
}
How do I capture the object instead?
Solution 1:[1]
@page "/"
<select @onchange="ItemSelected" class="form-select">
<option value="null">Select...</option>
@foreach (var option in options)
{
<option @key="option" value="@option.ID">@option.Value</option>
}
</select>
@code {
private Option option;
private List<Option> options = Enumerable.Range(1, 10).Select(i => new Option { ID = i, Value = $"Option{i}" }).ToList();
private void ItemSelected(ChangeEventArgs args)
{
if (int.TryParse(args.Value.ToString(), out int selectedID))
{
option = options.Where(o => o.ID == selectedID).FirstOrDefault();
Console.WriteLine(option.ID.ToString());
Console.WriteLine(option.Value);
}
}
public class Option
{
#nullable enable
public int? ID { get; set; }
#nullable disable
public string Value { get; set; }
}
}
UPDATE:
Hi, sorry for bothering you but I am stuck a bit on something. How do I avoid Option in my code? Because I already have an Item class private IEnumerable Items { get; set; } = new List(); is there a way to substitute both? thanks
Option is the class name given by me. You can give it whatever name you want. You may define your class like the following instead:
public class ItemDTO
{
#nullable enable
public int? Id { get; set; }
#nullable disable
public string Name{ get; set; }
}
Note: If you're using .Net 6.0, you may remove the #nullable directive
Update:
Don't use Task.Run
Change this:
protected override async Task OnInitializedAsync()
{
await Task.Run(GetItems);
Client = _client.Get(Id);
}
private void GetItems()
{
Items = _item.GetAll();
}
To:
protected override void OnInitialized()
{
Client = _client.Get(Id);
Items = _item.GetAll();
}
Change this:
private IEnumerable<ItemDTO> Items { get; set; } = new List<ItemDTO>();
To:
private IList<ItemDTO> Items { get; set; } = new List<ItemDTO>();
The above changes are rather cosmetics than functional. I've no way to verify this as I only read the code; I do not view and run it in an IDE.
Anyhow, the following code snippet is incorrect and as a result leads to an error:
var option = ItemDTO.Where(o => o.Id ==
selectedID).FirstOrDefault();
The code above is suppose to query the the list of ItemDTO objects, and return a single object whose Id property is equivalent to the value we pass to the method (ItemSelected) in which the code is executed. The list of ItemDTO objects, defined as Items should be used for searching the selected item; that is, you should use:
`Items.Where`
Instead of:
ItemDTO.Where
ItemDTO is a class name or a type...
This is how your code should be:
var option = Items.Where(o => o.Id ==
selectedID).FirstOrDefault();
May God bless your code ;}
Solution 2:[2]
You can't directly. ChangeEventArgs returns a string as it's Value object.
You need to do something like this:
@page "/"
<select @onchange=OnSelect >
@foreach (var country in Countries)
{
<option value="@country.Id" selected="@this.IsSelected(country)">@country.Name</option>
}
</select>
<div>
Selected : @this.SelectedCountry
</div>
@code {
private Country? country;
private string SelectedCountry => this.country?.Name ?? "None Selected";
protected override void OnInitialized()
{
// to demo selected is working
this.country = this.Countries[1];
}
private void OnSelect(ChangeEventArgs e)
{
if (int.TryParse(e.Value?.ToString(), out int value))
country = Countries.SingleOrDefault(item => item.Id == value);
}
private bool IsSelected(Country c)
=> c == this.country;
public List<Country> Countries = new List<Country>
{
new Country { Id =44, Name = "UK" },
new Country { Id =61, Name = "France" },
new Country { Id =1, Name = "USA" },
};
public class Country
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
}
}
Solution 3:[3]
Sorry I can't type well now to check the syntax exactly, but maybe something like:
@onchange="(e)=> ItemSelected(Items.Single(i=> i.ID.ToString() == e.Value.ToString()))"
And then
private void ItemSelected(YourItemClass SelectedItem) {}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | MrC aka Shaun Curtis |
| Solution 3 | Bennyboy1973 |
