JSFiddle - React, Tailwind, and code Playground

by Francesco Frustaci

HTML

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<!-- This is the template needed for the view model but you can style it as necessary 
Its bootstrap right now.-->
<script type="text/html" id="PaginationTemplate">
  <nav class="text-center" aria-label="Page navigation">
    <ul class="pagination" style="cursor:pointer">
      <li data-bind="css:{disabled: Page() <= 1} ">
        <a aria-label="Previous" data-bind="click: ChangePageTo('first')">
          <span aria-hidden="true">&laquo;</span>
        </a>
      </li>
      <li>
        <a data-bind="text: Page() -2, click: ChangePageBy(-2), visible: Page() > 2 "> </a>
      </li>
      <li>
        <a data-bind="text: Page() -1, click: ChangePageBy(-1), visible: Page() > 1 "> </a>
      </li>
      <li class="active">
        <a data-bind="text: Page() "> </a>
      </li>
      <li>
        <a data-bind="text: Page() +1, click: ChangePageBy(1), visible: (PageTotal() > Page() +0)"></a>
      </li>
      <li>
        <a data-bind="text: Page() +2, click: ChangePageBy(2), visible: (PageTotal() > Page() +1)"></a>
      </li>

      <li data-bind="css: {disabled: (PageTotal() < Page() +1)}">
        <a aria-label="Next" data-bind="click: ChangePageTo('last')">
          <span aria-hidden="true">&raquo;</span>
        </a>
      </li>
    </ul>
  </nav>
</script>


<!-- This is what it looks like without pagination.
<div data-bind="foreach: ListOfStuff">
  <span data-bind="text: $data"> </span><br>
</div>-->
<select data-bind="value: Pagination().PerPage">
                                <option value="10">10</option>
                                <option value="25">25</option>
                                <option value="50">50</option>
                                <option value="100">100</option>
                            </select>
<div data-bind="foreach: Pagination().PaginatedArray">
  <span data-bind="text: $data"></span><br>
</div>
<div...

JavaScript

function MainViewModel() {
  var self = this;

  self.ListOfStuff = ko.observableArray();

  self.Pagination = ko.observable(new PaginationVM(self.ListOfStuff));

  self.PopulateArray = function() {
    for (var i = 0; i < 100; i++) {
      self.ListOfStuff.push("Item " + i);
    }
  }
  self.PopulateArray();
}


function PaginationVM(input) {
  var self = this;
  self.InputArray = input;
  self.PerPage = ko.observable();
  self.Page = ko.observable(1);

  self.PageTotal = ko.computed(function() {
    var totalPages = Math.ceil(self.InputArray().length / parseInt(self.PerPage()));
    if (self.Page() > totalPages && totalPages > 0) {
      self.Page(totalPages);
    }
    return totalPages
  })

  self.PaginatedArray = ko.computed(function() {
    var perPage = parseInt(self.PerPage())
    var start = self.Page() * perPage - perPage;
    return self.InputArray().slice(start, start + perPage);
  })

  self.ChangePageBy = function(offset) {
    return function() {
      self.Page(self.Page() + offset);
    }
  }

  self.ChangePageTo = function(newPage) {
    return function() {
      switch (newPage) {
        case "last":
          self.Page(self.PageTotal());
          break;
        case "first":
          self.Page(1);
          break;
        default:
          self.Page(newPage);
      }
    }
  }
}


ko.applyBindings(new MainViewModel());