Paul Cowan

Nomadic cattle rustler and inventor of the electric lasso

Emberjs - Creating a Timeago Helper

Freetime is very hard to come by when you have two small children under three but I actually had a couple of hours spare at this time of writing and had set myself the challenge of implementing an ember.js timeago handlebars helper when I came across this example by @jgwhite that does exactly that. The README gives a very good breakdown of how to implement the helper.

I’ve made some slight changes which you can see in this working jsbin. My view is pretty much the same apart from that I am comparing raw javascript dates instead of using moment.js.

timeago_view.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
App.TimeAgoView = Ember.View.extend({
  template: Ember.Handlebars.compile(""),
  didInsertElement: function() {
    this._super.apply(this, arguments);
    return this.tick();
  },
  formattedContent: Ember.computed(function() {
    var fromNow;
    fromNow = function(date) {
      var now = new Date(),
          timeDiff = Math.ceil((now.getTime()- date.getTime()) / (1000 * 60));

      if (timeDiff <= 1) {
        return "A few seconds ago";
      } else if (timeDiff < 60) {
        return "" + timeDiff + " minute(s) ago";
      } else {
        return "" + (Math.floor(timeDiff / 60)) + " hour(s) ago";
      }
    };

    return fromNow(this.get('content'));
  }).property('content'),
  tick: function() {
    var nextTick,
      _this = this;
    nextTick = Ember.run.later(this, function() {
      _this.notifyPropertyChange('formattedContent');
      return _this.tick();
    }, 60000);
    return this.set('nextTick', nextTick);
  },
  willDestroyElement: function() {
    this._super.apply(this, arguments);
    return Ember.run.cancel(this.get('nextTick'));
  }
});

The key to making this work is the notifyPropertyChange method which is a convenience method that calls propertyWillChange and propertyDidChange. Calling both these methods consecutively is actually what happens behind the scenes when you call set() on an object and the combination triggers a notification to all registered obervers that the property has changed.

My handlebars helper is ever so slightly different and possibly worth a brief comment and is listed below:

timeago_helper.js
1
2
3
4
5
6
7
Ember.Handlebars.registerHelper('timeAgo', function(property, options) {
  var value = Ember.get(this, property) || new Date();

  options.hash.content = value;

  return Ember.Handlebars.helpers.view.call(this, App.TimeAgoView, options);
});

Line 4 adds a new property to the the hash property of the options argument. Handlebars will mix any property in this options hash into the view. You can also set up bindings and other goodness for each property that you add by using the option.hashTypes hash. I am not doing that in this instance but it is worth noting that you can.

Line 6 uses the view helper to insert a new instance of the App.TimeAgoView into the output. It is worth noting that this is the helper that is called by handelbars for normal view declarations like this:

1
{{view App.SomeView}}

The upshot of all this is that I feel a bit deflated as I was really looking forward to sinking my teeth into this. I guess I have @jgwhite to thank for that.

I now need a new chanllenge…….and something that I have actually written to blog about…..

Comments