Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add in the example to combine search with request paging #147

Closed
wants to merge 2 commits into from

2 participants

@simkimsia

This is for issue #141

#141

It works, but I have two problems.

1) it does not work with the PaginationView.

2) it does not work with History.

Please check if the architecture here makes sense to you.

@simkimsia

I just read about the use of Mediator pattern to resolve the problem of View trigger updates in other Views in your book Developing Backbone.js Applications

I suspect my SearchView is trying to trigger a change in the ResultView.

Should I also attempt to use Mediator pattern here?

@addyosmani
Owner

@simkimsia since you opened up this PR I'm now recommending developers use the event bus/aggregator that comes in Backbone 1.0 (also in the common problems section of the updated book) for mediation. Could you take a look at http://lostechies.com/derickbailey/2013/03/18/event-aggregator-andorvs-mediator-a-tale-of-two-patterns/ and let me know if you would like to adjust the solution accordingly?

@addyosmani
Owner

ping :)

@simkimsia

Hi @addyosmani let me take a look and try to adjust the solution accordingly.

@addyosmani addyosmani closed this
@wyuenho wyuenho referenced this pull request from a commit
@wyuenho wyuenho Fix #147. Backbone.PageableCollection#clone should clone the entire P…
…ageableCollection under any more
aa3549c
@wyuenho wyuenho referenced this pull request from a commit
@wyuenho wyuenho Code reduction for #147 0a953b6
@wyuenho wyuenho referenced this pull request from a commit
@wyuenho wyuenho Revert "Code reduction for #147"
This reverts commit 0a953b6.
1967e17
@wyuenho wyuenho referenced this pull request from a commit
@wyuenho wyuenho Revert "Fix #147. Backbone.PageableCollection#clone should clone the …
…entire PageableCollection under any more"

This reverts commit aa3549c.

Conflicts:
	test/infinite-pageable.js
1a467c8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
20 examples/netflix-request-paging-with-search/app.js
@@ -0,0 +1,20 @@
+//Top-level namespaces for our code
+
+(function(){
+
+ window.app = {};
+ app.collections = {};
+ app.models = {};
+ app.views = {};
+ app.mixins = {};
+
+ // Defer initialization until doc ready.
+ $(function(){
+ app.collections.paginatedItems = new app.collections.PaginatedCollection();
+ app.views.search = new app.views.SearchView({collection:app.collections.paginatedItems});
+ app.views.app = new app.views.AppView({collection: app.collections.paginatedItems});
+ app.views.pagination = new app.views.PaginatedView({collection:app.collections.paginatedItems});
+ });
+
+})();
+
View
96 examples/netflix-request-paging-with-search/collections/PaginatedCollection.js
@@ -0,0 +1,96 @@
+(function (collections, model, paginator) {
+
+ // Create a new collection using one of Backbone.Paginator's
+ // pagers. We're going to begin using the requestPager first.
+
+ collections.PaginatedCollection = paginator.requestPager.extend({
+
+ // As usual, let's specify the model to be used
+ // with this collection
+ model: model,
+
+ // We're going to map the parameters supported by
+ // your API or backend data service back to attributes
+ // that are internally used by Backbone.Paginator.
+
+ // e.g the NetFlix API refers to it's parameter for
+ // stating how many results to skip ahead by as $skip
+ // and it's number of items to return per page as $top
+
+ // We simply map these to the relevant Paginator equivalents
+
+ // Note that you can define support for new custom attributes
+ // adding them with any name you want
+
+ paginator_core: {
+ // the type of the request (GET by default)
+ type: 'GET',
+
+ // the type of reply (jsonp by default)
+ dataType: 'jsonp',
+
+ // the URL (or base URL) for the service
+ url: 'http://odata.netflix.com/Catalog/People(49446)/TitlesActedIn?'
+ },
+
+ paginator_ui: {
+ // the lowest page index your API allows to be accessed
+ firstPage: 1,
+
+ // which page should the paginator start from
+ // (also, the actual page the paginator is on)
+ currentPage: 1,
+
+ // how many items per page should be shown
+ perPage: 3,
+
+ // a default number of total pages to query in case the API or
+ // service you are using does not support providing the total
+ // number of pages for us.
+ // 10 as a default in case your service doesn't return the total
+ totalPages: 10
+ },
+
+ server_api: {
+ // the query field in the request
+ '$filter': '',
+
+ // number of items to return per request/page
+ '$top': function() { return this.perPage },
+
+ // how many results the request should skip ahead to
+ // customize as needed. For the Netflix API, skipping ahead based on
+ // page * number of results per page was necessary.
+ '$skip': function() { return (this.currentPage - 1) * this.perPage },
+
+ // field to sort by
+ '$orderby': function() {
+ if(this.sortField === undefined)
+ return 'ReleaseYear';
+ return this.sortField;
+ },
+
+ // what format would you like to request results in?
+ '$format': 'json',
+
+ // custom parameters
+ '$inlinecount': 'allpages',
+ '$callback': '?'
+ },
+
+ parse: function (response) {
+ // Be sure to change this based on how your results
+ // are structured (e.g d.results is Netflix specific)
+ var tags = response.d.results;
+ //Normally this.totalPages would equal response.d.__count
+ //but as this particular NetFlix request only returns a
+ //total count of items for the search, we divide.
+ this.totalPages = Math.ceil(response.d.__count / this.perPage);
+
+ this.totalRecords = parseInt(response.d.__count);
+ return tags;
+ }
+
+ });
+
+})( app.collections, app.models.Item, Backbone.Paginator);
View
155 examples/netflix-request-paging-with-search/index.html
@@ -0,0 +1,155 @@
+<!DOCTYPE HTML>
+<html lang="en-US">
+
+ <head>
+
+ <meta charset="UTF-8">
+ <title>Backbone.js pagination</title>
+ <link rel="stylesheet" href="../css/bootstrap.min.css">
+ </head>
+
+ <body>
+
+ <div class="container">
+ <p>&nbsp;</p>
+ <div class="page-header">
+ <h1>Paginator.requestPager() <small>Paginating requests to and from an API/backend</small></h1>
+ </div>
+
+ <div id="searchForm">
+ </div>
+
+
+ <h3 id="searchTitle"></h3>
+ <ul id="content">
+ </ul>
+
+ <div id="pagination">
+ </div>
+
+ </div>
+
+ <script type="text/html" id="searchFormTemplate">
+ <input type="text" id="searchText" />
+ <input type="submit" id="searchSubmit" value="Search" />
+ </script>
+
+ <!--sample template for result item-->
+ <script type="text/html" id="resultItemTemplate">
+ <div class="result row">
+ <div class="title">
+ <h4><%= Name %></h4>
+ <div class="meta"><strong>Meta-data:</strong> Runtime: <%= Math.floor(Runtime/60) %> mins, Released: <%= ReleaseYear %>, Rating: <%= Rating %></span>
+ </div>
+
+ <div class="span12 cover">
+ <div class="span4">
+ <img src="<%= BoxArt.MediumUrl %>"/></div>
+ <div class="synop span8">
+ <%= ShortSynopsis %>
+ </div>
+ </div>
+
+ </div>
+ </script>
+
+ <!-- sample template for pagination UI -->
+ <script type="text/html" id="tmpServerPagination">
+ <div class="breadcrumb">
+
+ <span class="cell">
+ <% for(p=1;p<=totalPages;p++){
+ %>
+ <% if (currentPage == p) { %>
+ <span class="page selected"><%= p %></span>
+ <% } else { %>
+ <a href="#" class="page"><%= p %></a>
+ <% } %>
+ <%
+ }%>
+
+ <span class="divider">/</span>
+
+ <% if (currentPage > firstPage) { %>
+ <a href="#" class="serverprevious">Previous</a>
+ <% }else{ %>
+ <span>Previous</span>
+ <% }%>
+
+ <% if (currentPage < totalPages) { %>
+ <a href="#" class="servernext">Next</a>
+ <% } %>
+
+ <% if (firstPage != currentPage) { %>
+ <a href="#" class="serverfirst">First</a>
+ <% } %>
+
+ <% if (lastPage != currentPage) { %>
+ <a href="#" class="serverlast">Last</a>
+ <% } %>
+
+
+ <span class="divider">/</span>
+
+ <span class="cell serverhowmany">
+ Show
+ <a href="#" class="selected">3</a>
+ |
+ <a href="#" class="">9</a>
+ |
+ <a href="#" class="">12</a>
+ per page
+ </span>
+
+
+ <span class="divider">/</span>
+ <span class="cell first records">
+ Page: <span class="current"><%= currentPage %></span>
+ of
+ <span class="total"><%= totalPages %></span>
+ shown
+ </span>
+
+ <span class="divider">/</span>
+
+ <span class="cell sort">
+ <a href="#" class="orderUpdate btn small">Sort by:</a>
+ </span>
+
+ <select id="sortByField">
+ <option value="cid">Select a field to sort on</option>
+ <option value="ReleaseYear">Release year</option>
+ <option value="ShortName">Alphabetical</option>
+ </select>
+ </span>
+
+
+ </div>
+ </script>
+
+
+
+ <!-- scripts-->
+ <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
+ <script src="../libs/underscore.js"></script>
+ <script src="../libs/json2.js"></script>
+ <script src="../libs/backbone-min.js"></script>
+
+ <script src="app.js"></script>
+
+ <!--Backbone.Paginator-->
+ <script src="../../lib/backbone.paginator.js"></script>
+
+ <!--Models/Collections-->
+ <script src="models/Item.js"></script>
+ <script src="collections/PaginatedCollection.js"></script>
+
+ <!--Views-->
+ <script src="views/ResultView.js"></script>
+ <script src="views/PaginationView.js"></script>
+ <script src="views/SearchView.js"></script>
+ <script src="views/AppView.js"></script>
+
+
+ </body>
+</html>
View
3  examples/netflix-request-paging-with-search/models/Item.js
@@ -0,0 +1,3 @@
+(function ( models ) {
+ models.Item = Backbone.Model.extend({});
+})( app.models );
View
32 examples/netflix-request-paging-with-search/views/AppView.js
@@ -0,0 +1,32 @@
+(function ( views ) {
+
+ views.AppView = Backbone.View.extend({
+ el : '#content',
+
+ initialize : function () {
+
+ var tags = this.collection;
+
+ tags.on('add', this.addOne, this);
+ tags.on('reset', this.addAll, this);
+ tags.on('all', this.render, this);
+
+ tags.pager();
+
+ },
+
+ addAll : function () {
+ this.$el.empty();
+ this.collection.each (this.addOne);
+ },
+
+ addOne : function ( item ) {
+ var view = new views.ResultView({model:item});
+ $('#content').append(view.render().el);
+ },
+
+ render: function(){
+ }
+ });
+
+})( app.views );
View
75 examples/netflix-request-paging-with-search/views/PaginationView.js
@@ -0,0 +1,75 @@
+(function (views) {
+
+ views.PaginatedView = Backbone.View.extend({
+
+ events: {
+ 'click a.servernext': 'nextResultPage',
+ 'click a.serverprevious': 'previousResultPage',
+ 'click a.orderUpdate': 'updateSortBy',
+ 'click a.serverlast': 'gotoLast',
+ 'click a.page': 'gotoPage',
+ 'click a.serverfirst': 'gotoFirst',
+ 'click a.serverpage': 'gotoPage',
+ 'click .serverhowmany a': 'changeCount'
+
+ },
+
+ tagName: 'aside',
+
+ template: _.template($('#tmpServerPagination').html()),
+
+ initialize: function () {
+
+ this.collection.on('reset', this.render, this);
+ this.collection.on('change', this.render, this);
+
+ this.$el.appendTo('#pagination');
+
+ },
+
+ render: function () {
+ var html = this.template(this.collection.info());
+ this.$el.html(html);
+ },
+
+ updateSortBy: function (e) {
+ e.preventDefault();
+ var currentSort = $('#sortByField').val();
+ this.collection.updateOrder(currentSort);
+ },
+
+ nextResultPage: function (e) {
+ e.preventDefault();
+ this.collection.requestNextPage();
+ },
+
+ previousResultPage: function (e) {
+ e.preventDefault();
+ this.collection.requestPreviousPage();
+ },
+
+ gotoFirst: function (e) {
+ e.preventDefault();
+ this.collection.goTo(this.collection.information.firstPage);
+ },
+
+ gotoLast: function (e) {
+ e.preventDefault();
+ this.collection.goTo(this.collection.information.lastPage);
+ },
+
+ gotoPage: function (e) {
+ e.preventDefault();
+ var page = $(e.target).text();
+ this.collection.goTo(page);
+ },
+
+ changeCount: function (e) {
+ e.preventDefault();
+ var per = $(e.target).text();
+ this.collection.howManyPer(per);
+ }
+
+ });
+
+})( app.views );
View
18 examples/netflix-request-paging-with-search/views/ResultView.js
@@ -0,0 +1,18 @@
+( function ( views ){
+
+ views.ResultView = Backbone.View.extend({
+ tagName : 'li',
+ template: _.template($('#resultItemTemplate').html()),
+
+ initialize: function() {
+ this.model.bind('change', this.render, this);
+ this.model.bind('destroy', this.remove, this);
+ },
+
+ render : function () {
+ this.$el.html(this.template(this.model.toJSON()));
+ return this;
+ }
+ });
+
+})( app.views );
View
43 examples/netflix-request-paging-with-search/views/SearchView.js
@@ -0,0 +1,43 @@
+(function (views) {
+
+ views.SearchView = Backbone.View.extend({
+
+ events: {
+ 'click input#searchSubmit': 'fetchResults',
+ },
+
+ template: _.template($('#searchFormTemplate').html()),
+
+ initialize: function () {
+
+ this.collection.on('reset', this.render, this);
+ this.collection.on('change', this.render, this);
+
+ this.$el.appendTo('#searchForm');
+
+ },
+
+ render: function () {
+ var html = this.template(this.collection.info());
+ this.$el.html(html);
+ },
+
+ fetchResults: function (e) {
+ e.preventDefault();
+ var searchText = $('#searchText').val();
+ // for more information on the Netflix API,
+ // checkout http://developer.netflix.com/docs/oData_Catalog
+ var searchQuery = "Name eq '";
+ if (searchText && searchText !== "") {
+ searchQuery = searchQuery + searchText + "'";
+ }
+ this.collection.goTo(1,
+ {
+ data: {'$filter' : searchQuery}
+ }
+ );
+ },
+
+ });
+
+})( app.views );
Something went wrong with that request. Please try again.