Ralph von der Heyden

14 November 2014 by Ralph von der Heyden

Time based triggers in Ember.JS

Sometimes you want to poll an API for new data periodically. Sometimes you depend on properties that change over time, but are out of Ember's control. Fear not, Ember's run.later has you covered.

If you want to re-evaluate a computed property on a schedule, you need to depend that property on a property that changes over time. Turns out that creating such a property is fairly simple. This function triggers a change every second:

currentTimeMetronome: function() {  
  var interval = 1000;
  Ember.run.later(this, function() {
    this.notifyPropertyChange('currentTimePulse');
    this.currentTimeMetronome();
  }, interval);
}.on('init'),

Computed properties can depend on the currentTimePulse to get re-evaluated every second:

currentTime: function() {  
  var date = new Date();
  return date.toString();
}.property('currentTimePulse'),

The trick is to use Ember.run.later here. It receives 3 arguments, the last being the time (in ms) to postpone running the function in the 2nd argument. The first argument is the context the function should be run in.

You can apply the same pattern to functions, for example to poll APIs for new data:

App.IndexRoute = Ember.Route.extend({  
  model: function() {
    var interval = 1000 * 60;
    Ember.run.later(this, function() {
      this.model().then(function(json) {
        this.controller.set('model', json);
      }.bind(this));
    }, interval);

    return Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/commits');
  },
});

Check out this JSbin if you want to see a running demo:
Demo: http://emberjs.jsbin.com/xoriq/6
Code: http://emberjs.jsbin.com/xoriq/6/edit?js,output

UPDATE: Reader Dhruv Parmar pointed me to an article by Richard Livsey that shows how to "install" a clock inside your Ember app that is then injected into controllers, routes and the like. If you need a clock in multiple places, this is definitely the way to go. The downside of Richard's solution is using setTimeout(), which can be less efficient than Ember.run.later.