Reputation: 2191
Is there a simple way to trigger a Backbone.js event when the current date (just the day, not the time) changes?
Upvotes: 2
Views: 1609
Reputation: 4479
You may create constructor that extends Backbone Events like this:
var Clocks = function(){};
_.extend(Clocks.prototype, Backbone.Events, {
start: function () {
this.timer = setInterval(_.bind(this.tick, this), 1000);
return this;
},
tick: function () {
this.trigger('tick', new Date)
},
stop: function () {
this.timer && clearInterval(this.timer);
return this;
}
});
And then use it in backbone model to update it attributes:
var ClocksModel = Backbone.Model.extend({
defaults: function () {
var date = new Date
return {
date: date.getDate(),
seconds: date.getSeconds()
}
},
initialize: function () {
this.clocks = new Clocks;
this.clocks.on('tick', this.updateDate, this)
},
updateDate: function (date) {
this.set('date', date.getDate())
this.set('seconds', date.getSeconds())
},
start: function () {
this.clocks.start();
return this;
},
stop: function () {
this.clock.stop();
return this;
}
});
Then you'll be able to:
clocks = new ClocksModel;
clocks
.on('change:seconds', function(model, newSeconds) {
console.log('seconds changed to ', newSeconds)
})
.on('change:date', function(model, newDate) {
console.log('date changed to', newDate)
})
.start()
Upvotes: 2
Reputation: 4205
So, the answer to the question - there is no simple way without rolling your own solution.
That said, the implementation isn't too bad.
The idea here is that you have a model with a 'day' property. Upon initializing the model, we'll invoke an initializer that will determine the duration till 'midnight tomorrow'. Right after midnight, the setTimeout will get called which will update the model's 'day' property. In the view itself, we listen for a change for the 'day' property. Once the property is updated, we'll re-initialize the method that changes the date. This way there's no polling, and your events will be triggered once the date changes.
Of course there are numerous ways you could broadcast the update - i.e. explicitly trigger the event as opposed to set
ing the property -- but here's the code for what I've described above:
Model
var Model = Backbone.Model.extend({
defaults: function(){
var d = new Date();
return {
day: d.getDay()
}
},
initialize: function(){
_.bindAll(this, '_init_date_trigger');
this._init_date_trigger();
},
_init_date_trigger: function(){
var now = new Date();
var midnightTomorrow = new Date();
midnightTomorrow.setDate(now.getDate() + 1);
midnightTomorrow.setHours(0,0,0,0);
var msTillTomorrow = midnightTomorrow - now + 1;
var me = this;
console.log("date will be changed in " + msTillTomorrow);
setTimeout(function(){
me.set("day", new Date().getDay());
me._init_date_trigger();
}, msTillTomorrow);
}
})
View
var View = Backbone.View.extend({
template:_.template("The day is: <span class='day'> <%= day %> </span>"),
initialize: function(){
this.model.on("change:day", this.render);
},
render: function(){
this.$el.html( this.template( this.model.toJSON() ) );
return this;
}
});
Implementation
var myModel = new Model();
var myView = new View({model: myModel});
$("#example").html( myView.render().el );
Here's the fiddle: http://jsfiddle.net/6KGzt/4/
Upvotes: 4
Reputation: 78731
I don't have a better idea than checking regularly:
var lastCheckedDate = new Date();
setInterval(function () {
var d = new Date();
//TODO: check whether the day in d and lastCheckedDate are the same or not
//TODO: if not, trigger event
lastCheckedDate = d;
}, 10000); //this will check in every 10 seconds
Upvotes: 2