Home > Back-end >  Model properties not bind to dropdowns in Blazor
Model properties not bind to dropdowns in Blazor

Time:12-26

I have 2 cascade dropdowns:

enter image description here

The problem is when I click on Save button my model would be empty. I can't use bind-value in my dropdowns because I can't use onchange event. How can I have cascade feature as long as binding properties.

Codes:

@using Model

<select value="@MyLocation.CountryCode" @onchange="@CountryChanged">
@if (string.IsNullOrEmpty(MyLocation.CountryCode) == true)
{
     <option value="0" selected>[Choose One...]</option>
}

@foreach (var item in Countries)
{
     <option value="@item.Key">@item.Value</option>
}
</select>
<br />
<select value="@MyLocation.CityCode">
@foreach (var item in CountryCities)
{
     <option value="@item.Key">@item.Value</option>
}
</select>
<br />
<button  @onclick="() => HandleSave()">Save</button>

@code {

public Location MyLocation { get; set; } = new Location();
private Dictionary<string, string> Countries { set; get; } = new Dictionary<string, string>();
private Dictionary<string, string> CountryCities { set; get; } = new Dictionary<string, string>();

protected override Task OnInitializedAsync()
{
    Countries.Add("01", "Germany");
    Countries.Add("02", "Japan");
    Countries.Add("03", "England");

    return base.OnInitializedAsync();
}

private async Task CountryChanged(ChangeEventArgs e)
{
    CountryCities.Clear();
    switch (e.Value.ToString())
    {
        case "01":
            CountryCities.Add("001", "Munchen");
            break;
        case "02":
            CountryCities.Add("002", "Tokyo");
            break;
        case "03":
            CountryCities.Add("003", "Manchester");
            break;
    }
}

private void HandleSave()
{
    var Country = MyLocation.CountryCode; <--- CountryCode is null
}
}

CodePudding user response:

On the CountryChanged method you can add:

MyLocation.CountryCode = e.Value.ToString();

You can do the same for the CityCode:

<select value="@MyLocation.CityCode" @onchange="@OnCityChanged">
@foreach (var item in CountryCities)
{
    <option value="@item.Key">@item.Value</option>
}

@code {
private void OnCityChanged(ChangeEventArgs e) => MyLocation.CityCode = e.Value.ToString();
}

Edit: Note that for the OnCityChanged to work, user have to actually select a value. In case that they don't, the first value (in your case Muchen, Tokyo, Manchester) won't be set as property in your model. For that scenario, you can do something like that, in the CountryChanged method:

switch (e.Value.ToString())
    {
        case "01":
            CountryCities.Add("001", "Munchen");
            MyLocation.CityCode= "001";
            ...

Edit 2: Reply to your comment "Thanks but i'm looking for a way like bind-value in input texts."

<EditForm Model="MyLocation">
<InputSelect TValue="string" @bind-Value="MyLocation.CountryCode">
    @if (string.IsNullOrEmpty(MyLocation.CountryCode) == true)
    {
        <option value="0" selected>[Choose One...]</option>
    }

    @foreach (var item in Countries)
    {
        <option value="@item.Key">@item.Value</option>
    }
</InputSelect>

CodePudding user response:

@page "/"

<select  value="@MyLocation.CountryCode"
        @onchange="@((args) => { MyLocation.CountryCode = args.Value.ToString(); SelectCities(args); })">

    <option value="">Select Country...</option>
    @foreach (var country in countryList)
    {
        <option value="@country.Code"> @country.Name </option>
    }
 
</select>
<br />
@if (cityList != null && cityList.Any())
{
    <select  @bind="@MyLocation.CityCode">
       @foreach (var city in cityList)
       {
               <option value="@city.Code">@city.Name</option>
       }
    </select>
}
    <br />

    <button  @onclick="() => HandleSave()">Save</button>

    @code {

        private Location MyLocation = new Location();


        private IList<Country> countryList = new List<Country>
  {
            new Country
            {
                Code = "001", Name="USA",
                Cities = new List<City> {  new City { Code = "1", Name = "City1" },
                         new City { Code = "2", Name = "City2" } }
            },
            new Country
            {
                Code = "002", Name="Germany",
                Cities = new List<City> {  new City { Code = "3", Name = "City1" },
                         new City { Code = "4", Name = "City2" } }
            },
            new Country
            {
                Code = "003", Name="France",
                Cities = new List<City> {  new City { Code = "5", Name = "City1" },
                         new City { Code = "6", Name = "City2" } }
            },

            new Country
            {
                Code = "004", Name="UK",
                Cities = new List<City> {  new City { Code = "7", Name = "City1" },
                         new City { Code = "8", Name = "City2" },
                         new City { Code = "9", Name = "City3" },
                         new City { Code = "10", Name = "City4" }}
            },

            new Country { Code = "005", Name="Russia",
               Cities =  new List<City>  {  new City { Code = "11", Name = "City1" } }}
        };


        private IQueryable<City> cityList;

        private void HandleSave()
        {
            Console.WriteLine($"MyLocation.CountryCode: {MyLocation.CountryCode}");
            Console.WriteLine($"MyLocation.CityCode: {MyLocation.CityCode}");
         
        }

        private void SelectCities(ChangeEventArgs args)
        {
            // Note: Each time SelectCities is called MyLocation.CityCode should be set to null.
            MyLocation.CityCode = null;
            string countryCode = args.Value.ToString();

            cityList = (from country in countryList
                        where country.Code == countryCode
                        from city in country.Cities
                        select city).AsQueryable();
        }

        public class Location
        {
            public string CountryCode { get; set; }
            public string CityCode { get; set; }

        }

        public class Country
        {
            public string Code { get; set; }
            public string Name { get; set; }

            public IList<City> Cities { get; set; }
        }

        public class City
        {
            public string Code { get; set; }
            public string Name { get; set; }

        }

    }

Now try to convert this code to work with the Forms' InputSelect component, embedded within an EditForm

  • Related