2015-01-23 20 views
5

Sto provando a creare una vista con due DropDownList. Le opzioni disponibili nel secondo DropDownList dipendono da ciò che l'utente ha selezionato nel primo. Sto passando questi dati al mio punto di vista in ViewBag come segue:Rasoio MVC 4 - Creazione di una DropDownList dinamica

List<SelectListItem> firstBoxChoices = ViewBag.firstBoxChoices; 
    Dictionary<string, List<SelectListItem>> secondBoxDict = ViewBag.secondBoxDict; 

Il primo oggetto ha le scelte per la prima DropDownList. Quando l'utente seleziona uno di questi, ho bisogno di ottenere l'elenco appropriato di scelte per il secondo DropDownList dal mio dizionario. Non riesco a capire come ottenere questo. Se ottengo la nuova selezione del primo DropDownList in una funzione Javascript onchange(), non sembra esserci alcun modo per utilizzare questo valore come chiave per il mio dizionario C#.

Naturalmente, ho visto questa funzionalità sul web, quindi so che deve essere possibile in qualche modo. Come posso raggiungere questo obiettivo?

Grazie!

risposta

7

Ci sono un paio di modi per farlo senza costringervi a memorizzare tutti gli elementi di dati possibili nel modello, la mia preferenza è usare Javascript/JQuery. Ecco un esempio di un Paese/cascata Stato discesa:

Javascript utilizzato per ottenere gli stati quando viene selezionato un paese:

<script type="text/javascript"> 
    function AppendUrlParamTokens(url, params) { 

     for (var param in params) { 
      if (params[param] == null) { 
       delete params[param]; 
      } 
     } 

     return url + "?" + jQuery.param(params); 
    } 

    function OnCountriesChange(ddl) { 
     jQuery.getJSON(AppendUrlParamTokens('@Url.Action("GetStates", "Data")', { countryId: ddl.options[ddl.selectedIndex].value }), function (result) { 
      var target = jQuery('#states_ddl'); 
      target.empty(); 
      jQuery(result).each(function() { 
       jQuery(document.createElement('option')) 
        .attr('value', this.Value) 
        .text(this.Text) 
        .appendTo(target); 
      }); 
     }); 
    }; 
</script> 

Paese discesa:

@Html.DropDownListFor(model => model.Country, new SelectList(Model.Countries, "Value", "Text", Model.PreviousCountrySelected), "(Select One)", new { id = "countries_ddl", onchange = "OnCountriesChange(this)" }) 

discesa Stato:

Html.DropDownListFor(model => model.State, 
           Model.States != null 
             ? new SelectList(Model.States, "Value", "Text", Model.PreviousStateSelected) 
             : new SelectList(new List<SelectListItem>(), "Value", "Text"), 
           new { id = "states_ddl" }) 

Metodo di controllo per recuperare gli stati:

public ActionResult GetStates(short? countryId) 
{ 
    if (!countryId.HasValue) 
    { 
     return Json(new List<object>(), JsonRequestBehavior.AllowGet); 
    } 

    var data = GetAllStatesForCountry(countryId.Value).Select(o => new { Text = o.StateName, Value = o.StateId }); 

    return Json(data, JsonRequestBehavior.AllowGet); 
} 

L'idea è che alla selezione del menu a discesa 1 si usi ajax per recuperare il valore del secondo menu a discesa.

Edit: dimenticato di includere metodo di utilità per la costruzione degli URL

+0

Questo è proprio quello che stavo cercando! Grazie. –

3

La .change caso di vostra prima selezionare dovrebbe popolare il secondo di selezione chiamando un metodo server che restituisce i dati di opzione in base al valore selezionato. Dato il seguente vista del modello

public class MyModel 
{ 
    [Required(ErrorMessage = "Please select an organisation")] 
    [Display(Name = "Organisation")] 
    public int? SelectedOrganisation { get; set; } 
    [Required(ErrorMessage = "Please select an employee")] 
    [Display(Name = "Employee")] 
    public int? SelectedEmployee { get; set; } 
    public SelectList OrganisationList { get; set; } 
    public SelectList EmployeeList { get; set; } 
} 

controller

public ActionResult Edit(int ID) 
{ 
    MyModel model = new MyModel(); 
    model.SelectedOrganisation = someValue; // set if appropriate 
    model.SelectedEmployee = someValue; // set if appropriate 
    ConfigureEditModel(model); // populate select lists 
    return View(model); 
} 

[HttpPost] 
public ActionResult Edit(MyModel model) 
{ 
    if(!ModelState.IsValid) 
    { 
    ConfigureEditModel(model); // reassign select lists 
    return View(model); 
    } 
    // save and redirect 
} 

private void ConfigureEditModel(MyModel model) 
{ 
    // populate select lists 
    model.OrganisationList = new SelectList(db.Organisations, "ID", "Name"); 
    if(model.SelectedOrganisation.HasValue) 
    { 
    var employees = db.Employees.Where(e => e.Organisation == model.SelectedOrganisation.Value); 
    model.EmployeeList = new SelectList(employees, "ID", 
    } 
    else 
    { 
    model.EmployeeList = new SelectList(Enumerable.Empty<SelectListItem>()); 
    } 
} 

[HttpGet] 
public JsonResult FetchEmployees(int ID) 
{ 
    var employees = db.Employees.Where(e => e.Organisation == ID).Select(e => new 
    { 
    ID = e.ID, 
    Name = e.Name 
    }); 
    return Json(employees, JsonRequestBehavior.AllowGet); 
} 

View

@model MyModel 
.... 
    @Html.LabelFor(m => m.SelectedOrganisation) 
    @Html.DropDownListFor(m => m.SelectedOrganisation, Model.OrganisationList, "-Please select-") 
    @Html.ValidationMessageFor(m => m.SelectedOrganisation) 
    @Html.LabelFor(m => m.SelectedEmployee) 
    @Html.DropDownListFor(m => m.SelectedEmployee, Model.EmployeeList, "-Please select-") 
    @Html.ValidationMessageFor(m => m.SelectedEmployee) 
.... 

Script

var url = '@Url.Action("FetchEmployees")'; 
var employees = $('SelectedEmployee'); 
$('#SelectedOrganisation').change(function() { 
    employees.empty(); 
    if(!$(this).val()) { 
    return; 
    } 
    employees.append($('<option></option>').val('').text('-Please select-')); 
    $.getJson(url, { ID: $(this).val() }, function(data) { 
    $.each(data, function(index, item) { 
     employees.append($('<option></option>').val(item.ID).text(item.Text)); 
    }); 
    }); 
}); 
+0

Anche un'ottima risposta. Grazie! –

Problemi correlati