More with Backbone

In my last entry I had made a small change to an existing backbone.js application. Instead of loading all projects in my company’s portfolio, I adjusted the view to only load a subset of them. I still need, however, to create a “load more” button to allow the user load the remainder of the projects as desired. I left my previous entry wondering how to do this.

I think I know how to add the event that the button will trigger at least. It should look like this:

 events:{
    "click .more" : "renderNextProjectGroup"
 }

And renderNextProjectGroup should figure out how many projects are currently being displayed n, then load n + 1 through n + 1 + projectsPerLoad. How do I determine how projects are currently being displayed?

I know I can do this using basic jQuery:

renderNextProjectGroup: function () {
   var that = this;

   var start = $(".project").length;
   var end = start + (that.projectsPerLoad - 1);
   that.renderProjectGroup(start, end);
},

start grabs the number of projects currently displayed. end simply adds the number of additional projects to show.

This works but it feels wrong. Should a view (or model?) be keeping track of how many projects are currently displayed, or is ok to grab that info as-needed like I’m doing?

I think a bigger offense, however, is using “.project” instead of grabbing this value from the ProjectView, which look like this:

var ProjectView = Backbone.View.extend({
   className: "project coda-slider-wrapper",
   template: $("#projectTemplate").html(),

   render: function () {
      var tmpl = _.template(this.template);
      this.$el.html(tmpl(this.model.toJSON()));
      return this;
   }
});

How do I use backbone/underscore to determine how many elements there are with ProjectView.className?

I tried this but it doesn’t work:

var Portfolio = Backbone.Collection.extend({
   model: Project,
   url: '/json/projects.json',
   projectClass: "project2 coda-slider-wrapper"
});

var ProjectView = Backbone.View.extend({
   className: this.Portfolio.projectClass,
   ....
});

Hm. I’ve decided I’m never going to figure out how this is typically done within backbone until I see it done using backbone. I need to find an existing example of a similar effort.

< … googling “backbone pagination” … >

I found a backbone plugin (or component, if you will) that seems to do exactly what I’m trying to do: http://addyosmani.com/blog/backbone-paginator-new-pagination-components-for-backbone-js/

< … frustrating efforts to use addy osmani’s pagination components … >

I can’t get Addy Osmani’s pagination components to work. Despite the ability to customize the query parameters, I can’t figure out how to get the paginator to work with my data. It calls my data but I don’t know if the data is being successfully set up in a array somewhere or what has happened to it.

Maybe there is something more simple out there. Maybe I can just do this myself after all. All I really need is the load more button and a better way to keep track of the total number of projects. Maybe I can use the pagination component for ideas, but just code it myself.

One thing I haven’t been sure of is whether I should simply hard code the HTML for the load more button or use a template. Osmani’s pagination component uses a template and that seems reasonable, so I will start there. The code for the button will look like this (adapted from Osmani’s):

<script id="projectPagination" type="text/html">
   <% if (page < totalPages) { %>
      <a href="#" class="btn project_next">Show More</a>
   <% } %>
</script>

Obviously I need to put values to page and totalPages. Osmani’s pagination component declares those values in the collection, which makes sense. I can set the totalPages value when the collection finishes fetching the data. Here’s what I end up with:

var Portfolio = Backbone.Collection.extend({
   model: Project,
   url: '/json/projects.json',
   projectClass: "project2 coda-slider-wrapper",
   numProjects: 0,
   page: 0,
   perPage: 5,
   totalPages: 0,

   parse: function(response) {
      this.numProjects = _.size(response);
      this.totalPages = Math.ceil(this.numProjects / this.perPage);

      return response;
   }
 });

This all works as expected. But what about the page variable? Where and when should that be set? Beyond the initial declaration the page variable is nowhere to be found in the collection. Osmani’s collection does extend paginator.requestPager though. It’s all over the place there. Because our needs are so much more simple than what Osmani’s code does though, I think I will just do this myself.

First I’m going to set up the event that’s triggered when the load more button is clicked.

< … big time struggling with how to share a controller between multiple views … >

I can’t figure out how to have my PortfolioView, which displays all the projects, and my LoadMoreView, which is simply the button that will load more projects, both get values from the controller. PortfolioView needs the models from the controller to display each project, and LoadMoreView needs to know if it should continue to be displayed.

Finally I have found “Developing Backbone.js Applications” and the “Gotchyas” section of “A Conceptual Understanding of Backbone.js For The Everyman“. Both describe passing a model and the collection it belongs to to each view. I’m going to give that a try.

 

Leave a Reply