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

时间:2011-08-08 14:45:30

标签: ajax asp.net-mvc-3 jquery razor

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

我已经尝试过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" })

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

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

更新

我已将代码更新为Darin的代码,但我无法使其正常工作:

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

3 个答案:

答案 0 :(得分:3)

以下是级联下拉列表的示例。一如既往地定义视图模型:

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

答案 1 :(得分:1)

jQuery脚本将如下所示:

<script type="text/javascript">
function getCities(abbr) {
    $.ajax({
        url: "@Url.Action("Cities", "Locations")",
        data: {abbreviation: abbr},
        dataType: "json",
        type: "POST",
        error: function() {
            alert("An error occurred.");
        },
        success: function(data) {
            var items = "";
            $.each(data, function(i, item) {
                items += "<option value=\"" + item.Value + "\">" + item.Text + "</option>";
            });

            $("#City").html(items);
        }
    });
}

$(document).ready(function(){
    $("#State").change(function() {
        var abbr = $("#State").val();

        getCities(abbr);
    });
});
</script>

检索数据的存储库可能看起来像这样(显然可以将其连接到实时数据):

public class LocationRepository : ILocationRepository
{
    public IQueryable<State> GetStates()
    {
        return new List<State>
        {
            new State { Abbreviation = "NE", Name = "Nebraska" },
            new State { Abbreviation = "NC", Name = "North Carolina" }
        }.AsQueryable();
    }

    public IQueryable<City> GetCities(string abbreviation)
    {
        var cities = new List<City>();

        if (abbreviation == "NE")
        {
            cities.AddRange(new List<City> {
                new City { Id = 1, Name = "Omaha" },
                new City { Id = 2, Name = "Lincoln" }
            });
        }
        else if (abbreviation == "NC")
        {
            cities.AddRange(new List<City> {
                new City { Id = 3, Name = "Charlotte" },
                new City { Id = 4, Name = "Raleigh" }
            });
        }

        return cities.AsQueryable();
    }
}

public interface ILocationRepository
{
    IQueryable<State> GetStates();
    IQueryable<City> GetCities(string abbreviation);
}

控制器可能如下所示:

public class LocationsController : Controller
{
    private ILocationRepository locationRepository = new LocationRepository();

    [HttpPost]
    public ActionResult States()
    {
        var states = locationRepository.GetStates();

        return Json(new SelectList(state, "Id", "Name"));
    } 

     [HttpPost]
    public ActionResult Cities(string abbreviation)
    {
        var cities = locationRepository.GetCities(abbreviation);

        return Json(new SelectList(cities, "Abbreviation", "Name")); 
    }
}

答案 2 :(得分:1)

我假设您从服务器端填充父下拉列表,此父dd中的第一个选项是"--- Select ---"

你可以试试这个

$(document).ready(function () {
   var $parent = $('#ddlParentCategories');

   var $child = $('#ddlChildCategories');
   $child.find("option:gt(0)").remove();

   if(!$parent.children().eq(0).is(":selected")){

     $parent.change(function () {
        $.ajax({
          url: "urlToFetchTheChild",
          data: { categoryId: this.value },
          success: function(data){  
            //The data you send should be a well formed array of json object containing code/value pair of child categories

            for(var i = 0;i<data.length;i++){
               $child.append("<option value='"+ data[i].code +"'>"+ data[i].value +"</option>"); 
            }

          }
        });
     });
   }


});