ajax - 根据从父级下拉列表中选择的内容填充子级下拉列表

原文 标签 ajax asp.net-mvc-3 jquery razor

Populating child drop down based on what was selected from parent drop down list

I am using the latest version of jQuery and ASP.NET MVC 3 with the Razor view engine.

I have tried Google looking for a decent example of loading a child drop down list when a parent drop down item is selected. I am looking to do this via jQuery AJAX using JSON. My knowledge of this is zero.

I have a Category class with a list of categories. It's a parent-child association.

If I select a category from the parent drop down list, then all the child categories need to be listed in the child drop down list for the selected parent category.

This is what I currently have, but need to complete it, not sure if I am in the right direction:

$(document).ready(function () {
   $('#ddlParentCategories').change(function () {
      alert('changed');
   });
});

I loaded my drop down list from my view model as such:

@Html.DropDownListFor(x => x.ParentCategoryId, new SelectList(Model.ParentCategories, "Id", "Name", Model.ParentCategoryId), "-- Select --", new { id = "ddlParentCategories" })

The first item has text "-- Select --" (for both parent and child drop down lists). On initial page load nothing must be loaded in the child drop down list. When a value is selected then the child drop down list must be populated. And when "-- Select --" is selected again in the parent drop down list then all the items in the child drop down list must cleared except "-- Select --".

If possible, if the child categories is loading, how do I display that "round" loading icon?

UPDATE

I have updated my code to Darin's code, and I cannot get it to work properly:

Category class:

public class Category
{
   public int Id { get; set; }
   public string Name { get; set; }
   public string Description { get; set; }
   public string MetaKeywords { get; set; }
   public string MetaDescription { get; set; }
   public bool IsActive { get; set; }
   public int? ParentCategoryId { get; set; }
   public virtual Category ParentCategory { get; set; }
   public virtual ICollection<Category> ChildCategories { get; set; }
}

EditProductViewModel class:

public class EditProductViewModel
{
   public int Id { get; set; }
   public string Name { get; set; }
   public string ShortDescription { get; set; }
   public string LongDescription { get; set; }
   public bool IsActive { get; set; }
   public string PageTitle { get; set; }
   public bool OverridePageTitle { get; set; }
   public string MetaKeywords { get; set; }
   public string MetaDescription { get; set; }
   public int ParentCategoryId { get; set; }
   public IEnumerable<Category> ParentCategories { get; set; }
   public int ChildCategoryId { get; set; }
   public IEnumerable<Category> ChildCategories { get; set; }
}

ProductController class:

public ActionResult Create()
{
   EditProductViewModel viewModel = new EditProductViewModel
   {
      ParentCategories = categoryService.GetParentCategories()
         .Where(x => x.IsActive)
         .OrderBy(x => x.Name),
      ChildCategories = Enumerable.Empty<Category>(),
      IsActive = true
   };

   return View(viewModel);
}

public ActionResult AjaxBindingChildCategories(int parentCategoryId)
{
   IEnumerable<Category> childCategoryList = categoryService.GetChildCategoriesByParentCategoryId(parentCategoryId);

   return Json(childCategoryList, JsonRequestBehavior.AllowGet);
}

Create view:

<tr>
   <td><label>Parent Category:</label> <span class="red">*</span></td>
   <td>@Html.DropDownListFor(x => x.ParentCategoryId,
         new SelectList(Model.ParentCategories, "Id", "Name", Model.ParentCategoryId),
         "-- Select --",
         new { data_url = Url.Action("AjaxBindingChildCategories"), id = "ParentCategories" }
      )
      @Html.ValidationMessageFor(x => x.ParentCategoryId)
   </td>
</tr>
<tr>
   <td><label>Child Category:</label> <span class="red">*</span></td>
   <td>@Html.DropDownListFor(x => x.ChildCategoryId,
         new SelectList(Model.ChildCategories, "Id", "Name", Model.ChildCategoryId),
         "-- Select --",
         new { id = "ChildCategories" }
      )
      @Html.ValidationMessageFor(x => x.ChildCategoryId)
   </td>
</tr>

<script type="text/javascript">

   $(document).ready(function () {
      $('#ParentCategories').change(function () {
         var url = $(this).data('url');
         var data = { parentCategoryId: $(this).val() };

         $.getJSON(url, data, function (childCategories) {
            var childCategoriesDdl = $('#ChildCategories');
            childCategoriesDdl.empty();

            $.each(childCategories, function (index, childCategory) {
               childCategoriesDdl.append($('<option/>', {
                  value: childCategory, text: childCategory
               }));
            });
         });
      });
   });


</script>

It goes into my AjaxBindingChildCategories action and it brings back records, it just doesn't want to display my child category dropdownlist. I had a look in Fire Bug and the error that I get is:

GET AjaxBindingChildCategories?parentCategoryId=1

500 Internal Server Error
Answer

Here's an example of cascading drop down lists. As always start by defining a view model:

public class MyViewModel
{
    [DisplayName("Country")]
    [Required]
    public string CountryCode { get; set; }
    public IEnumerable<SelectListItem> Countries { get; set; }

    public string City { get; set; }
    public IEnumerable<SelectListItem> Cities { get; set; }
}

then a controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MyViewModel
        {
            // TODO: Fetch countries from somewhere
            Countries = new[]
            {
                new SelectListItem { Value = "FR", Text = "France" },
                new SelectListItem { Value = "US", Text = "USA" },
            },

            // initially we set the cities ddl to empty
            Cities = Enumerable.Empty<SelectListItem>()
        };
        return View(model);
    }

    public ActionResult Cities(string countryCode)
    {
        // TODO: based on the selected country return the cities:
        var cities = new[]
        {
            "Paris", "Marseille", "Lyon"
        };
        return Json(cities, JsonRequestBehavior.AllowGet);
    }
}

a view:

@model MyViewModel

@using (Html.BeginForm())
{
    <div>
        @Html.LabelFor(x => x.CountryCode)
        @Html.DropDownListFor(
            x => x.CountryCode, 
            Model.Countries, 
            "-- Select country --", 
            new { data_url = Url.Action("cities") }
        )
        @Html.ValidationMessageFor(x => x.CountryCode)
    </div>

    <div>
        @Html.LabelFor(x => x.City)
        @Html.DropDownListFor(
            x => x.City, 
            Model.Cities, 
            "-- Select city --"
        )
        @Html.ValidationMessageFor(x => x.City)
    </div>

    <p><input type="submit" value="OK" /></p>
}

and finally the unobtrusive javascript in a separate file:

$(function () {
    $('#CountryCode').change(function () {
        var url = $(this).data('url'); 
        var data = { countryCode: $(this).val() };
        $.getJSON(url, data, function (cities) {
            var citiesDdl = $('#City');
            citiesDdl.empty();
            $.each(cities, function (index, city) {
                citiesDdl.append($('<option/>', {
                    value: city,
                    text: city
                }));
            });
        });
    });
});

翻译

我正在Razor视图引擎中使用最新版本的jQuery和ASP.NET MVC 3。

我尝试过Google寻找当选择父项下拉项时加载子项下拉列表的不错的示例。我正在使用jQuery通过AJAX JSON进行此操作。我对此的了解为零。

我有一个带有类别列表的Category类。这是一个亲子协会。

如果我从父下拉列表中选择一个类别,则所有子类别都需要在所选父类别的子下拉列表中列出。

这是我目前拥有的,但是需要完成它,不确定我的方向是否正确:

$(document).ready(function () {
   $('#ddlParentCategories').change(function () {
      alert('changed');
   });
});


我从视图模型中这样加载了下拉列表:

@Html.DropDownListFor(x => x.ParentCategoryId, new SelectList(Model.ParentCategories, "Id", "Name", Model.ParentCategoryId), "-- Select --", new { id = "ddlParentCategories" })


第一项带有文本“-Select-”(用于父级和子级下拉列表)。初始页面加载时,子下拉列表中不得加载任何内容。选择一个值后,必须填充子下拉列表。当在父下拉列表中再次选择“-选择-”时,必须清除子下拉列表中的所有项目,但“-选择-”除外。

如果可能,如果正在加载子类别,如何显示“圆形”加载图标?

更新

我已经将代码更新为达林的代码,但无法正常工作:

Category类:

public class Category
{
   public int Id { get; set; }
   public string Name { get; set; }
   public string Description { get; set; }
   public string MetaKeywords { get; set; }
   public string MetaDescription { get; set; }
   public bool IsActive { get; set; }
   public int? ParentCategoryId { get; set; }
   public virtual Category ParentCategory { get; set; }
   public virtual ICollection<Category> ChildCategories { get; set; }
}


EditProductViewModel类:

public class EditProductViewModel
{
   public int Id { get; set; }
   public string Name { get; set; }
   public string ShortDescription { get; set; }
   public string LongDescription { get; set; }
   public bool IsActive { get; set; }
   public string PageTitle { get; set; }
   public bool OverridePageTitle { get; set; }
   public string MetaKeywords { get; set; }
   public string MetaDescription { get; set; }
   public int ParentCategoryId { get; set; }
   public IEnumerable<Category> ParentCategories { get; set; }
   public int ChildCategoryId { get; set; }
   public IEnumerable<Category> ChildCategories { get; set; }
}


ProductController类:

public ActionResult Create()
{
   EditProductViewModel viewModel = new EditProductViewModel
   {
      ParentCategories = categoryService.GetParentCategories()
         .Where(x => x.IsActive)
         .OrderBy(x => x.Name),
      ChildCategories = Enumerable.Empty<Category>(),
      IsActive = true
   };

   return View(viewModel);
}

public ActionResult AjaxBindingChildCategories(int parentCategoryId)
{
   IEnumerable<Category> childCategoryList = categoryService.GetChildCategoriesByParentCategoryId(parentCategoryId);

   return Json(childCategoryList, JsonRequestBehavior.AllowGet);
}


Create视图:

<tr>
   <td><label>Parent Category:</label> <span class="red">*</span></td>
   <td>@Html.DropDownListFor(x => x.ParentCategoryId,
         new SelectList(Model.ParentCategories, "Id", "Name", Model.ParentCategoryId),
         "-- Select --",
         new { data_url = Url.Action("AjaxBindingChildCategories"), id = "ParentCategories" }
      )
      @Html.ValidationMessageFor(x => x.ParentCategoryId)
   </td>
</tr>
<tr>
   <td><label>Child Category:</label> <span class="red">*</span></td>
   <td>@Html.DropDownListFor(x => x.ChildCategoryId,
         new SelectList(Model.ChildCategories, "Id", "Name", Model.ChildCategoryId),
         "-- Select --",
         new { id = "ChildCategories" }
      )
      @Html.ValidationMessageFor(x => x.ChildCategoryId)
   </td>
</tr>

<script type="text/javascript">

   $(document).ready(function () {
      $('#ParentCategories').change(function () {
         var url = $(this).data('url');
         var data = { parentCategoryId: $(this).val() };

         $.getJSON(url, data, function (childCategories) {
            var childCategoriesDdl = $('#ChildCategories');
            childCategoriesDdl.empty();

            $.each(childCategories, function (index, childCategory) {
               childCategoriesDdl.append($('<option/>', {
                  value: childCategory, text: childCategory
               }));
            });
         });
      });
   });


</script>


它进入我的AjaxBindingChildCategories动作,并带回记录,它只是不想显示我的子类别下拉列表。我看了一下Fire Bug,发现的错误是:

GET AjaxBindingChildCategories?parentCategoryId=1

500 Internal Server Error
最佳答案
这是级联下拉列表的示例。与往常一样,首先定义一个视图模型:

public class MyViewModel
{
    [DisplayName("Country")]
    [Required]
    public string CountryCode { get; set; }
    public IEnumerable<SelectListItem> Countries { get; set; }

    public string City { get; set; }
    public IEnumerable<SelectListItem> Cities { get; set; }
}


然后是一个控制器:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MyViewModel
        {
            // TODO: Fetch countries from somewhere
            Countries = new[]
            {
                new SelectListItem { Value = "FR", Text = "France" },
                new SelectListItem { Value = "US", Text = "USA" },
            },

            // initially we set the cities ddl to empty
            Cities = Enumerable.Empty<SelectListItem>()
        };
        return View(model);
    }

    public ActionResult Cities(string countryCode)
    {
        // TODO: based on the selected country return the cities:
        var cities = new[]
        {
            "Paris", "Marseille", "Lyon"
        };
        return Json(cities, JsonRequestBehavior.AllowGet);
    }
}


一个看法:

@model MyViewModel

@using (Html.BeginForm())
{
    <div>
        @Html.LabelFor(x => x.CountryCode)
        @Html.DropDownListFor(
            x => x.CountryCode, 
            Model.Countries, 
            "-- Select country --", 
            new { data_url = Url.Action("cities") }
        )
        @Html.ValidationMessageFor(x => x.CountryCode)
    </div>

    <div>
        @Html.LabelFor(x => x.City)
        @Html.DropDownListFor(
            x => x.City, 
            Model.Cities, 
            "-- Select city --"
        )
        @Html.ValidationMessageFor(x => x.City)
    </div>

    <p><input type="submit" value="OK" /></p>
}


最后在一个单独的文件中使用简洁的javascript:

$(function () {
    $('#CountryCode').change(function () {
        var url = $(this).data('url'); 
        var data = { countryCode: $(this).val() };
        $.getJSON(url, data, function (cities) {
            var citiesDdl = $('#City');
            citiesDdl.empty();
            $.each(cities, function (index, city) {
                citiesDdl.append($('<option/>', {
                    value: city,
                    text: city
                }));
            });
        });
    });
});
相关推荐

php - 实时更新网页

php - 我的Codeigniter使用Ajax自动完成

php - 实时更新ajax图表

javascript - 该网页如何更新? Firebug显示没有净活动?

php - PHP-如何提交包含指向不同MySQL行的输入字段的表单

jquery - 在不使用REST或JSON的情况下使用basichttpbinding调用wcf webservice

javascript - AJAX PageMethods与路由冲突?

jquery - 在Rails 3中通过.ajax渲染静态局部

c# - 从AJAX服务返回大型JSON文件-WCF

javascript - jQuery Validator —自定义方法有效时不会隐藏错误