65.9K
CodeProject 正在变化。 阅读更多。
Home

级联下拉列表和部分视图

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.65/5 (6投票s)

2013年6月13日

CPOL

3分钟阅读

viewsIcon

31286

downloadIcon

1179

使用JavaScript Voodoo在MVC中实现级联下拉列表以显示PartialViews。

引言

一篇短文,介绍了如何在MVC Razor页面中连接下拉列表,以动态更新并使用PartialViews填充页面。

背景 

MVC Image

由于我刚接触MVC和Web开发,我很难理解JavaScript与我的控制器操作的交互。 在浏览了网络并问了许多愚蠢的问题之后,这是一个我拼凑并发现有用的简单解决方案。

如果您不了解MVC模式和/或Entity Framework,那么这篇文章可能不适合您,因为我不会深入解释如何连接这些。

使用代码

这里需要几件事。 我正在使用Entity Framework - Model First方法,因此我们需要设置一个简单的数据库。

这可以使用静态模型来完成,但这也很简单。 提供了一个脚本,但架构很简单: 

Create Table ProductType(
  Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
  Name VarChar(50) UNIQUE NOT NULL
)
 
Create Table ProductCategory(
  Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
  ProductTypeId INT NOT NULL FOREIGN KEY REFERENCES ProductType(Id),
  Name VARCHAR(50) NOT NULL ,
)
 
Create Table Product(
  Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
  ProductCategoryId INT NOT NULL FOREIGN KEY REFERENCES ProductType(Id),
  Name VARCHAR(50) NOT NULL,
  Description (200) NOT NULL,
  Price Decimal(12,4) NOT NULL
)

然后,我们将一个新的ADO.NET实体数据模型项添加到我们的Models文件夹中。 我将其命名为ProductDataEntities

您的解决方案应类似于这样

Solution Image

请注意,Visual Studio创建了许多文件夹来组织您的项目。 我们将感兴趣的文件夹是

  1. Controllers 
  2. 模型
  3. Views 

让我们看看控制器

首先,我们需要一个Action来显示我们的页面。 在这种情况下,我们将获取一个ProductType对象列表,并将对我们之前创建的Entity Model的引用传递给我们的.cshtm页面: 

public ActionResult Index(){
 var productTypes = db.ProductTypes.OrderBy(p=>p.Name);
 ViewBag.ProductTypes = productTypes;
 return View();
}

我们还需要一个JsonResultProductCategory数据传递回第二个DropDownList

[AllowVerbs(HtmlVerbs.Get)]
public JsonResult GetCategoryList(string ptypeid){
  if (string.IsNullOrEmpty*ptypeid)
    return Json(HttpNotFound());
  var categoryList = GetCategoryList(Convert.ToInt32(Ptypeid));
  var categoryData = categoryList.Select(m => new SelectListItem(){
     Text = m.Name,
     Value = m.Id.ToString()
    });
  return Json(categoryData, JsonRequestBehavior.AllowGet); 
}  

我们还需要一个小的辅助方法来获取JsonResult中的categoryData参数的对象列表: 

private IList<ProductCategory> GetCategoryList(int ptypeid){
  return db.ProductCategory.OrderBy(c=>c.Name).Where(c=>c.ProductTypeId == ptypeid).ToList();
}

最后,但并非最不重要的是一个ActionResult,它将渲染我们的PartialView

public ActionResult GetProducts(string Id)
{
  int i = Convert.ToInt32(Id)
  var products = db.Products.OrderBy(p=>p.Name).Where(p=>p.ProductCategoryId == id); 
  return PartialView(products);
}

现在我们已经完成了C#方面的工作(是的,这确实是所需的所有代码),我们可以继续使用View

View

我们的Index View仅包含几个DropDownList对象和一个名为ddlproducts的空div元素

@Model ProductData.Models.ProductDataEntities
  ...
  <div> <h4> Product Types </h4>
    <p>@Html.DropDownListFor(model => model.ProductTypes, 
        new SelectList(@ViewBag.ProductTypes, "Id", "Name"),
        "--select a Product Type--",
        new {
            id = "ddlProductTypes"
        })</p> 
 
    <h4>Product Category</h4>
    <p>@Html.DropDownList("Id", new SelectList(
              Enumerable.Empty<SelectListItem>(), "Id", "Name"), 
        "-- select a Product Category --",
	new
	{
	    id = "ddlProductCategorys",
	    data_url = Url.Action("GetProducts", "Home")
	})</p>
  
</div>  
<div id="ddlproducts"></div>

请注意第二个DropDownList中的data_url = Url.Action("GetProducts", "Home")参数。 这告诉我们的脚本在change事件上调用什么方法。 GetProducts Action返回一个PartialView,该View被加载到我们空的div元素中。

PartialView   

列出我们返回的Product对象

@model IEnumerable<CascadingDDL_MVC.Models.Product>
 
  @Html.ActionLink("Create New", "Create")
  <table><tr
    <th>
      @Html.DisplayNameFor(model => model.Name)
    </th>
    <th>
      @Html.DisplayNameFor(model => model.Description)
    </th>
    <th>
      @Html.DisplayNameFor(model => model.Price)
    </th>
    <th><
  @foreach (var item in Model) {
    <tr>
      <td>
        @Html.DisplayFor(modelItem => item.Name)
      </td>
      <td>
        @Html.DisplayFor(modelItem => item.Description)
      </td>
      <td>
        @Html.DisplayFor(modelItem => item.Price)
      </td>
      <td>
        @Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
        @Html.ActionLink("Details", "Details", new { id=item.Id }) |
        @Html.ActionLink("Delete", "Delete", new { id=item.Id })
      </td>
    </tr>
</table>

现在所有这些C#和CSHTML都很好,但在目前阶段,我们的示例并没有做太多。 当然,ProductType DropDownList将被数据填充,但是当您选择一个项目时,什么也不会发生。 这就是JavaScript Voodoo的用武之地。 

JavaScript 

免责声明 - 我发现JavaScript令人沮丧。 很难阅读,而且通常看起来像来自许多猴子的输出。 但是,它是一个非常有用的工具,用于操作DOM,因此我敦促您学习它。 值得庆幸的是,我们的脚本非常简单,应该相对容易理解。 也就是说,JavaScript仍然让我感到头疼!

请注意,对拼写的关注非常重要。 请帮自己一个忙,剪切并粘贴您的参数。

在Index.cshtml文件的最底部...  

<script type="text/javascript" 
         src="../../Scripts/jquery-1.8.2.min.js"></script>
<script type="text/javascript">
 $(function () {
   $("#ddlProductTypes").change(function () {
     var typeid = $(this).val();
     // Clear the resilt div '#ddlproducts' if there is already a list displayed
     $('#products').html("");
     // Get the ProductCategory data and load into second DropDownList
     $.getJSON("../Home/LoadCategorys", { typeid: typeid },
     function (categoryData) { //
       var select = $("#ddlProductCategorys");
       select.empty();
       select.append($('<option/>', {
         value: 0,
         text: "-- select a category --"
         $.each(categoryData, function (index, itemData) {
           select.append($('<option/>', {
             value: itemData.Value,
             text: itemData.Text
         }));
       });
     });
   });
   $(function () {                            //This is fired when we select a Product Category
     $('#ddlProductCategorys').change(function () {
       var url = $(this).data('url');
       var value = $(this).val();
       $('#products').load(url, { id: value });
    });
  });
});
 
</script> 

脚本会等待一个change事件 

$("#ddlProductTypes").change(function () {

当我们选择ProductTypeddlProductType)DropDownList中的一个项目时,会触发该事件。 反过来,这会调用我们的JsonAction方法LoadCategorys,该方法返回要加载到第二个DropDownList(ddlProductCategorys)中的ProductCategory数据列表(categoryData)。

接下来,我们使用另一个Action方法,该方法被分配给DropDownList的数据属性 

data_url = Url.Action("GetProducts", "Home") 

通过将结果分配给<div id="products>元素的load参数。 

$('#products').load(url, { id: value });  

这将调用Home Controller中的GetProducts ActionMethod,该方法返回要加载的标记。

就这么简单。

© . All rights reserved.