简体   繁体   中英

Backbone.js - Cached collection and binding of events of its views and models

I am creating a Calendar app. The main view displays a single month, and in each month there are views for each day.

Data in the month is represented by a collection, and each model in the collection represents each day's data.

Now, I wanted to reduce the number of server requests to get the calendar, so each time I ask the server to get me results, I save it in an object.

var Calendar = Backbone.Router.extend({
  calendar_view  : new MonthView(),
  calendar_cache : new Object(),

  initialize:function() {
    calendar_view.display_calendar();
  }  
});

var MonthView = Backbone.View.extend({

  display_calendar : function() {
    if(calendar.calendar_cache[month]) {
      this.collection = calendar.calendar_cache[month];
      this.render();
    } else {
      // ... get the new calendar data from the server and save to the cache
    }
  }

  render:function() {
    // display calendar by building its views and rendering it.
  }
});

var cal = new Calendar();
var month = 10;

I'm not entirely sure if above is the right approach, but when I tried it, it worked well.

The model for each day and the month is simple.

var Month = Backbone.Collection.extend({
  model:Day
});

var Day = Backbone.Model.extend({});

Each day also has its view, which is built inside the "MonthView.render()" function.

var DayView = Backbone.View.extend({
  ...
});

Now, my problem is in my DayView, I bind to a model change to kick off a certain event, as below.

var DayView = Backbone.View.extend({
  initialize:function() {
    this.model.bind('change', this.highlight, this);
  },

  highlight:function() {
    console.log('This event should be fired whenever this view's model is changed!');
  }
});

But for the cached collection of models, the above binding isn't working. I am assuming it's something to do with binding/unbinding of views and its model events when I refresh the views.

I went through questions

Backbone.js : repopulate or recreate the view?

And also went through the article

http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/

But I'm not exactly sure what to do and how to go about this.

EDIT : I tried turning OFF the caching, but just requesting the server every time and everything works fine. So is it because there is an old view hanging around somewhere that is binding to the cached model?

EDIT : (For Thomas) rendering my "month view" is as follows. MonthView acts as a 'parent' view, and appends all the Day view into its "el".

MonthView = Backbone.View.extend({
  ...
  ...
  render:function() {
    var self = this;
    this.collection.each(function(day) {
      var each_day = new DayView({ model: day });
      $(self.el).append(each_day.render().el);

      // highlight if each_day is "today", by modifying the model's attribute.
      if( day.toJSON().day == TODAY ) {
        day.set({selected:true});
      }
    }
  }
});

var TODAY = 23;

Above code works fine, when displaying the calendar for the first time, but next time I'm accessing the same calendar, "day.set({selected:true})" doesn't seem to fire the "this.model.bind" set in the DayView file.

Above code works fine, when displaying the calendar for the first time, but next time I'm accessing the same calendar, "day.set({selected:true})" doesn't seem to fire the "this.model.bind" set in the DayView file.

Is the value of the TODAY variable changing between the time you first display the calendar and the next time you access it?

If the TODAY value doesn't change, then your following code below will set selected to true when you first display the calendar and fire the change event, however the next time you access the calendar, it will set selected to true on the same model, but the change event will not be fired because the selected value was already set to true and did not change.

  if( day.toJSON().day == TODAY ) {
    day.set({selected:true});
  }

Explications

It's normal that the model don't trigger the View the next time because Backbone JS don't change the model.

Indeed when you do day.set({selected:true}); , the model has now a property selected to true . So when you do once again, Backbone doesn't modify the model because it has already the property selected to true .

Solution

You don't need to modify the model to call the View's highlight function, call it directly from the View instance :

  if( day.toJSON().day == TODAY ) {
    each_day.highlight();
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM