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

带模板的 GridView 类 jQuery 插件,用于使用 MVC 和 Entity Framework 进行 CRUD 操作

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.84/5 (6投票s)

2013年12月26日

CPOL

11分钟阅读

viewsIcon

38411

downloadIcon

925

用于 Grid 数据显示的 jQuery 插件。

引言

上一篇文章中,我曾用一个Javascript对象来以类似GridView的方式显示JSON数据。它似乎能工作,但将其重写为一个jQuery插件有一些优点,例如改进的浏览器兼容性、操作的可链式调用、更简单的DOM选择等。解决了同一页面上多个GridView对象的一些问题,支持为多个GridView重用CSS类,并将事件封装在每个GridView实例内。这是早期插件的一个改进版本,启用了数据字段查找、链接字段,并与尝试使用基于模板的表单进行记录添加或编辑相关联。

这是该代码的更新版本,已针对Internet Explorer进行了调整。事实证明,在没有导致Internet Explorer崩溃的情况下,无法使用JavaScript或jQuery一次性将多个表单元素设置为空。将表单元素设置为空然后设置为空似乎可以解决该问题。 

背景

这个GridView插件的第二个版本包含一些改进和错误修复。新功能包括:数据查找字段、链接字段、用于记录添加或编辑的模板。还添加了用于CRUD操作的Entity Framework和MVC服务器端代码。

使用代码

让我们从服务器端代码开始。项目中添加了两个实体:User和Item,它们具有以下属性:

在示例应用程序视图中,它们都连接到两个不同的GridView实例,并在同一视图中使用两个单独的模板进行记录创建和编辑。

控制器方法位于CPArticle2Controller.cs文件中。每个实体都有四个方法:检索对象列表(GetJsonItems)、添加新实体、更新或删除模型中的实体。例如:

[HttpPost]
public JsonResult UpdateUser(Models.User oUser)
{  ... return Json(oEntUser, JsonRequestBehavior.AllowGet); }  //return updated record 

它们通过[HttpPost]调用,接受JsonResult格式的数据,对数据执行一些操作,然后以Json格式将更新后的实体返回给客户端。在此示例应用程序中,没有为错误处理或服务器端数据检查做特殊规定。但在生产级别的应用程序中,应该添加这些。

现在我们来看客户端。我们先从包含文件开始:

  • jquery-1.10.2.min.js - jQuery库
  • jquery-ui.js - jQuery UI,一个有用的工具和Widgets库。在此示例中,它用于使GridView插件生成的GridView在页面上可拖动,并执行一些示例动画(如果您希望启用它们)。
  • bpopup.js - 一个小的jQuery插件,用于模态弹出窗口,在您想要添加或编辑某些数据实体时,由回调函数使用。
  • gridview.js - 此处描述的GridView插件以及其他四个辅助插件 - addNewElement, formatDate, setCountryProvince 和 populateSelect。在此文件中,有一个dataArrays JSON数据对象,其中包含一些用于查找数据或填充下拉列表的数据,更多内容如下。
  • HTML body包含两个div Grid_Users 和 Grid_Items,它们用作两个GridView实例的根元素,以及用于实体处理的两个模板 GridPopUp_User 和 GridPopUp_Item。

    <div id="Grid_Users" class="Grid_Root"></div>
    <div id="Grid_Items" class="Grid_Root"></div>
    
    <!-- user pop-up template--> 
    <div id="GridPopUp_User">
            
       <input type="text" id="divDataUser_0" data-fieldname="FirstName" />
       <input type="text" id="divDataUser_1" data-fieldname="LastName" />
       <input type="text" id="divDataUser_2" data-fieldname="Email" />
       <input type="text" id="divDataUser_3" data-fieldname="Address1" />
       <input type="text" id="divDataUser_4" data-fieldname="Address2" />
       <input type="text" id="divDataUser_5" data-fieldname="PostalCode" />
       <input type="text" id="divDataUser_6" data-fieldname="City" />
       <select id="divDataUser_7" data-fieldname="Province"></select>
       <select id="divDataUser_8" data-fieldname="Country"></select>
       <select id="divDataUser_9" data-fieldname="Status" data-lookup="statusCodes"></select>
    
       <input type="hidden" data-fieldname="UserID" />
    
       <input type="button" id="btnSubmit_User" value="Submit" class="btnSubmit" />
    
    </div>
    
    <!-- Item pop-up template--> 
    <div id="GridPopUp_Item">
    
       <input type="text" id="divDataItem_0" data-fieldname="Name" />
       <textarea rows="5" cols="30" id="divDataItem_1" data-fieldname="Description"></textarea>
       <select id="divDataItem_2" data-fieldname="CountryOfOrigin" data-lookup="Countries">       </select>
       <input type="text" id="divDataItem_3" data-fieldname="Price" />
       <input type="text" id="divDataItem_4" data-fieldname="Weight" />
       <input type="text" id="divDataItem_5" data-fieldname="VendorName" />
    
       <input type="hidden" data-fieldname="ItemID" />
    
       <input type="button" id="btnSubmit_Item" value="Submit" class="btnSubmit" />
    
    </div>      

    我们来看看这两个模板:它们由一组表单元素组成,包含在一个div中。表单元素具有两个新的HTML5兼容属性:“data-fieldname”和“data-lookup”。

    data-fieldname属性用于将表单控件值映射到相应实体的数据字段。例如,GridPopUp_User模板的data-fieldname="FirstName"将自动链接到User实体的FirstName字段。映射、解析和表单处理由Index.cshml视图中包含的popUp函数执行。请确保正确输入字段名。它们必须与实体名以及最终的数据库记录名完全匹配。

    data-lookup属性由辅助jQuery插件populateSelect使用,用于从gridview.js文件中包含的dataArrays JSON对象填充下拉列表。例如,此行代码在页面加载时调用:

    $("[data-lookup]").populateSelect(null);   

    将使用dataArrays对象中的数据填充所有选定的下拉列表,匹配data-lookup属性中指定的数组名称:data-lookup="Countries"将导致插件尝试在dataArrays对象中查找JSON数组Countries,重置下拉列表并用来自Countries数组的数据填充它。

    dataArrays对象默认包含Countries和Provinces的数组,但可以动态扩展以根据需要添加新数组。例如,这行代码:

    dataArrays["allProvinces"] = $.extend({}, dataArrays.ProvincesCA, dataArrays.ProvincesAU,  dataArrays.StatesUS);    

    将合并ProvincesCA、ProvincesAU和StatesUS数组,并在dataArrays对象中创建一个名为allProvinces的新数组。

    现在我们来看Javascript代码以及不同的插件和Javascript对象。实际的GridView插件,此处描述的插件位于include gridview.js中。

     (function ($) {
        $.fn.addGridView = function (dataTable, jsonConfig, cssID, addNewCallBack) {
            try {
                /*public variables and methods*/
                var oGrid = this;
                oGrid.pageSize = 8;
                oGrid.pageIndex = 0;
                oGrid.dataTable = dataTable;
                oGrid.addButtonText = "Add New";
                oGrid.objName = "";
                oGrid.applyEffects = false;
     
                this.displayPage = function () { .... }
    .....
                this.onPagingClick = function (pageIX) { .... }
    ..... etc.
     
      

    GridView插件接受四个参数:

    • dataTable - 要显示JSON数据对象
    • jsonConfig - 可选的JSON配置对象,允许指定要显示的数据列以及它们的顺序,以及一些附加属性,更多内容如下。如果您想省略jsonConfig,则必须指定null。
    • cssID - 一个字符串,将用作前缀,用于指定将附加到GridView各个元素的CSS类。它允许为多个GridView实例重用CSS类。
    • addNewCallBack是一个可选参数。它应该是一个已存在的函数,或者如果您想省略它,则为null。如果您指定了它,插件将在GridView的右下角添加一个按钮,并将该按钮的单击事件链接到指定的函数。此函数应处理新实体的添加,并将接收一个指向GridView对象的引用作为参数。

    GridView插件有六个公共属性和两个公共方法:

    • pageSize - Grid中的数据行数
    • pageIndex - 当前显示的页码
    • dataTable - 指向传入的JSON数据对象的引用
    • addButtonText - 如果您指定了addNewCallBack参数,则允许自定义新增按钮的文本
    • objName - 要显示实体的名称。它用于标识正在处理的实体,如果存在添加、编辑、添加或删除功能。如果Grid仅用于显示,则可以省略。
    • applyEffects - 是一个布尔开关,默认为false。如果将其设置为true,则在页面刷新期间将执行一些滑动效果。
    • displayPage() - 刷新GridView显示。此方法在对象创建时不会被调用,您需要在插件初始化并设置pageSize和pageIndex后调用它。
    • onPageClick(pageIndex) - 刷新GridView显示的另一种可选方式。此方法也由导航单击事件调用。

    GridView插件通过获取jQuery选择器的根元素来工作,例如jQuery("#Grid_Items"),并将其HTML表格的元素添加为子元素。它会生成并填充一个表头行,该表头行要么包含JSON对象的字段名,要么使用提供的配置JSON对象。它使用JSON dataTable对象中的数据填充单元格元素,并根据所选页码生成导航链接集。该插件内部生成jQuery对象并使用它们来操作DOM。jQuery对象是由gridview.js中包含的辅助插件addNewElement生成的。

    可选的grid布局JSON对象允许自定义GridView列。

    var GridLayout_User = [
     { "DataField": "FirstName", "HeaderText": "First Name", "Width": 80 },
     { "DataField": "LastName", "HeaderText": "Last Name", "Width": 80 },
     { "DataField": "City", "HeaderText": "City", "Width": 80 },
     { "DataField": "Province", "HeaderText": "Province", "Width": 80, "LookUp": "allProvinces" },
     { "DataField": "Country", "HeaderText": "Country", "Width": 80, "LookUp": "Countries" },
     { "DataField": "Status", "HeaderText": "Status", "Width": 80, "LookUp": "statusCodes" },
     { "DataField": "DateJoined", "HeaderText": "Date Joined", "Width": 120 },
     { "StaticText": "Edit", "HeaderText": "", "Width": 60, "HyperLinkField": onLinkEditClick },
     { "StaticText": "Delete", "HeaderText": "", "Width": 60, "HyperLinkField": onLinkDeleteClick }
    ] 
    • "DataField": "FirstName", - 指定列的数据字段名,即数据对象中的字段名。字段名必须存在于JSON数据对象中。
    • "HeaderText": "First Name", - 出现在第一列的标题中
    • "Width": 100 - 列宽,请注意,这是一个数字而不是文本,如上一篇文章的配置对象中所述。
    • "HyperLinkField": onLinkEditClick - 可选字段。如果您希望将GridView列链接到回调函数,可以在此处指定。GridView将在此列中添加一个链接,该链接的单击事件将连接到指定的函数(onLinkEditClick),并且该函数将接收指向GridView对象和单击行索引作为参数。这些参数可用于查找数据记录或对GridView对象执行操作。
    • "StaticText":"Edit" - 将填充在该列中的静态文本
    • "LookUp" :"Countries" - 如果指定了此选项,GridView将尝试在gridview.js中包含的dataArrays对象中查找指定的数组("Countries"),并尝试用查找数组中的值替换显示的数据。例如,显示的数据将是“United States”而不是“US”。

    插件如何在页面中初始化和使用

    function getUsers() {
      try {
        $.getJSON("/CPArticle2/GetJsonUsers", null, function (data) {
          try {
            var dtUsers = eval(data);
            var oGrid_Users = 
            $("#Grid_Users").addGridView(dtUsers, GridLayout_User, "Grid_", onAddNewClick);
            oGrid_Users.pageIndex = 0;
            oGrid_Users.pageSize = 5;
            oGrid_Users.objName = "User";
            //oGrid_Users.applyEffects = true;
            oGrid_Users.displayPage();
            oGrid_Users.draggable({ stack: ".Grid_Root" });
          }
          catch (ex1) {
            alert(ex1);
          }
        });
      }
      catch (ex) {
        alert(ex);
      }
    }

    在此示例中,生成了两个GridView,它们使用了两个不同的JSON数组:Users和Items。

    var oGrid_Users = $("#Grid_Users").addGridView(dtUsers, GridLayout_User, "Grid_",          onAddNewClick);  

    $("#Grid_Users")是根元素的jQuery选择器。

    addGridView(dtUsers, GridLayout_User, "Grid_", onAddNewClick); 使用四个参数初始化插件。

    • dtUsers 是从控制器 "/CPArticle2/GetJsonUsers" 检索到的JSON数据对象。
    • GridLayout_User 是指定格式化选项的JSON数组。
    • "Grid_" 是用作前缀的字符串,用于将CSS类附加到GridView元素。
    • onAddNewClick 是用于添加新实体的函数。

    如果您想省略jsonConfig对象和新增功能,则必须指定null。

    var oGrid_Users = $("#Grid_Users").addGridView(dtUsers, null, "Grid_"); 

    oGrid 存储由插件返回的jQuery对象,可用于指定pageIndex、pageSize和其他选项,并通过displayPage()刷新GridView显示。

    oGrid.draggable({ stack: ".Grid_Root" }); 只是一个演示,说明插件如何被各种Widgets和库使用,例如jQuery UI库,使其在页面上可拖动。请注意,在此示例中,{stack: ".Grid_Root" }用于将当前正在拖动的GridView置于最前面。这意味着根元素必须附加CSS类.Grid_Root。

    GridView插件的外观自定义完全通过CSS类完成。

    /* Header Properties */
    .Grid_HeaderRow {
      border: 1px solid black;
      font-weight: bold; font-size: 15px; color: #FFFFFF;
      height: 35px; background-color: #777777;
    }
     
    .Grid_HeaderCell {
      border: 1px solid black; padding: 3px;
      text-overflow: ellipsis; overflow: hidden;
      white-space: nowrap; text-align: center;
    }
     
    /* Table Body Properties - Row and Cell elements*/
    .Grid_Row {
      height: 35px;
    }
     
    .Grid_Row:nth-child(odd) {
      background-color: #DDDDDD;
    }
     
    .Grid_Cell {
      border: 1px solid #777777; padding: 5px; text-align: center;
    }
     
    /* Footer Properties */
    .Grid_FooterRow {
      height: 40px;
    }
    ........ etc. 
    

    约定是使用参数cssID - 一个字符串,用作前缀,用于指定CSS类。

    如果您将"Grid_"作为cssID参数传递,则需要使用的类将是:

  • Grid_Table
  • Grid_HeaderRow
  • Grid_HeaderCell
  • Grid_Row 和 Grid_Row:nth-child(odd)
  • Grid_Cell
  • Grid_FooterRow
  • Grid_FooterCell
  • Grid_AddNew - 新增按钮的CSS
  • Grid_Paging - 导航包装器的CSS
  • Grid_NavigationLink
  • Grid_NavigationLink:hover
  • Grid_NavigationCurrentPage
  • Grid_CellLink
  • Grid_CellLink:hover
  • Grid_Error - 错误消息div的CSS
  • 现在我们来看编辑和添加功能。页面加载时,初始化了两个弹出对象:

    oPopUp_User = new popUp("GridPopUp_User");  //initialize pop-ups  
    oPopUp_Item = new popUp("GridPopUp_Item");  
    

    GridPopUp_User 和 GridPopUp_Item 是用于显示和填充User和Item实体数据的两个模板的包装div。popUp模板通过函数激活:

    $pop.Show = function (operationMode, dataRecord, callBack) {      ......  } 
    • callBack 是在点击模板的提交按钮时将被调用的函数。它将接收作为dataRecord参数传递的更新后的JSON数据对象,或者在操作模式为“Add”时,它将生成一个新的JSON对象并用模板中的数据填充它。
    • operationMode 指定模板是在编辑还是添加模式下使用。可能的值是“Add”或“Edit”。在添加模式下,提交时会创建一个新的JSON对象;在“Add”模式下,您必须为dataRecord参数指定null。
    • dataRecord 是将用于填充模板控件并以更新数据返回给callBack参数中指定的函数的JSON数据对象。

    在调用Show函数之前,必须指定模板的按钮ID,例如:

    window["oPopUp_" + callBackObject.objName].btnSubmitID = "btnSubmit_" +                     callBackObject.objName;  

    其中CallBackObject是传递给Edit或Add函数的GridView引用,objName是初始化GridView时传递的实体名,在此示例中是User或Item。

    有三个函数处理CRUD操作:

    function onAddNewClick(callBackObject)
    function onLinkEditClick(rowIX, callBackObject)
    function onLinkDeleteClick(rowIX, callBackObject)
    

    我将简要描述它们的工作原理:

     function onAddNewClick(callBackObject) {
      var $self = this;
      //Controller for adding a record
      $self.ajaxURL = "CPArticle2/AddNew" + callBackObject.objName;  
    
      this.onAjaxReturn = function (dataRecord) {
        //insert a row with the returned data record as a first record
        callBackObject.dataTable.unshift(dataRecord); 
        callBackObject.pageIndex = 0;
        callBackObject.displayPage();
        //close and reset the pop-up form fields
        window["oPopUp_" + callBackObject.objName].close();
      }
    
      this.onFormReturn = function (dataRecord) {
        //send form data to the server
        ajaxCall($self.ajaxURL, dataRecord, $self.onAjaxReturn); 
      }
    
      if (callBackObject.objName == "User") {
        //set the drop-down element ids for Country and province
        window["oPopUp_" + callBackObject.objName].countryElementID = "divDataUser_8";  
        window["oPopUp_" + callBackObject.objName].provinceElementID = "divDataUser_7";
      }
      
      window["oPopUp_" + callBackObject.objName].btnSubmitID = "btnSubmit_" +                       callBackObject.objName;
      window["oPopUp_" + callBackObject.objName].Show("Add", null, $self.onFormReturn);
    } 

    onAddNewClick(callBackObject) 由GridView在点击“Add New”按钮时调用。callBackObject是调用它的GridView对象的引用。该函数使用控制器名称:“CPArticle2/AddNew” + callBackObject.objName,这意味着您必须遵循“AddNew” + objName的约定来构建您的服务器端方法,例如,对于User实体:“CPArticle2/AddNewUser”。

    如果您指定了countryElementID和provinceElementID选项,popUp模板对象将使用这些ID的控件填充数据,数据来自gridview.js文件中包含的dataArrays对象。countryElementID下拉列表的onChange事件将根据国家选择自动刷新省份。

    回调函数.onFormReturn 在popUp提交时被调用,它将接收新的数据记录并将其发送给ajaxCall到服务器进行处理。ajaxCall将返回更新后的实体,特别是新创建实体的ID,返回给onAjaxReturn回调函数。新创建的实体将被插入到GridView dataTable数组的第一个记录中,并且将刷新以显示第一页。

    编辑或删除GridView行的其他两个方法工作方式类似:执行Ajax调用,然后GridView得到更新和刷新。

    关注点

    CRUD操作未链接到任何现有的框架,如Angular.js或Backbone.js。我曾尝试过使用两者来实现CRUD功能,对我来说,Angular.js似乎是更好的选择,所以将来我可能会用基于Angular.js的CRUD模板更新此内容。

    历史

    之前有一个纯Javascript对象的版本。但该插件似乎在技术上更优越。

    © . All rights reserved.