2010-12-16 74 views
47

我對如何實現Razor視圖中地址的級聯下拉列表感興趣。我的網站實體具有SuburbId屬性。郊區有CityId,城市有ProvinceId。我想在網站視圖中顯示所有郊區,城市和省的下拉菜單,例如,郊區下拉菜單將首先顯示「首選城市」,城市下拉菜單「首選省份」。在選擇一個省,省內的城市人口衆多等。MVC 3 Razor視圖中的級聯下拉

我該如何做到這一點?我從哪說起呢?

+0

我的博客層疊的DropDownList在ASP.Net MVC(http://blogs.msdn.com/b/ rickandy/archive/2012/01/09/cascasding-dropdownlist-in-asp-net-mvc.aspx)完全正確。另請參閱我的教程使用DropDownList Box和jQuery(http://www.asp.net/mvc/tutorials/javascript/working-with-the-dropdownlist-box-and-jquery/using-the-dropdownlist-helper- with-aspnet-mvc) – RickAndMSFT 2012-03-23 17:06:52

回答

86

我們來舉個例子來說明。與往常一樣開始一個模型:

public class MyViewModel 
{ 
    public string SelectedProvinceId { get; set; } 
    public string SelectedCityId { get; set; } 
    public string SelectedSuburbId { get; set; } 
    public IEnumerable<Province> Provinces { get; set; } 
} 

public class Province 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
} 

下一個控制器:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     var model = new MyViewModel 
     { 
      // TODO: Fetch those from your repository 
      Provinces = Enumerable.Range(1, 10).Select(x => new Province 
      { 
       Id = (x + 1).ToString(), 
       Name = "Province " + x 
      }) 
     }; 
     return View(model); 
    } 

    public ActionResult Suburbs(int cityId) 
    { 
     // TODO: Fetch the suburbs from your repository based on the cityId 
     var suburbs = Enumerable.Range(1, 5).Select(x => new 
     { 
      Id = x, 
      Name = "suburb " + x 
     }); 
     return Json(suburbs, JsonRequestBehavior.AllowGet); 
    } 

    public ActionResult Cities(int provinceId) 
    { 
     // TODO: Fetch the cities from your repository based on the provinceId 
     var cities = Enumerable.Range(1, 5).Select(x => new 
     { 
      Id = x, 
      Name = "city " + x 
     }); 
     return Json(cities, JsonRequestBehavior.AllowGet); 
    } 
} 

最後一個觀點:

@model SomeNs.Models.MyViewModel 

@{ 
    ViewBag.Title = "Home Page"; 
} 

<script type="text/javascript" src="/scripts/jquery-1.4.4.js"></script> 
<script type="text/javascript"> 
    $(function() { 
     $('#SelectedProvinceId').change(function() { 
      var selectedProvinceId = $(this).val(); 
      $.getJSON('@Url.Action("Cities")', { provinceId: selectedProvinceId }, function (cities) { 
       var citiesSelect = $('#SelectedCityId'); 
       citiesSelect.empty(); 
       $.each(cities, function (index, city) { 
        citiesSelect.append(
         $('<option/>') 
          .attr('value', city.Id) 
          .text(city.Name) 
        ); 
       }); 
      }); 
     }); 

     $('#SelectedCityId').change(function() { 
      var selectedCityId = $(this).val(); 
      $.getJSON('@Url.Action("Suburbs")', { cityId: selectedCityId }, function (suburbs) { 
       var suburbsSelect = $('#SelectedSuburbId'); 
       suburbsSelect.empty(); 
       $.each(suburbs, function (index, suburb) { 
        suburbsSelect.append(
         $('<option/>') 
          .attr('value', suburb.Id) 
          .text(suburb.Name) 
        ); 
       }); 
      }); 
     }); 
    }); 
</script> 

<div> 
    Province: 
    @Html.DropDownListFor(x => x.SelectedProvinceId, new SelectList(Model.Provinces, "Id", "Name")) 
</div> 
<div> 
    City: 
    @Html.DropDownListFor(x => x.SelectedCityId, Enumerable.Empty<SelectListItem>()) 
</div> 
<div> 
    Suburb: 
    @Html.DropDownListFor(x => x.SelectedSuburbId, Enumerable.Empty<SelectListItem>()) 
</div> 

作爲改進的JavaScript代碼可以通過寫一個jQuery縮短插件以避免重複某些部分。


UPDATE:

和談論的一個插件,你可以有在電線之間的東西:

(function ($) { 
    $.fn.cascade = function (options) { 
     var defaults = { }; 
     var opts = $.extend(defaults, options); 

     return this.each(function() { 
      $(this).change(function() { 
       var selectedValue = $(this).val(); 
       var params = { }; 
       params[opts.paramName] = selectedValue; 
       $.getJSON(opts.url, params, function (items) { 
        opts.childSelect.empty(); 
        $.each(items, function (index, item) { 
         opts.childSelect.append(
          $('<option/>') 
           .attr('value', item.Id) 
           .text(item.Name) 
         ); 
        }); 
       }); 
      }); 
     }); 
    }; 
})(jQuery); 

,然後簡單地連線起來:

$(function() { 
    $('#SelectedProvinceId').cascade({ 
     url: '@Url.Action("Cities")', 
     paramName: 'provinceId', 
     childSelect: $('#SelectedCityId') 
    }); 

    $('#SelectedCityId').cascade({ 
     url: '@Url.Action("Suburbs")', 
     paramName: 'cityId', 
     childSelect: $('#SelectedSuburbId') 
    }); 
}); 
+1

我正要寫一篇評論,內容是「爲什麼要進入這項工作?使用jquery插件」 - 然後我讀了你的最後一句話。 :) +1 – RPM1984 2010-12-16 09:21:33

+4

+只是爲了您的答案的全面性,謝謝。我還沒有在我的代碼中使用它。但它看起來像一個勝利者。 – ProfK 2010-12-16 09:22:32

+1

我只寫了我的javascript函數,然後向下滾動查看函數:/ +1。 – Doomsknight 2011-11-24 16:17:44

5

感謝Darin爲您帶來解決方案。它極大地幫助我達到了這一點。但正如'xxviktor'提到的那樣,我確實得到了通告。錯誤。爲了擺脫它,我已經這樣做了。

public string GetCounties(int countryID) 
    { 
     List<County> objCounties = new List<County>(); 
     var objResp = _mastRepo.GetCounties(countryID, ref objCounties); 
     var objRetC = from c in objCounties 
         select new SelectListItem 
         { 
          Text = c.Name, 
          Value = c.ID.ToString() 
         }; 
     return new JavaScriptSerializer().Serialize(objRetC); 
    } 

爲了實現自動級聯,我用這種方法稍微擴展了jQuery擴展。

 $('#ddlCountry').cascade({ 
      url: '@Url.Action("GetCounties")', 
      paramName: 'countryID', 
      childSelect: $('#ddlState'), 
      childCascade: true 
     }); 

而實際的JS使用這個參數如下(在JSON請求內)。

   // trigger child change 
       if (opts.childCascade) { 
        opts.childSelect.change(); 
       } 

希望這可以幫助有類似問題的人。

0

要實現支持MVC的內置驗證和綁定的級聯下拉列表,您需要做一些與其他答案中所做的不同的事情。

如果你的模型有驗證,這將支持它。從模型的摘錄與驗證:

[Required] 
[DisplayFormat(ConvertEmptyStringToNull = false)]  
public Guid cityId { get; set; } 

在你的控制器,你需要添加一個get方法,讓你的看法以後可以得到相關的數據:現在

[AcceptVerbs(HttpVerbs.Get)] 
public JsonResult GetData(Guid id) 
{ 
    var cityList = (from s in db.City where s.stateId == id select new { cityId = s.cityId, name = s.name }); 
    //simply grabbing all of the cities that are in the selected state 

    return Json(cityList.ToList(), JsonRequestBehavior.AllowGet); 
} 

,以我提到的查看早期:

在你看來,你有類似的這種兩個下拉菜單:

<div class="editor-label"> 
    @Html.LabelFor(model => model.stateId, "State") 
</div> 
<div class="editor-field"> 
    @Html.DropDownList("stateId", String.Empty) 
    @Html.ValidationMessageFor(model => model.stateId) 
</div> 

<div class="editor-label"> 
    @Html.LabelFor(model => model.cityId, "City") 
</div> 
<div class="editor-field"> 
    @*<select id="cityId"></select>*@ 
    @Html.DropDownList("cityId", String.Empty) 
    @Html.ValidationMessageFor(model => model.cityId) 
</div> 

下拉菜單中的內容由控制器綁定,並自動填充。注意:根據我的經驗,刪除此綁定並依靠java腳本來填充下拉菜單會使您失去驗證。此外,我們在這裏綁定的方式在驗證方面很好,所以沒有理由去改變它。

現在到我們的jQuery插件:

(function ($) { 
$.fn.cascade = function (secondaryDropDown, actionUrl, stringValueToCompare) { 
    primaryDropDown = this; //This doesn't necessarily need to be global 
    globalOptions = new Array(); //This doesn't necessarily need to be global 
    for (var i = 0; i < secondaryDropDown.options.length; i++) { 
     globalOptions.push(secondaryDropDown.options[i]); 
    } 

    $(primaryDropDown).change(function() { 
     if ($(primaryDropDown).val() != "") { 
      $(secondaryDropDown).prop('disabled', false); //Enable the second dropdown if we have an acceptable value 
      $.ajax({ 
       url: actionUrl, 
       type: 'GET', 
       cache: false, 
       data: { id: $(primaryDropDown).val() }, 
       success: function (result) { 
        $(secondaryDropDown).empty() //Empty the dropdown so we can re-populate it 
        var dynamicData = new Array(); 
        for (count = 0; count < result.length; count++) { 
         dynamicData.push(result[count][stringValueToCompare]); 
        } 

        //allow the empty option so the second dropdown will not look odd when empty 
        dynamicData.push(globalOptions[0].value); 
        for (var i = 0; i < dynamicData.length; i++) { 
         for (var j = 0; j < globalOptions.length; j++) { 
          if (dynamicData[i] == globalOptions[j].value) { 
           $(secondaryDropDown).append(globalOptions[j]); 
           break; 
          } 
         } 

        } 
       }, 
       dataType: 'json', 
       error: function() { console.log("Error retrieving cascading dropdown data from " + actionUrl); } 
      }); 
     } 
     else { 
      $(secondaryDropDown).prop('disabled', true); 
     } 
     secondaryDropDown.selectedindex = 0; //this prevents a previous selection from sticking 
    }); 
    $(primaryDropDown).change(); 
}; 
} (jQuery)); 

您可以複製上面的jQuery,我創建,爲<script>...</script>標籤在你看來,或者在一個單獨的腳本文件,如果你希望(注意:我更新,這使它跨瀏覽器,但是我使用的場景不再需要,但它應該可以工作)。

在這些相同的腳本標籤,(不是在一個單獨的文件),您可以通過以下JavaScript調用插件:

$(document).ready(function() { 
    var primaryDropDown = document.getElementById('stateId'); 
    var secondaryDropdown = document.getElementById('cityId'); 
    var actionUrl = '@Url.Action("GetData")' 
    $(primaryDropDown).cascade(secondaryDropdown, actionUrl); 
}); 

記得添加$(document).ready一部分,該頁面必須完全在你面前裝嘗試使下降級聯。

0

<script src="~/Scripts/jquery-1.10.2.min.js"></script> 
 

 

 
<script type="text/javascript"> 
 
    $(document).ready(function() { 
 
     //Dropdownlist Selectedchange event 
 
     $("#country").change(function() { 
 
      $("#State").empty(); 
 
      $.ajax({ 
 
       type: 'POST', 
 
       url: '@Url.Action("State")', // we are calling json method 
 

 
       dataType: 'json', 
 

 
       data: { id: $("#country").val() }, 
 
       // here we are get value of selected country and passing same value 
 
       
 

 
       success: function (states) { 
 
        // states contains the JSON formatted list 
 
        // of states passed from the controller 
 

 
        $.each(states, function (i, state) { 
 
         $("#State").append('<option value="' + state.Value + '">' + 
 
          state.Text + '</option>'); 
 
         // here we are adding option for States 
 

 
        }); 
 
       }, 
 
      error: function (ex) { 
 
       alert('Failed to retrieve states.' + ex); 
 
      } 
 
     }); 
 
     return false; 
 
    }) 
 
    }); 
 
</script>
<div> 
 
    @Html.DropDownList("country", ViewBag.country as List<SelectListItem>, "CountryName", new { style = "width: 200px;" }) 
 
</div> 
 
<div> 
 

 
</div> 
 
<div> 
 
    @Html.DropDownList("State", ViewBag.country as List<SelectListItem>) 
 

 
</div>

從控制器我收到值

public async Task<ActionResult> Country() 
    { 

     Country co = new Country(); 
     List<SelectListItem> li = new List<SelectListItem>(); 
     li.Add(new SelectListItem { Text = "Select", Value = "0" }); 
     li.Add(new SelectListItem { Text = "India", Value = "1" }); 
     li.Add(new SelectListItem { Text = "Nepal", Value = "2" }); 
     li.Add(new SelectListItem { Text = "USA", Value = "3" }); 
     li.Add(new SelectListItem { Text = "Kenya", Value = "4" }); ; 
     ViewBag.country= li; 
     return View(); 
    } 
    public JsonResult state(string id) 
    { 
     List<SelectListItem> states = new List<SelectListItem>(); 
     states.Add(new SelectListItem { Text = "--Select State--", Value = "0" }); 
     switch (id) 
     { 
      case "1": 


       states.Add(new SelectListItem { Text = "MP", Value = "1" }); 
       states.Add(new SelectListItem { Text = "UP", Value = "2" }); 
       break; 
      case "3": 

       states.Add(new SelectListItem { Text = "USA1", Value = "3" }); 
       states.Add(new SelectListItem { Text = "USA2", Value = "4" }); 
       break; 
     } 

     return Json(new SelectList(states, "Value", "Text", JsonRequestBehavior.AllowGet)); 
    }