Preface: The blogger has shared some basic usages of knockoutJS and BootstrapTable before. They are all basic applications, and they are not encapsulated at all. They just avoid the value and assignment of html controls, and are far from showing the exquisiteness of MVVM. Recently, the project plans to officially use ko, so it has made some packaging for ko and bootstraptable, and it is shared here for reference by park friends. For packaging ideas, please refer to the blog park master Xiao Qin. If the park friends have a better way, please feel free to discuss it.
KnockoutJS series articles:
BootstrapTable and KnockoutJS combine to achieve the function of adding, deleting, modifying and checking [1]
BootstrapTable and KnockoutJS combine to achieve the function of adding, deleting, modifying and checking [2]
1. The first viewmodel handles the query
The implementation of demo is still to continue the department management function of the last time. The following expansion explains by data flow.
1. The background returns the implementation of viewmodel to the View
public ActionResult Index(){var model = new{tableParams = new{url = "/Department/GetDepartment",//pageSize = 2,},urls = new{delete = "/Department/Delete",edit = "/Department/Edit",add = "/Department/Edit",},queryCondition = new{name = "",des = ""}};return View(model);}Code doubt: The model returned here contains three options
•tableParams: Page table initialization parameters. Since the default parameters are defined in js, the parameters set here are page-specific initialization parameters.
•urls: The URL path containing the request for addition, deletion and modification.
•queryCondition: The query conditions of the page.
2. cshtml page code
The Index.cshtml page code is as follows:
@{Layout = null;}<!DOCTYPE html><html><head><meta name="viewport" content="width=device-width" /><title>Index</title><link href="~/Content/bootstrap/css/bootstrap.min.css" rel="stylesheet" /><link href="~/Content/bootstrap-table/bootstrap-table.min.css" rel="stylesheet" /><script src="~/scripts/jquery-1.9.1.min.js"></script><script src="~/Content/bootstrap/js/bootstrap.min.js"></script><script src="~/Content/bootstrap-table/bootstrap-table.min.js"></script><script src="~/Content/bootstrap-table/locale/bootstrap-table-zh-CN.js"></script><script src="~/scripts/knockout/knockout-3.4.0.min.js"></script><script src="~/scripts/knockout/knockout-3.4.0.min.js"></script><script src="~/scripts/knockout/extensions/knockout.mapping-latest.js"></script><script src="~/scripts/extensions/knockout.index.js"></script><script src="~/scripts/extensions/knockout.bootstraptable.js"></script><script type="text/javascript">$(function(){var data = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model));ko.bindingViewModel(data, document.getElementById("div_index"));});</script></head><body><div id="div_index" style="padding:0px;overflow-x:hidden;"><div><div>Query conditions</div><div><form id="formSearch"><div><label>Department name</label><div><input type="text" data-bind="value:queryCondition.name"></div><label>Department description</label><div><input type="text" data-bind="value:queryCondition.des"></div><div style="text-align:right;"><button type="button"data-bind="click:clearClick">Clear</button><button type="button"data-bind="click:queryClick">Query</button></div></form></div></div><div id="toolbar"><button data-bind="click:addClick" type="button"><span aria-hidden="true"></span>Add</button><button data-bind="click:editClick" type="button"><span aria-hidden="true"></span>Modify</button><button data-bind="click:deleteClick" type="button"><span aria-hidden="true"></span>Delete</button></div><table data-bind="bootstrapTable:bootstrapTable"><tr><th data-checkbox="true"></th><th data-field="Name">Department name</th><th data-field="Level">Department level</th><th data-field="Des">Description</th><th data-field="strCreatetime">Creation time</th></tr></tead></table></div></body></html>Code doubt: Like the previous article, you need to quote JQuery, bootstrap, bootstraptable, knockout and other related files. Here are the following two documents:
•knockout.index.js: encapsulates the properties and event bindings related to the query page.
•knockout.bootstraptable.js: Encapsulates the initialization of bootstrapTable and customizes knockout binding methods.
All the above page interactions are encapsulated in public js, so there is no need to write a large number of duplicate codes such as DOM elements to obtain assignments, event binding, etc. on the page. There are only the above two sentences of js written on this page. Isn't it very easy?
3. JS encapsulation
Let’s take a look at the two js files mentioned above, knockout.bootstable.js and knockout.index.js.
(1) knockout.bootstraptable.js
(function ($) {//Add a bootstrapTableViewModel method to ko.bootstrapTableViewModel = function (options) {var that = this;this.default = {toolbar: '#toolbar', //Which container for the tool button queryParams: function (param) {return { limit: param.limit, offset: param.offset };},//Pagination parameters (*) pagination: true, //Does pagination display (*) sidePagination: "server", //Pagination method: client client pagination, server server pagination (*) pageNumber: 1, //Initialize the first page to load, the default first page pageSize: 10, //The number of rows recorded per page (*) pageList: [10, 25, 50, 100], //The number of rows per page to be selected (*) method: 'get',search: true, //Does the table search be displayed? This search is a client search and will not enter the server. Therefore, I personally feel that it is of little significance to strictSearch: true, showColumns: true, //Does all columns cache: false, showRefresh: true, //Does the refresh button minimumCountColumns: 2, //The minimum number of columns allowed clickToSelect: true, //Does the click to select rows be enabled showToggle: true,};this.params = $.extend({}, this.default, options || {});//Get the selected record this.getSelections = function () {var arrRes = that.bootstrapTable("getSelections")return arrRes;};//Refresh this.refresh = function () {that.bootstrapTable("refresh");};};//Add ko custom binding ko.bindingHandlers.bootstrapTable = {init: function (element, valueAccessor, allBindingsAccessor, viewModel) {//The oParam here is the bound viewmodelvar oViewModel = valueAccessor();var $ele = $(element).bootstrapTable(oViewModel.params);//Add a bootstrapTable method to the viewmodel oViewModel.bootstrapTable = function () {return $ele.bootstrapTable.apply($ele, arguments);}},update: function (element, valueAccessor, allBindingsAccessor, viewModel) {}};})(jQuery);Code doubt: The above code mainly does two things
1. Customized viewModel initialized by bootstrapTable.
2.
Add ko custom bindings.
If the park friends do not understand the use of custom binding, you can check out the blogger's first two blog posts (one) and (two) for detailed introduction.
(2) knockout.index.js
(function ($) {ko.bindingViewModel = function (data, bindElement) {var self = this;this.queryCondition = ko.mapping.fromJS(data.queryCondition);this.defaultQueryParams = {queryParams: function (param) {var params = self.queryCondition;params.limit = param.limit;params.offset = param.offset;return params;}};var tableParams = $.extend({}, this.defaultQueryParams, data.tableParams || {});this.bootstrapTable = new ko.bootstrapTableViewModel(tableParams);//Clear event this.clearClick = function () {$.each(self.queryCondition, function (key, value) {//Clear if (typeof (value) == "function") {this(''); //value('');}});self.bootstrapTable.refresh();};//Query event this.queryClick = function () {self.bootstrapTable.refresh();};//Add event this.addClick = function () {var dialog = $('<div id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"></div>');dialog.load(data.urls.edit, null, function () { });$("body").append(dialog);dialog.modal().on('hidden.bs.modal', function () {//Clear the binding when closing the pop-up box (this clear includes clearing the binding and clearing the registration event)ko.cleanNode(document.getElementById("formEdit"));dialog.remove();self.bootstrapTable.refresh();});};//Edit event this.editClick = function () {var arrrectedData = self.bootstrapTable.getSelections();if (arrrectedData.length <= 0 || arrrectedData.length > 1) {alert("Only edit one line at a time");return;}var dialog = $('<div id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"></div>');dialog.load(data.urls.edit, arrrectedData[0], function () { });$("body").append(dialog);dialog.modal().on('hidden.bs.modal', function () {//Clear the binding when closing the pop-up box (this clear includes clearing the binding and clearing the registration event)ko.cleanNode(document.getElementById("formEdit"));dialog.remove();self.bootstrapTable.refresh();});};//Delete event this.deleteClick = function () {var arrrectedData = self.bootstrapTable.getSelections();if (!arrrectedData||arrrectedData.length<=0) {alert("Please select at least one line");return;}$.ajax({url: data.urls.delete,type: "post",contentType: 'application/json',data: JSON.stringify(arrrectedData),success: function (data, status) {alert(status);self.bootstrapTable.refresh();}});};ko.applyBindings(self, bindElement);};})(jQuery);Code doubt: This js mainly encapsulates the attributes and event binding of page elements, and several places that need to be explained
•this.queryCondition = ko.mapping.fromJS(data.queryCondition): The purpose of this sentence is to convert the query conditions passed from the background from JSON data to monitoring attributes. Only by executing this sentence can attributes and page elements be monitored in both directions.
•self.bootstrapTable.refresh(): The meaning of this sentence is to refresh the table data. It is actually the refresh method of bootstrapTable that is called, but the blogger simply encapsulates it in the knockout.bootstraptable.js file.
•dialog.load(data.urls.edit, null, function () { }): When adding and editing, the load() method of jQuery is used. The function of this method is to request the page elements of this url and execute the js code of the corresponding page of the url. This method is very powerful in dynamically referring to the js file and executing the code inside the js file.
Finally, attach the code corresponding to the background GetDepartment() method
[HttpGet]public JsonResult GetDepartment(int limit, int offset, string name, string des){var lstRes = DepartmentModel.GetData();if (!string.IsNullOrEmpty(name)){lstRes = lstRes.Where(x => x.Name.Contains(name)).ToList();}if (!string.IsNullOrEmpty(des)){lstRes = lstRes.Where(x => x.Des.Contains(des)).ToList();}lstRes.ForEach(x=> {x.strCreatetime = x.Createtime.ToString("yyyy-MM-dd HH:mm:ss");});var oRes = new{rows = lstRes.Skip(offset).Take(limit).ToList(),total = lstRes.Count};return Json(oRes, JsonRequestBehavior.AllowGet);}At this point, the query and clearing functions of the query page can be realized.
Do you still have a question: What if we need to customize the events of bootstrapTable? Can't be transmitted through the viewmodel in the background, right?
Indeed, the js event method cannot be passed from the background, so we need to customize the processing method of the event in the front end, for example, we can do this:
<script type="text/javascript">$(function(){var data = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model));data.tableParams.onLoadSuccess = function(data){ alert("LoadSuccess Event"); };ko.bindingViewModel(data, document.getElementById("div_index"));});</script>2. Get the second viewmodel edit
One of the viewmodels above handles the query and deletion functions, but adding and editing also requires the support of another viewmodel. Let’s take a look at the package implementation of editing.
1. Implementation of ActionResult
Through the code query above, we can know that when the user clicks on Add and Edit, another View view will be requested →/Department/Edit. Let's take a look at the implementation of Edit view
public ActionResult Edit(Department model){var oResModel = new{editModel = model,urls = new{submit = model.id == 0 ? "/Department/Add" : "/Department/Update"}};return View(oResModel);}Code doubt: The above code is very simple, which is to return a viewmodel to the view page, containing the edited entity and the submitted url. Whether this entity primary key exists is determined by whether the current commit is a new entity or an edit entity.
2. cshtml code
Edit.cshtml code is as follows:
<form id="formEdit"><div role="document"><div><div><button type="button" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button><h4 id="myModalLabel">Operation</h4></div><div><div><label for="txt_departmentname">Department name</label><input type="text" name="txt_departmentname" data-bind="value:editModel.Name" placeholder="Department Name"></div><div><label for="txt_departmentlevel">Department Level</label><input type="text" name="txt_departmentlevel" data-bind="value:editModel.Level" placeholder="Department Level"></div><div><label for="txt_des">Description</label><input type="text" name="txt_des" data-bind="value:editModel.Des" placeholder="Descriptive"></div><div><button type="button" data-dismiss="modal"><span aria-hidden="true"></span>Close</button><button type="submit"><span aria-hidden="true"></span>Save</button></div></div></form><link href="~/Content/bootstrapValidator/css/bootstrapValidator.css" rel="stylesheet" /><script src="~/Content/bootstrapValidator/js/bootstrapValidator.js"></script><script src="~/scripts/extensions/knockout.edit.js"></script><script type="text/javascript">$(function () { var editData = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model));ko.bindingEditViewModel(editData, {}); });</script>Code doubt: Since we have added the verification component bootstrapValidator, we need to reference the relevant js and css. This file knockout.edit.js mainly encapsulates the properties and event binding of the edit page. Let’s take a look at the implementation code of this js.
3. JS encapsulation
knockout.edit.js code:
(function ($) {ko.bindingEditViewModel = function (data, validatorFields) {var that = {}; that.editModel = ko.mapping.fromJS(data.editModel); that.default = {message: 'Verification failed',fields: { },submitHandler: function (validator, form, submitButton) {var arrrectedData = ko.toJS(that.editModel);$.ajax({url: data.urls.submit,type: "post",contentType: 'application/json',data: JSON.stringify(arrrectedData),success: function (data, status) {alert(status);}});$("#myModal").modal("hide");}}; that.params = $.extend({}, that.default, {fields: validatorFields} || {});$('#formEdit').bootstrapValidator(that.params);ko.applyBindings(that, document.getElementById("formEdit"));};})(jQuery);Code doubt: This js mainly encapsulates the properties of the edit model and the submitted event binding. Since the bootstrapValidator verification component is used, form submission is required. In fact, page id should not appear in public js, such as "formEdit" and "myModal" above. This can be passed as a parameter, which needs to be optimized. The parameter validatorFields represents the verification field of the verification component. If the form does not require verification, it is OK to pass an empty Json or not. We did not do field verification in the above article. In fact, generally speaking, the basic table will have one or several non-empty fields, such as non-empty verification of department names. The code on the Edit.cshtml page is changed to this:
<form id="formEdit"><div role="document"><div><div><button type="button" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button><h4 id="myModalLabel">Operation</h4></div><div><label for="txt_departmentname">Department name</label><input type="text" name="Name" data-bind="value:editModel.Name" placeholder="department name"></div><div><label for="txt_departmentlevel">Departmentlevel</label><input type="text" name="Level" data-bind="value:editModel.Level" placeholder="Departmentlevel"></div><div><label for="txt_des">Description</label><input type="text" name="Des" data-bind="value:editModel.Des" placeholder="Des"></div><div><button type="button" data-dismiss="modal"><span aria-hidden="true"></span>Close</button><button type="submit"><span aria-hidden="true"></span>Save</button></div></div></form><link href="~/Content/bootstrapValidator/css/bootstrapValidator.css" rel="stylesheet" /><script src="~/Content/bootstrapValidator/js/bootstrapValidator.js"></script><script src="~/scripts/extensions/knockout.edit.js"></script><script type="text/javascript">$(function () { var editData = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model));ko.bindingEditViewModel(editData, {Name: {validators: {notEmpty: {message: 'The name cannot be empty!'}}}}); });</script>Then it will be automatically verified when submitting:
Note: The verification attribute Name corresponds to the name attribute of the input tag, so to do verification, this name attribute must be set correctly.
It is best to attach a background method for adding, deleting and modifying:
[HttpPost]public JsonResult Add(Department oData){DepartmentModel.Add(oData);return Json(new { }, JsonRequestBehavior.AllowGet);}[HttpPost]public JsonResult Update(Department oData){DepartmentModel.Update(oData);return Json(new { }, JsonRequestBehavior.AllowGet);}[HttpPost]public JsonResult Delete(List<Department> oData){DepartmentModel.Delete(oData); return Json(new { }, JsonRequestBehavior.AllowGet);}At this point, the effect of adding, deleting, modifying and checking of the entire page is OK. Let’s take a look at the effect briefly:
3. Summary
The above simply encapsulates the addition, deletion, modification and search service of bootstrapTable+ko, which is just a primary package. If you need to apply these to your project, you may also need some simple optimization measures, such as:
1. If it is simply a viewmodel of a page, can it be better to write it directly into the View page without returning it from the ActionResult in the background, and it saves the problem of serialization and parameter passing. This needs to be optimized.
2. The id of the page element should not appear in public js. The page element can be passed in through parameters.
3. Add and edit event methods to have a lot of duplicate code in the pop-up box. The best way to do this part is to encapsulate the pop-up box into a separate component to call it, which can reduce most of the js code.
4. If there are select drop-down box elements in the query conditions and edited properties, you may also need to encapsulate the datasource and other attributes of the drop-down box. This part is very common. After the blogger has sorted out the demo, add this piece.
The above is the solution to the BootstrapTable + KnockoutJS introduced by the editor to achieve the addition, deletion, modification and search (3) The two Viewmodels have completed the addition, deletion, modification and search. I hope it will be helpful to everyone. If you have any questions, please leave me a message and the editor will reply to everyone in time. Thank you very much for your support to Wulin.com website!