Home Web Front-end JS Tutorial Detailed example of combining Bootstrap and KnockoutJs to achieve paging effect_javascript skills

Detailed example of combining Bootstrap and KnockoutJs to achieve paging effect_javascript skills

May 16, 2016 pm 03:02 PM

KnockoutJS is an MVVM framework implemented in JavaScript. Very cool. For example, after the list data items are added or deleted, there is no need to refresh the entire control fragment or write JS to add or delete nodes by yourself. You only need to pre-define the template and attributes that conform to its syntax definition. Simply put, we only need to focus on data access.

1. Introduction

Since the company’s system needs to be revised recently, I plan to use KnockoutJs to make the web front-end for the new system. In the process of doing it, I encountered a problem - how to use KnockoutJs to complete the paging function. In the previous article, we did not introduce the use of KnockoutJs to implement paging, so in this article, we will supplement the use of KnockoutJs+Bootstrap to implement paging display of data.

2. Use KnockoutJs to implement paging

There are two ways to implement paging. The first is to load all the data, and then display all the data in pages; the second is to only load part of the data each time, and reload the following for each request. data.

For these two methods, paging implemented using the Razor method generally uses the second method to implement paging. However, for single-page programs, the first implementation method also has its benefits. It is completely suitable for not very large amounts of data. The first implementation method can be used, because in this case, the user experience of subsequent data loading will be very smooth. So these two implementation methods will be introduced here.

2.1 Implementation of loading partial data each time

The backend code here uses the code from the previous article, with just some additional sample data added. The specific backend implementation code is:

/// <summary>
 /// Web API 服务,为Web前端提供数据服务
 /// </summary>
 public class TaskController : ApiController
 {
  private readonly TaskRepository _taskRepository = TaskRepository.Current;
  public IEnumerable<Task> GetAll()
  {
   return _taskRepository.GetAll().OrderBy(a => a.Id);
  }
  [Route("api/task/GetByPaged")]
  public PagedModel GetAll([FromUri]int pageIndex)
  {
   const int pageSize = 3;
   int totalCount;
   var tasks = _taskRepository.GetAll(pageIndex, pageSize, out totalCount).OrderBy(a => a.Id);
   var pageData = new PagedModel()
   {
    PageIndex = pageIndex,
    PagedData = tasks.ToList(),
    TotalCount = totalCount,
    PageCount = (totalCount+ pageSize -1) / pageSize
   };
   //返回数据
   return pageData;
  }
 }
/// <summary>
 /// 任务仓储,封装了所有关于数据库的操作
 /// </summary>
 public class TaskRepository
 {
  #region Static Filed
  private static Lazy<TaskRepository> _taskRepository = new Lazy<TaskRepository>(() => new TaskRepository());
  public static TaskRepository Current
  {
   get { return _taskRepository.Value; }
  }
  #endregion
  #region Fields
  private readonly List<Task> _tasks = new List<Task>()
  {
   new Task
   {
    Id =1,
    Name = "创建一个SPA程序",
    Description = "SPA(single page web application),SPA的优势就是少量带宽,平滑体验",
    Owner = "Learning hard",
    FinishTime = DateTime.Parse(DateTime.Now.AddDays(1).ToString(CultureInfo.InvariantCulture))
   },
   new Task
   {
    Id =2,
    Name = "学习KnockoutJs",
    Description = "KnockoutJs是一个MVVM类库,支持双向绑定",
    Owner = "Tommy Li",
    FinishTime = DateTime.Parse(DateTime.Now.AddDays(2).ToString(CultureInfo.InvariantCulture))
   },
   new Task
   {
    Id =3,
    Name = "学习AngularJS",
    Description = "AngularJs是MVVM框架,集MVVM和MVC与一体。",
    Owner = "李志",
    FinishTime = DateTime.Parse(DateTime.Now.AddDays(3).ToString(CultureInfo.InvariantCulture))
   },
   new Task
   {
    Id =4,
    Name = "学习ASP.NET MVC网站",
    Description = "Glimpse是一款.NET下的性能测试工具,支持asp.net 、asp.net mvc, EF等等,优势在于,不需要修改原项目任何代码,且能输出代码执行各个环节的执行时间",
    Owner = "Tonny Li",
    FinishTime = DateTime.Parse(DateTime.Now.AddDays(4).ToString(CultureInfo.InvariantCulture))
   },
   new Task
   {
    Id =5,
    Name = "测试任务1",
    Description = "测试任务1",
    Owner = "李志",
    FinishTime = DateTime.Parse(DateTime.Now.AddDays(5).ToString(CultureInfo.InvariantCulture))
   },
   new Task
   {
    Id =6,
    Name = "测试任务2",
    Description = "测试任务2",
    Owner = "李志",
    FinishTime = DateTime.Parse(DateTime.Now.AddDays(6).ToString(CultureInfo.InvariantCulture))
   },
   new Task
   {
    Id =7,
    Name = "测试任务3",
    Description = "测试任务3",
    Owner = "李志",
    FinishTime = DateTime.Parse(DateTime.Now.AddDays(7).ToString(CultureInfo.InvariantCulture))
   },
  };
  #endregion
  #region Public Methods
  public IEnumerable<Task> GetAll()
  {
   return _tasks;
  }
  public IEnumerable<Task> GetAll(int pageNumber, int pageSize, out int totalCount)
  {
   var skip = (pageNumber - 1) * pageSize;
   var take = pageSize;
   totalCount = _tasks.Count;
   return _tasks.Skip(skip).Take(take);
  }
  public Task Get(int id)
  {
   return _tasks.Find(p => p.Id == id);
  }
  public Task Add(Task item)
  {
   if (item == null)
   {
    throw new ArgumentNullException("item");
   }
   item.Id = _tasks.Count + 1;
   _tasks.Add(item);
   return item;
  }
  public void Remove(int id)
  {
   _tasks.RemoveAll(p => p.Id == id);
  }
  public bool Update(Task item)
  {
   if (item == null)
   {
    throw new ArgumentNullException("item");
   }
   var taskItem = Get(item.Id);
   if (taskItem == null)
   {
    return false;
   }
   _tasks.Remove(taskItem);
   _tasks.Add(item);
   return true;
  }
  #endregion
 }
Copy after login

Web front-end implementation code:

@{
ViewBag.Title = "Index2";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div id="list2">
<h2>分页第二种实现方式——任务列表</h2>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>编号</th>
<th>名称</th>
<th>描述</th>
<th>负责人</th>
<th>创建时间</th>
<th>完成时间</th>
<th>状态</th>
</tr>
</thead>
<tbody data-bind="foreach:pagedList">
<tr>
<td data-bind="text: id"></td>
<td><a data-bind="text: name"></a></td>
<td data-bind="text: description"></td>
<td data-bind="text: owner"></td>
<td data-bind="text: creationTime"></td>
<td data-bind="text: finishTime"></td>
<td data-bind="text: state"></td>
</tr>
</tbody>
<tbody data-bind="if: loadingState">
<tr>
<td colspan="8" class="text-center">
<img width="60" src="/images/loading.gif" />
</td>
</tr>
</tbody>
<tfoot data-bind="ifnot:loadingState">
<tr>
<td colspan="8">
<div class="pull-right">
<div>总共有<span data-bind="text: totalCount"></span>条记录, 每页显示:<span data-bind="text: pageSize"></span>条</div>
<div>
<ul class="pagination">
<li data-bind="css: { disabled: pageIndex() === 1 }"><a href="#" data-bind="click: previous">&laquo;</a></li>
</ul>
<ul data-bind="foreach: allPages" class="pagination">
<li data-bind="css: { active: $data.pageNumber === ($root.pageIndex()) }"><a href="#" data-bind="text: $data.pageNumber, click: function() { $root.gotoPage($data.pageNumber); }"></a></li>
</ul>
<ul class="pagination"><li data-bind="css: { disabled: pageIndex() === pageCount }"><a href="#" data-bind="click: next">&raquo;</a></li></ul>
</div>
</div>
</td>
</tr>
</tfoot>
</table>
</div>
</div> 
Copy after login

The corresponding Js implementation is:

// 实现分页的第二种方式
var ListViewModel2 = function() {
//viewModel本身。用来防止直接使用this的时候作用域混乱
var self = this;
self.loadingState = ko.observable(true);
self.pageSize = ko.observable(3);
//数据
this.pagedList = ko.observableArray();
//要访问的页码
this.pageIndex = ko.observable(1);
//总页数
this.pageCount = ko.observable(1);
//页码数
this.allPages = ko.observableArray();
//当前页
this.currengePage = ko.observable(1);
self.totalCount = ko.observable(1);
this.refresh = function() {
//限制请求页码在该数据页码范围内
if (self.pageIndex() < 1)
self.pageIndex(1);
if (self.pageIndex() > self.pageCount()) {
self.pageIndex(self.pageCount());
}
//post异步加载数据
sendAjaxRequest("GET", function (data) {
// 加载新的数据前,先移除原先的数据
self.pagedList.removeAll();
self.allPages.removeAll();
self.totalCount(data.totalCount);
self.pageCount(data.pageCount);
self.loadingState(false);
for (var i = 1; i <= data.pageCount; i++) {
//装填页码
self.allPages.push({ pageNumber: i });
}
//for...in 语句用于对数组或者对象的属性进行循环操作。
//for ... in 循环中的代码每执行一次,就会对数组的元素或者对象的属性进行一次操作。
for (var i in data.pagedData) {
//装填数据
self.pagedList.push(data.pagedData[i]);
}
}, 'GetByPaged', { 'pageIndex': self.pageIndex() });
};
//请求第一页数据
this.first = function() {
self.pageIndex(1);
self.refresh();
};
//请求下一页数据
this.next = function() {
self.pageIndex(this.pageIndex() + 1);
self.refresh();
};
//请求先前一页数据
this.previous = function() {
self.pageIndex(this.pageIndex() - 1);
self.refresh();
};
//请求最后一页数据
this.last = function() {
self.pageIndex(this.pageCount() - 1);
self.refresh();
};
//跳转到某页
this.gotoPage = function (data, event) {
self.pageIndex(data);
self.refresh();
};
};
function sendAjaxRequest(httpMethod, callback, url, reqData) {
$.ajax("/api/task" + (url &#63; "/" + url : ""), {
type: httpMethod,
success: callback,
data: reqData
});
}
$(document).ready(function () {
var viewModel = new ListViewModel2();
viewModel.refresh();
if ($('#list2').length)
ko.applyBindings(viewModel, $('#list2').get(0));
}); 
Copy after login

Here is an introduction to the implementation idea of ​​using KnockoutJs to implement the paging function:

1. After the page is loaded, initiate an Ajax request to asynchronously call the REST service to request some data.

2. Then display the requested data through KnockoutJs binding.

3. Bind the corresponding paging information to Bootstrap paging

4. When the user clicks to turn the page, initiate an Ajax request to asynchronously call the Rest service to request data, and then display the requested data.

The above is the calling logic relationship of the code described above. You can refer to the corresponding JS code to understand the above description. At this point our second implementation method is completed.

2.2 Load all data for the first time, and then display all data in pages

Next, we introduce the first implementation method. With this implementation method, the user will only feel that the data is loading for the first time, and will not feel that the page is loading during the page turning process. In this way, for some When the data itself is not too much, the user experience is smoother.

The specific implementation idea is not to display all the requested data on the page, because there is too much data and the user may be dazzled if it is displayed on the page all at once. Displaying the data in pages will make it clearer for users.

The specific implementation code of Web front-end Js is:

var ListViewModel = function () {
var self = this;
window.viewModel = self;
self.list = ko.observableArray();
self.pageSize = ko.observable(3); 
self.pageIndex = ko.observable(0); //要访问的页码
self.totalCount = ko.observable(1); //总记录数
self.loadingState = ko.observable(true);
self.pagedList = ko.dependentObservable(function () {
var size = self.pageSize();
var start = self.pageIndex() * size;
return self.list.slice(start, start + size);
});
self.maxPageIndex = ko.dependentObservable(function () {
return Math.ceil(self.list().length / self.pageSize()) - 1;
});
self.previousPage = function () {
if (self.pageIndex() > 0) {
self.pageIndex(self.pageIndex() - 1);
}
};
self.nextPage = function () {
if (self.pageIndex() < self.maxPageIndex()) {
self.pageIndex(self.pageIndex() + 1);
}
};
self.allPages = ko.dependentObservable(function () {
var pages = [];
for (var i = 0; i <= self.maxPageIndex() ; i++) {
pages.push({ pageNumber: (i + 1) });
}
return pages;
});
self.moveToPage = function (index) {
self.pageIndex(index);
};
};
var listViewModel = new ListViewModel();
function bindViewModel() {
sendAjaxRequest("GET", function (data) {
listViewModel.loadingState(false);
listViewModel.list(data);
listViewModel.totalCount(data.length);
if ($('#list').length)
ko.applyBindings(listViewModel, $('#list').get(0));
}, null, null);
}
$(document).ready(function () {
bindViewModel();
}); 
Copy after login

The implementation of its front-end page is similar to the previous implementation. The specific page code is as follows:

@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div id="list">
<h2>任务列表</h2>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>编号</th>
<th>名称</th>
<th>描述</th>
<th>负责人</th>
<th>创建时间</th>
<th>完成时间</th>
<th>状态</th>
</tr>
</thead>
<tbody data-bind="foreach:pagedList">
<tr>
<td data-bind="text: id"></td>
<td><a data-bind="text: name"></a></td>
<td data-bind="text: description"></td>
<td data-bind="text: owner"></td>
<td data-bind="text: creationTime"></td>
<td data-bind="text: finishTime"></td>
<td data-bind="text: state"></td>
</tr>
</tbody>
<tbody data-bind="if:loadingState">
<tr>
<td colspan="8" class="text-center">
<img width="60" src="/images/loading.gif" />
</td>
</tr>
</tbody>
<tfoot data-bind="ifnot:loadingState">
<tr>
<td colspan="8">
<div class="pull-right">
<div>总共有<span data-bind="text: totalCount"></span>条记录, 每页显示:<span data-bind="text: pageSize"></span>条</div>
<div>
<ul class="pagination">
<li data-bind="css: { disabled: pageIndex() === 0 }"><a href="#" data-bind="click: previousPage">&laquo;</a></li>
</ul>
<ul data-bind="foreach: allPages" class="pagination">
<li data-bind="css: { active: $data.pageNumber === ($root.pageIndex() + 1) }"><a href="#" data-bind="text: $data.pageNumber, click: function() { $root.moveToPage($data.pageNumber-1); }"></a></li>
</ul>
<ul class="pagination"><li data-bind="css: { disabled: pageIndex() === maxPageIndex() }"><a href="#" data-bind="click: nextPage">&raquo;</a></li></ul>
</div>
</div>
</td>
</tr>
</tfoot>
</table>
</div>
</div> 
Copy after login

3. Operation effect

Next, let’s take a look at the paging effect achieved using KnockoutJs:

4. Summary

At this point, the content to be introduced in this article ends. Although the content implemented in this article is relatively simple, for some friends who are new to KnockoutJs, I believe the implementation of this article will be a lot of guidance. Next, I will share with you the relevant content of AngularJs.

The above is the detailed explanation of the example of combining Bootstrap and KnockoutJs to achieve the paging effect introduced by the editor. I hope it will be helpful to everyone!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

What should I do if I encounter garbled code printing for front-end thermal paper receipts? What should I do if I encounter garbled code printing for front-end thermal paper receipts? Apr 04, 2025 pm 02:42 PM

Frequently Asked Questions and Solutions for Front-end Thermal Paper Ticket Printing In Front-end Development, Ticket Printing is a common requirement. However, many developers are implementing...

Who gets paid more Python or JavaScript? Who gets paid more Python or JavaScript? Apr 04, 2025 am 12:09 AM

There is no absolute salary for Python and JavaScript developers, depending on skills and industry needs. 1. Python may be paid more in data science and machine learning. 2. JavaScript has great demand in front-end and full-stack development, and its salary is also considerable. 3. Influencing factors include experience, geographical location, company size and specific skills.

How to merge array elements with the same ID into one object using JavaScript? How to merge array elements with the same ID into one object using JavaScript? Apr 04, 2025 pm 05:09 PM

How to merge array elements with the same ID into one object in JavaScript? When processing data, we often encounter the need to have the same ID...

Demystifying JavaScript: What It Does and Why It Matters Demystifying JavaScript: What It Does and Why It Matters Apr 09, 2025 am 12:07 AM

JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.

The difference in console.log output result: Why are the two calls different? The difference in console.log output result: Why are the two calls different? Apr 04, 2025 pm 05:12 PM

In-depth discussion of the root causes of the difference in console.log output. This article will analyze the differences in the output results of console.log function in a piece of code and explain the reasons behind it. �...

How to achieve parallax scrolling and element animation effects, like Shiseido's official website?
or:
How can we achieve the animation effect accompanied by page scrolling like Shiseido's official website? How to achieve parallax scrolling and element animation effects, like Shiseido's official website? or: How can we achieve the animation effect accompanied by page scrolling like Shiseido's official website? Apr 04, 2025 pm 05:36 PM

Discussion on the realization of parallax scrolling and element animation effects in this article will explore how to achieve similar to Shiseido official website (https://www.shiseido.co.jp/sb/wonderland/)...

TypeScript for Beginners, Part 2: Basic Data Types TypeScript for Beginners, Part 2: Basic Data Types Mar 19, 2025 am 09:10 AM

Once you have mastered the entry-level TypeScript tutorial, you should be able to write your own code in an IDE that supports TypeScript and compile it into JavaScript. This tutorial will dive into various data types in TypeScript. JavaScript has seven data types: Null, Undefined, Boolean, Number, String, Symbol (introduced by ES6) and Object. TypeScript defines more types on this basis, and this tutorial will cover all of them in detail. Null data type Like JavaScript, null in TypeScript

Can PowerPoint run JavaScript? Can PowerPoint run JavaScript? Apr 01, 2025 pm 05:17 PM

JavaScript can be run in PowerPoint, and can be implemented by calling external JavaScript files or embedding HTML files through VBA. 1. To use VBA to call JavaScript files, you need to enable macros and have VBA programming knowledge. 2. Embed HTML files containing JavaScript, which are simple and easy to use but are subject to security restrictions. Advantages include extended functions and flexibility, while disadvantages involve security, compatibility and complexity. In practice, attention should be paid to security, compatibility, performance and user experience.

See all articles