asp.net-mvcasp.net-coreienumerablecascadingdropdownviewdata

ASP.NET Core MVC - Invalid Operation Exception There is no viewdata of type Ienumerable<SelectListItem>


I am trying to cascade State Names according to the Country name selected in the Country drop down. I have written the JS for post method for selected Country. But when i added the state dropdown list in view and debug it. I get the error - There is no Viewdata of type Ienumerable of key StateName1.

NewRequestView Model

public class NewRequestView 
{    
    public string SelectedCountry { get; set; }
    public IEnumerable<SelectListItem> Countries { get; set; }
    public IEnumerable<SelectListItem> State { get; set; }        
}

Country Model

public class Country
{
    public int CountryID { get; set; }
    public string CountryName { get; set; }
}

Controller

 public IActionResult NewRequest()
    {
        var model = new NewRequestView { };                      
        model.Countries = iMapper.Map<IEnumerable<Country>, IEnumerable<SelectListItem>>(GetCountries());            
        return View(model);
    }

View

                             <div class="row">
                                <div class="col-xs-10 multiSelectCheckboxDiv" id="multiSelectCheckboxDiv">
                                    <span class="col1 contrlLabel" style=" font-family:calibri;color:gray;font-size:15px">Clients<span style="font-weight:800;color:red;">*</span>:</span>
                                    @Html.DropDownList("CountryName", Model.Countries ,"Select Country",new { @class = "form-control"})
                                    <div class="input-validation-errorText col-md-6" style="display:none;">
                                        Please select Country.
                                    </div>
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-xs-10 multiSelectCheckboxDiv" id="multiSelectCheckboxDiv">
                                    <span class="col1 contrlLabel" style=" font-family:calibri;color:gray;font-size:15px">Clients<span style="font-weight:800;color:red;">*</span>:</span>
                                    @Html.DropDownList("StateName1", Model.State, "Select State", new { @class = "form-control" })
                                    <div class="input-validation-errorText col-md-6" style="display:none;">
                                        Please select state.
                                    </div>
                                </div>
                            </div>

I Used AutoMapper to map the Country Names.

Mapper

 var config = new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<Client, SelectListItem>()
             .ForMember(x => x.Text, opt => opt.MapFrom(o => o.CountryName))
             .ForMember(x => x.Value, opt => opt.MapFrom(o => o.CountryName));

        });
        return config.CreateMapper();

From Selected Country I am firing JS to get all the state Names. But before i select itself i am getting the error

InvalidOperationException: There is no ViewData item of type 'IEnumerable' that has the key 'StateName1'.

Let me know what is the error i am doing here


Solution

  • Invalid Operation Exception There is no viewdata of type Ienumerable

    This is caused by a null list being supplied to Html.DropdownList() in your view.

    Looking at your controller action, you don't have anything that gives model.State value.

    public IActionResult NewRequest()
    {
       var model = new NewRequestView { };                      
       model.Countries = iMapper.Map<IEnumerable<Country>, IEnumerable<SelectListItem>>(GetCountries());
    
       // you need something like this
       model.State = new List<SelectListItem>(){
          new SelectListItem(){ Text = "Test", Value = "Test" }
       };
    
       return View(model);
    }
    

    Another option is, since the State Records will come from an ajax event once a Country is selected, you could actually just leave model.State blank and don't use Html.Dropdown().

    You can do this; The manually created select field will still be recognized as part of the model when you submit the form.

    <div class="row">
       <div class="col-xs-10 multiSelectCheckboxDiv" id="multiSelectCheckboxDiv">
          <span class="col1 contrlLabel" style=" font-family:calibri;color:gray;font-size:15px">Clients<span style="font-weight:800;color:red;">*</span>:</span>
    
          <select id="StateName1" name="Model.State" class="form-control">
             <option>Select State</option>
          </select>
          <div class="input-validation-errorText col-md-6" style="display:none;">
             Please select state.
          </div>
    
       </div>
    </div>