为了账号安全,请及时绑定邮箱和手机立即绑定

MVC 3 Razor视图中的级联下降

/ 猿问

MVC 3 Razor视图中的级联下降

慕妹3242003 2019-10-05 07:07:13

MVC 3 Razor视图中的级联下降

我对如何实现Razor视图中地址的级联下拉列表感兴趣。我的站点实体具有SuburbId属性。郊区有城市身份证,城市有省。我想在站点视图上显示所有郊区、城市和省的下拉列表,例如,郊区下拉列表将首先显示“首先选择一个城市”,而城市下拉列表显示“首先选择一个省”。在选择一个省时,该省的城市都是人口密集的。

我怎样才能做到这一点?我从哪里开始?


查看完整描述

3 回答

?
芜湖不芜


让我们用一个例子来说明。像往常一样,从模型开始:

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>

作为一种改进,可以通过编写jQuery插件来缩短javascript代码,以避免重复某些部分。


最新情况:

说到插件,你可以在其中找到一些东西:

(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')
    });});



查看完整回答
反对 回复 2019-10-13
?
潇潇雨雨

这极大地帮助了我达到目的。但是正如‘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();
                }

希望这能帮助有类似问题的人。



查看完整回答
反对 回复 2019-10-13
?
不负相思意

要实现支持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部分,页面必须完全加载,然后尝试使下降级联。



查看完整回答
反对 回复 2019-10-13

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信