1

I have a site where all pages need a dropdown listing countries and another dropdown containing child data based on the selected country.

I have taken a similar approach to this article:

MVC 3 Layout Page, Razor Template, and DropdownList

So I need the functionality as follows:

  • 1.) Context controls always present on the layout page (the country dropdown and it's dependent)
  • 2.) When the country dropdown changes, populate the second dropdown with data relevant to that country.

Currently I have a UserContextController which handles the get and post requests and returning partial views:

Index action from UserContextController:

[HttpPost]
public ActionResult Index(UserContextViewModel userContext)
{           
        //CurrentUserContext is a Session wrapper to store the selections from the dropdowns
        //in application scope for ease of reference. This is accessed in a base controller all      controllers inherit from            
this.CurrentUserContext.SetCountryContext(this.countryRepository.GetList().SingleOrDefault(c =>     c.Id == userContext.CountryId));

        if (userContext.TerritoryId > 0)
        {
        //return partial view containing model data and select list data    
        return PartialView("ContextControls", new     UserContextViewModel(this.countryRepository.GetList(), 
                                                                        AvailableTerritories,
                                                                            CurrentUserContext.CurrentCountry,
                                                                            CurrentUserContext.CurrentTerritory));            
    }

My Layout page referencing the UserContextController and Index action:

        <header>
            <div class="content-wrapper">                
                <a href=".">HOME</a>
                @Html.Action("Index", "UserContext")
            </div>
        </header>

The dropdowns in the partial view added to the layout page have some jquery that invokes an http post to the UserContextController when they change (shaped to the UserContextViewModel schema):

//_targetUrl is: /UserContext
$.post(_targetUrl, { CountryId: $('#CountryId').val(),TerritoryId:$('#TerritoryId').val() },     function (result) { });

View Model code that sets the selected item:

public IEnumerable<SelectListItem> CountrySelectItems 
        {
            get
            {
                int selectedCountryId = this.selectedCountry==null ? 0 : this.selectedCountry.Id;

                return new SelectList(this.countries, "Id", "Name",selectedCountryId);
            }
        }

Constructor of the ViewModel that sets the selected country:

public UserContextViewModel(IEnumerable<Country> countries, IEnumerable<Territory> territories,Country selectedCountry,Territory selectedTerritory)
        {
            this.countries = countries;
            this.territories = territories;

            this.selectedCountry = selectedCountry;
            this.selectedTerritory = selectedTerritory;
        }

The partial view:

<p>
        <label>Country:</label>
        @Html.DropDownList("CountryId", @Model.CountrySelectItems, new { @class = "context-control" })        
    </p>

The User context session wrapper to hold the values set :

protected IUserContext CurrentUserContext
        {
            get
            {                
                const string contextKey = "USER_CONTEXT";

                if (HttpContext.Session[contextKey] == null)
                {
                    HttpContext.Session.Add(contextKey, new UserContext());                    
                }

                return HttpContext.Session[contextKey] as IUserContext;
            }
        }

So this works and updates the values in my UserContext but the country dropdown never sets the selected country and always defaults to the first item in the list. i.e. contains UK and Germany. Select Germany -> post to controller -> sets the selected value -> dropdown still on UK!!

The UI should return to a start page when these dropdowns change as it effects the data rendered in the UI and the user needs to be aware of the "context change" (so they don't add data for a different country context for example).

What's interesting is that in Fiddler when the dropdown changes I can see the response returned contains the whole layout page and dropdown HTML has the correctly selected options!

I think my approach is wrong...does anyone have similar functionality they have achieved? I have come at this from the perspective of a production WebForms project completed recently that does the same via user controls and wanted to produce a PoC in MVC but failing miserably !

I think I need to drive the dropdowns via Angular to WebAPI requests and the setting of the context.

Community
  • 1
  • 1
Spencer
  • 251
  • 2
  • 8
  • You haven't posted enough code to be sure, but the selected value is based on you model property, so it you don't set the value of `CountryId` in the controller to a value which matches one of the options, then the first option will be selected by default. –  Dec 17 '14 at 22:35
  • Yes this is set and as mentioned I see the full layout returned with correctly selected options in dropdowns in Fiddler. Added code from the View Model to demonstrate – Spencer Dec 17 '14 at 22:39
  • The last parameter of `new SelectList(this.countries, "Id", "Name", selectedCountryId);` is pointless. If you using `@Html.DropDownListFor(m => m.CountryId, ...)` then the selected item will be defined by the value of `CountryId` - the value you set in the `SelectList` constructor is ignored –  Dec 17 '14 at 22:45
  • I'm not using DropDownListFor, added the view markup for review.. – Spencer Dec 17 '14 at 22:50
  • I'll never understand why anyone still uses these obsolete helpers, but the issue is still the same. Your helper is **binding** to property `CountryId` so if the value of property `CountryId` does not match one of the options then the first option will be selected. You need to set `CountryId` in the controller before you pass the view. –  Dec 17 '14 at 22:54
  • You're quite right, my misunderstanding of the DropDownList helper. Thanks, all good now. – Spencer Dec 17 '14 at 23:18

0 Answers0