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






4.84/5 (6投票s)
用于 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格式将更新后的实体返回给客户端。在此示例应用程序中,没有为错误处理或服务器端数据检查做特殊规定。但在生产级别的应用程序中,应该添加这些。
现在我们来看客户端。我们先从包含文件开始:
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参数传递,则需要使用的类将是:
现在我们来看编辑和添加功能。页面加载时,初始化了两个弹出对象:
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对象的版本。但该插件似乎在技术上更优越。