Search code examples
javascriptknockout.jsknockout-3.0

Knockout paging binding


Sorry if this is a really basic question but I'm in the process of learning Knockout and trying to wire up paging to my dataset.

In my code below, you will see that I am retrieving the dataset, and the page size dropdown affects the results appropriately.
And when I change the page number (#'d links in footer of table), nothing happens.
Could someone tell me what I'm missing?

function ViewModel(){
    var vm = this;

    // variables
    vm.drinks = ko.observableArray();
    vm.pageSizes = [15,25,35,50];
    vm.pageSize = ko.observable(pageSizes[0]);
    vm.currentPage = ko.observable(0);

    // computed variables
    // returns number of pages required for number of results selected
    vm.PageCount = ko.computed(function(){
        if(vm.pageSize()){
            return Math.ceil(vm.drinks().length / vm.pageSize());
        }else{
            return 1;
        }
    });

    // returns items from the array for the current page
    vm.PagedResults = ko.computed(function(){
        //return vm.drinks().slice(vm.currentPage, vm.pageSize());
        return vm.drinks().slice(vm.currentPage() * vm.pageSize(), (vm.currentPage() * vm.pageSize()) + vm.pageSize());
    });

    // returns a list of numbers for all pages
    vm.PageList = ko.computed(function(){
        if(vm.PageCount() > 1){
            return Array.apply(null, {length: vm.PageCount()}).map(Number.call, Number);
        }
    });

    // methods
    vm.ResetCurrentPage = function(){
        vm.currentPage(0);
    }

    // go to page number
    vm.GoToPage = function(page){
        vm.currentPage(page);
    }

    // populate drink list
    vm.GetDrinks = function(){
        // get data
        $(function () {
            $.ajax({
                type: "GET",
                url: 'https://mysafeinfo.com/api/data?list=alcoholicbeverages&format=json',
                dataType: "json",
                success: function (data) {
                    vm.drinks(data);
                }
            });
        });
    }

    // populate drinks
    vm.GetDrinks();
}

// apply bindings
ko.applyBindings(ViewModel);
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<div class="row">
    <div class="col-sm-3 pull-right form-horizontal">
        <label class="control-label col-sm-4">
            Results:
        </label>
        <div class="col-sm-8">
            <select data-bind="value: pageSize,
              optionsCaption: 'Page Size',
              options: pageSizes, event:{ change: ResetCurrentPage }"
                    class="form-control"></select>
        </div>
    </div>
</div>

<table class="table table-striped table-condensed">
    <thead>
        <tr>
            <th style="width: 25%">Name</th>
            <th>Category</th>
            <th style="width: 50%">Description</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: PagedResults">
        <tr>
            <td data-bind="text: nm"></td>
            <td data-bind="text: cat"></td>
            <td data-bind="text: dsc"></td>
        </tr>
    </tbody>
    <tfooter>
        <tr>
            <td colspan="3">
                Current Page: <label data-bind="text: currentPage"></label><br />
                <ul data-bind="foreach: PageList" class="pagination">
                    <li class="page-item"><a class="page-link" href="#" data-bind="text: $data + 1, click: GoToPage">1</a></li>
                </ul>
            </td>
        </tr>
    </tfooter>
</table>


Solution

  • Thanks to f_martinez for helping with my issue, here is the working example if anyone ends up here looking for how to do paging. jsfiddle

    I will keep this open for now in case f_martinez would like to post an answer to accept.

    function ViewModel() {
      var vm = this;
    
      // variables  
      vm.drinks = ko.observableArray();
      vm.pageSizes = [15, 25, 35, 50];
      vm.pageSize = ko.observable(pageSizes[0]);
      vm.currentPage = ko.observable(0);
    
      // computed variables
      // returns number of pages required for number of results selected
      vm.PageCount = ko.computed(function() {
        if (vm.pageSize()) {
          return Math.ceil(vm.drinks().length / vm.pageSize());
        } else {
          return 1;
        }
      });
    
      // returns items from the array for the current page
      vm.PagedResults = ko.computed(function() {
        if (vm.PageCount() > 1) {
          //return vm.drinks().slice(vm.currentPage, vm.pageSize());
          return vm.drinks().slice(vm.currentPage() * vm.pageSize(), (vm.currentPage() * vm.pageSize()) + vm.pageSize());
        } else {
          return vm.drinks();
        }
      });
    
      // returns a list of numbers for all pages
      vm.PageList = ko.computed(function() {
        if (vm.PageCount() > 1) {
          return Array.apply(null, {
            length: vm.PageCount()
          }).map(Number.call, Number);
        }
      });
    
      // methods
      // reset to first page
      vm.ResetCurrentPage = function() {
        vm.currentPage(0);
      }
    
      // go to page number
      vm.GoToPage = function(page) {
        vm.currentPage(page);
      }
    
      // determines if page # is active returns active class
      vm.GetClass = function(page) {
        return (page == vm.currentPage()) ? "active" : "";
      }
    
      // populate drink list
      vm.GetDrinks = function() {
        // get data
        $(function() {
          $.ajax({
            type: "GET",
            url: 'https://mysafeinfo.com/api/data?list=alcoholicbeverages&format=json',
            dataType: "json",
            success: function(data) {
              vm.drinks(data);
            }
          });
        });
      }
    
      // populate drinks
      vm.GetDrinks();
    }
    
    // apply bindings
    ko.applyBindings(ViewModel);
    .pagination > li > a:focus,
    .pagination > li > a:hover,
    .pagination > li > span:focus,
    .page-link.active {
      background-color: rgb(238, 238, 238);
    }
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    
    <div class="row">
      <div class="col-sm-3 pull-right form-horizontal">
        <label class="control-label col-sm-4">
          Results:
        </label>
        <div class="col-sm-8">
          <select data-bind="value: pageSize,           
                  optionsCaption: 'All Results',
                  options: pageSizes, event:{ change: ResetCurrentPage }" class="form-control"></select>
        </div>
      </div>
    </div>
    
    <table class="table table-striped table-condensed">
      <thead>
        <tr>
          <th style="width: 25%">Name</th>
          <th>Category</th>
          <th style="width: 50%">Description</th>
        </tr>
      </thead>
      <tbody data-bind="foreach: PagedResults">
        <tr>
          <td data-bind="text: nm"></td>
          <td data-bind="text: cat"></td>
          <td data-bind="text: dsc"></td>
        </tr>
      </tbody>
      <tfooter>
        <tr>
          <td colspan="3" class="text-center">
            <ul data-bind="foreach: PageList" class="pagination">
              <li class="page-item">
                <a href="#" class="page-link" data-bind="text: $data + 1, click: GoToPage, css: GetClass($data)"></a>
              </li>
            </ul>
          </td>
        </tr>
      </tfooter>
    </table>