2012-12-01

Paged Grid with Knockout.js and WebApi

,
I want to see how easily you can create a custom grid that uses an WebApi as datasource and that allows the user to page the data and also allow them to choose a page size for the grid.

The WebApi

The WebApi will return a viewmodel that contains an array of names (string) and a property that specifies how many pages that there are available.
    public class NamesGridViewModel
    {
        public IEnumerable<String> Names { get; set; }

        public int NumberOfPages { get; set; }
    }

The WebApi itself will contain a method that accepts 2 parameters. The parameters will be page (the page that we request) and pagesize (how many entries a page contains). This method will be responsible for calculating how many pages there are and to serve the requested names based on the 2 parametes.
    public class ValuesController : ApiController
    {
        public IList<String> Names
        {
            get { return new List<String> { "Fred", "Barney", "Betty", "Wilma", "Bart", "Lisa", "Maggie", "Homer", "Marge" }; }
        }
            
        public NamesGridViewModel Get(int page, int pagesize)
        {
            return new NamesGridViewModel
                       {
                           // get the request names for the specific page
                           Names = (0 == page? null : Names.Skip((page - 1)*pagesize).Take(pagesize).ToArray())
                           ,
                           // calculated number of pages and ceil the value
                           NumberOfPages = ((int) Math.Ceiling((double) Names.Count/pagesize))
                       };
        }
    }

The client


The client will need a reference to kockout.js. With knockout.js it is possible to apply the MVVM pattern and also work with templates in javascript.


The UI

Page size: <select data-bind="options: availablePageSize, optionsText: $data, value: selectedPageSize"></select><!-- the grid --><table data-bind="with: namesGridViewModel">
    <thead>
        <tr>
            <th>
                Name
            </th>
        </tr>
    </thead>
    <tbody data-bind="foreach: Names">
        <tr>
            <td data-bind="text: $data">
            </td>
        </tr>
    </tbody>
</table><!--Contains the page links--><div id="pager"></div>

The Javascript

<script type="text/javascript">
    // Our  ViewModel.
    function pageViewModel() {
        var self = this;
        self.namesGridViewModel = ko.observable(); // contains the viewmodel returned by the WebApi
        self.selectedPageSize = ko.observable(3); // contains the selected page size, default value is 3
        self.availablePageSize = ko.observableArray([1, 2, 3, 4, 5]); // contains the available page sizes a user can select
        self.selectedPage = ko.observable(1); // contains the selected page

        // Add a click event to all future element with a class "pageIndex". This event will fire
        // when the user clicks a specific page.
        $("#pager").on("click", ".pageIndex", function (event) {
            // set the selected page in the viewModel
            self.selectedPage($(this).text());
        });

        // This function will be used to get the data from our WebApi. The requested page and page size are passed
        // as a parameter. The result will be stored in the namesGridViewModel property. This will cause that the subscribe event
        // for the namesGridViewModel will be fired ==> the page links will be created.
        self.navigate = function () {
            $.get("/api/values?page=" + self.selectedPage() + "&pagesize=" + self.selectedPageSize(), self.namesGridViewModel);
        };

        // Function that will subscribe to all the needed events.
        self.SubscribeToEvents = function () {

            // This event will fire when selectedPageSize is changed.
            self.selectedPageSize.subscribe(function (newValue) {
                self.selectedPage(1);
                self.navigate();
            });

            // This event will be fired when the selectedPage is changed.
            self.selectedPage.subscribe(function (newValue) {
                self.navigate();
            });

            // This event will fire when a new value is defined for the namesGridViewModel.
            // It will create the page links below the grid.
            self.namesGridViewModel.subscribe(function (newValue) {
                var numberOfPages = newValue.NumberOfPages;
                var $pager = $("#pager");
                // clear the pager
                $pager.html("");
                // created the pages the user can click on
                for (var i = 1; i <= numberOfPages; i++) {
                    var link = $('<a class="pageIndex">' + i + '</a>');
                    $pager.append(link);
                }
            }, this);
        };
        
        // This function will be used to kick start everything.
        self.bind = function () {
            self.SubscribeToEvents();
            self.navigate();
            ko.applyBindings(self);
        }
    }
    // Create the viewModel and bind it.
    $(function () { new pageViewModel().bind(); })</script>

The result


image

Summary


You have seen how to create a basic paging grid using Knockout.js.You can easily extend this example to also allow sorting. The solution can be downloaded here.

10 comments:

  1. Nice example! Thanks!

    ReplyDelete
  2. I need a more complex observable data (in your code is an array of string, "Names").

    same as :
    var ObservableProduct = function (productCode, productdescription, imageName) {
    this.ProductCode = ko.observable(productCode);
    this.ProductDescription = ko.observable(productdescription);
    this.ImageName = ko.observable(imageName);
    };
    With computed data, etc...

    but I was not able to modify your code to get the result, you can give me a hand?

    ReplyDelete
  3. Nice article Thanks :)

    ReplyDelete
  4. Nice articles Thanks a lot

    ReplyDelete
  5. I have some confusion with the codes that were used here and I guess you need to edit some of it. But anyhow, this post is commendable for a dissertation writing topic.

    ReplyDelete
  6. Wow! Thank you! I continually needed to write on my site something like that. Can I take a fragment of your post to my blog.create free store cards

    ReplyDelete
  7. This post gives truly quality information. I’m definitely going to look into it. Really very useful tips are provided here. Thank you so much. Keep up the good works.traveltims |

    travelredsea |

    phototravels |

    traveldomain |

    denver-travel |

    zesttravel |

    mytraveldna |

    texastravelfreedom |

    foodietravel |

    socaltravelsurvey |

    ReplyDelete
  8. Alat bantu sex merupakan sebuah benda khusus di buat untuk membantu seseorang mendapatkan kepuasan sex.
    Salah satu alat bantu sex wanita yang banyak di gunakan untuk di jadikan sebagai alat sex untuk memuaskan dirinya sendiri adalah penis silikon.
    Penis mainan sex ini merupakan alat sex wanita yang dapat di pakai untuk membantu masturbasi (onani) juga hubungan sex.
    Ukuran penis berfariasi dari mulai ukuran sedang sampai ukuran penis besar.
    Selain alat bantu sexsualitas wanita juga ada benda khusus untuk pria.
    Alat bantu sex pria ini bentuk nya berbmacam macam, salah satu alat bantu pria yang cukup banyak di pakai adalah vagina silikon tabung senter.
    Sex merupakan salah satu kebutuhan pria wanita dewasa yang sudah berpasangan demi untuk menjaga jauh dari kesepian alat seks mungkin solusi yang cukup sederhan untuk mengatasi hasrat seksual seseorang yang kesepian.
    Geraipasutri.

    ReplyDelete