Knockout ajax paging example

uses knockout.pagedObservableArray extension

by jwstott

HTML

<script src="http://knockoutjs.com/downloads/knockout-2.2.1.js"></script>
<script src="http://dev7.blob.core.windows.net/dukane/knockout.pagedObservableArray.js"></script>
<script src="	 http://dev7.blob.core.windows.net/dukane/amplify.min.js"></script>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
<h1 data-bind="text: title"></h1>

<section>
    <ul data-bind="foreach: pagedPlaylists.allData()">
        <li><span data-bind="text: trimName"></span>

        </li>
        <hr/>
    </ul>
</section>
<div class="pagination">
    <ul>
        <li data-bind="css: { disabled: pagedPlaylists.pageIndex() === 1 }"> <a href="#" data-bind="    click: pagedPlaylists.previousPage">« Previous</a>

        </li>
    </ul>
    <ul data-bind="foreach: pagedPlaylists.pageRange()">
        <li data-bind="css: { active: $data === $root.pagedPlaylists.pageIndex() }"> <a href="#" data-bind="    text: $data, click: function () { $root.pagedPlaylists.moveToPage($data); }"></a>

        </li>
    </ul>
    <ul>
        <li data-bind="css: { disabled: pagedPlaylists.pageIndex() === pagedPlaylists.pageCount() }"> <a href="#" data-bind="    click: pagedPlaylists.nextPage">Next »</a>

        </li>
    </ul>
</div>

JavaScript

// Here's my data model
// pre-define amplify target resources
amplify.request.define('playlistsByOrganization', 'ajax', {
    url: 'http://d7.conveyclassrooms.com/api/engage/GetPlaylists',
    dataType: 'jsonp',
    type: 'GET'
    //cache: true
});

var Playlist = function (obj) {
    this.id = ko.observable(obj.id);
    this.organizationID = ko.observable(obj.organizationID);
    this.teacherID = ko.observable(obj.teacherID);
    this.name = ko.observable(obj.name);
    this.trimName = ko.computed({
        read: function () {
            var maxLen = 15,
                txt = this.name() || '';
            if (txt.length > maxLen) {
                return this.name().slice(0, maxLen) + '...';
            } else {
                return txt;
            }
        },
        deferEvaluation: true,
        owner: this
    });
    this.description = ko.observable(obj.description);
    this.assessmentType = ko.observable(obj.assessmentType);
    this.questionCount = ko.observable(obj.questionCount);
    this.author = ko.observable(obj.author);
    this.department = ko.observable(obj.department);
    this.subject = ko.observable(obj.subject);
    this.grade = ko.observable(obj.grade);
};

var ViewModel = function () {
    this.title = ko.observable('Sample VM');
    this.pagedPlaylists = new ko.pagedObservableArray({
        serverPaging: true,
        pageSize: 15,
        autoLoad: true,
        aggregateResults: false,
        loadPage: function (options) {
            return getPlaylists({
                id: 'CCDA27BA-9028-40FB-865E-09BF0163C2D1'
            });
        },
        map: function (newData) {
            var newItems = ko.utils.arrayMap(newData, function (item) {
                return new Playlist(item);
            });
            return newItems;
        },
        schema: {
            // describe the result format
            data: "Data", // the data which the data source will be bound to is in the "results" field
            count:...