Skip to content
This repository

Support for bound handlebars helpers #615

Closed
wants to merge 1 commit into from

5 participants

Gordon L. Hempton Peter Wagenet Stefan Rauchegger Trek Glowacki Niels Hoffmann
Gordon L. Hempton

This is my first attempt at adding a convenient way to create bound handlebars helpers. Bound handlebars helpers can now be created as follows:

  Ember.Handlebars.registerBoundHelper('capitalize', function(value) {
    return value.toUpperCase();
  });

Would love some feedback as to how this could be cleaned up.

Peter Wagenet
Owner

This is based on the BoundProperty stuff I did right? If so, and if we merge this, should we change basic property bindings to use this as well?

Stefan Rauchegger

would this support bidirectional binding?!

Peter Wagenet
Owner

@smadep No. If you want to bind to the DOM you have to do some extra work. As an example, the TextSupport mixin handle this for TextField and TextArea: https://github.com/emberjs/ember.js/blob/master/packages/ember-handlebars/lib/controls/text_support.js

Peter Wagenet
Owner

@ghempton I think it would definitely be useful to get something like this in core. However, I know there was some concern from @wycats about the way rendering is handled here. @wycats, any more thoughts on the matter?

Trek Glowacki
Owner
trek commented July 06, 2012

this isn't on the 1.0 milestone, but probably should be.

Niels Hoffmann

+1 for putting this on the 1.0 milestone

Peter Wagenet
Owner

@nhoffmann Already there :)

Gordon L. Hempton

I'd be happy to take another pass on this. What is the desired implementation? I think @wycats was wanting to reuse the code path from {{bind}}, but I'm wary of making Ember._HandlebarsBoundView more complex.

Peter Wagenet wagenet closed this October 08, 2012
Peter Wagenet
Owner

Closing in favor of #1274,

Jakub Nieznalski knusul referenced this pull request from a commit October 28, 2013
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

Mar 23, 2012
Gordon L. Hempton Support for bound handlebars helpers 711eb90
This page is out of date. Refresh to see the latest.
1  .gitignore
@@ -31,3 +31,4 @@ tmp
31 31
 tmp*.gem
32 32
 tmp.bpm
33 33
 tmp.spade
  34
+.project
28  packages/ember-handlebars/lib/ext.js
@@ -165,3 +165,31 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
165 165
   throw new Ember.Error(Ember.String.fmt(error, [view, path, this]));
166 166
 });
167 167
 
  168
+/**
  169
+  Registers a bound helper in handlebars. This helper will automatically
  170
+  update when the specified property path changes.
  171
+
  172
+  @param {String} name
  173
+  @param {Function} func
  174
+*/
  175
+Ember.Handlebars.registerBoundHelper = function(name, func) {
  176
+  var propertyPaths = Array.prototype.slice.call(arguments, 2);
  177
+  Ember.Handlebars.registerHelper(name, function(property, options) {
  178
+    var data = options.data,
  179
+        view = data.view,
  180
+        ctx  = this;
  181
+    
  182
+    var bindView = view.createChildView(Ember._BoundHelperView, {
  183
+      property: property,
  184
+      propertyPaths: propertyPaths,
  185
+      context: ctx,
  186
+      options: options.hash,
  187
+      value: func
  188
+    });
  189
+
  190
+    view.appendChild(bindView);
  191
+  });
  192
+};
  193
+
  194
+
  195
+
1  packages/ember-handlebars/lib/views.js
@@ -5,4 +5,5 @@
5 5
 // ==========================================================================
6 6
 
7 7
 require("ember-handlebars/views/bindable_span");
  8
+require("ember-handlebars/views/bound_helper_view");
8 9
 require("ember-handlebars/views/metamorph_view");
51  packages/ember-handlebars/lib/views/bound_helper_view.js
... ...
@@ -0,0 +1,51 @@
  1
+var get = Ember.get, set = Ember.set, getPath = Ember.Handlebars.getPath;
  2
+
  3
+require('ember-views/views/view');
  4
+require('ember-handlebars/views/metamorph_view');
  5
+
  6
+Ember._BoundHelperView = Ember.View.extend(Ember.Metamorph, {
  7
+
  8
+  context: null,
  9
+  options: null,
  10
+  property: null,
  11
+  // paths of the property that are also observed
  12
+  propertyPaths: [],
  13
+  
  14
+  value: Ember.K,
  15
+  
  16
+  valueForRender: function() {
  17
+    var value = this.value(Ember.getPath(this.context, this.property), this.options);
  18
+    if (this.options.escaped) { value = Handlebars.Utils.escapeExpression(value); }
  19
+    return value;
  20
+  },
  21
+
  22
+  render: function(buffer) {
  23
+    buffer.push(this.valueForRender());
  24
+  },
  25
+
  26
+  valueDidChange: function() {
  27
+    if (this.morph.isRemoved()) { return; }
  28
+    this.morph.html(this.valueForRender());
  29
+  },
  30
+
  31
+  didInsertElement: function() {
  32
+    this.valueDidChange();
  33
+  },
  34
+
  35
+  init: function() {
  36
+    this._super();
  37
+    Ember.addObserver(this.context, this.property, this, 'valueDidChange');
  38
+    this.get('propertyPaths').forEach(function(propName) {
  39
+        Ember.addObserver(this.context, this.property + '.' + propName, this, 'valueDidChange');
  40
+    }, this);
  41
+  },
  42
+  
  43
+  destroy: function() {
  44
+    Ember.removeObserver(this.context, this.property, this, 'valueDidChange');
  45
+    this.get('propertyPaths').forEach(function(propName) {
  46
+        this.context.removeObserver(this.property + '.' + propName, this, 'valueDidChange');
  47
+    }, this);
  48
+    this._super();
  49
+  }
  50
+
  51
+});
63  packages/ember-handlebars/tests/handlebars_test.js
@@ -1709,4 +1709,67 @@ test("should bind to the property if no registered helper found for a mustache w
1709 1709
   ok(view.$().text() === 'foobarProperty', "Property was bound to correctly");
1710 1710
 });
1711 1711
 
  1712
+test("should update bound helpers when properties change", function() {
  1713
+  Ember.Handlebars.registerBoundHelper('capitalize', function(value) {
  1714
+    return value.toUpperCase();
  1715
+  });
  1716
+  
  1717
+  view = Ember.View.create({
  1718
+    name: "Brogrammer",
  1719
+    template: Ember.Handlebars.compile("{{capitalize name}}")
  1720
+  });
  1721
+
  1722
+  appendView();
  1723
+  
  1724
+  ok(view.$().text() === 'BROGRAMMER', "helper output is correct");
  1725
+  
  1726
+  Ember.run(function() {
  1727
+    set(view, 'name', 'wes');
  1728
+  });
  1729
+  
  1730
+  ok(view.$().text() === 'WES', "helper output updated");
  1731
+});
  1732
+
  1733
+test("should update bound helpers when sub-properties change", function() {
  1734
+  Ember.Handlebars.registerBoundHelper('capitalizeName', function(value) {
  1735
+    return get(value, 'name').toUpperCase();
  1736
+  }, 'name');
  1737
+  
  1738
+  view = Ember.View.create({
  1739
+    person: Ember.Object.create({
  1740
+      name: 'Brogrammer'
  1741
+    }),
  1742
+    template: Ember.Handlebars.compile("{{capitalizeName person}}")
  1743
+  });
  1744
+
  1745
+  appendView();
  1746
+  
  1747
+  ok(view.$().text() === 'BROGRAMMER', "helper output is correct");
  1748
+  
  1749
+  Ember.run(function() {
  1750
+    set(view, 'person', Ember.Object.create({name: 'wes'}));
  1751
+  });
  1752
+  
  1753
+  ok(view.$().text() === 'WES', "helper output updated");
  1754
+});
  1755
+
  1756
+test("bound helpers should support options", function() {
  1757
+  Ember.Handlebars.registerBoundHelper('repeat', function(value, options) {
  1758
+    var count = options.count;
  1759
+    var a = [];
  1760
+    while(a.length < count){
  1761
+        a.push(value);
  1762
+    }
  1763
+    return a.join('');
  1764
+  });
  1765
+  
  1766
+  view = Ember.View.create({
  1767
+    text: 'ab',
  1768
+    template: Ember.Handlebars.compile("{{repeat text count=3}}")
  1769
+  });
  1770
+
  1771
+  appendView();
  1772
+  
  1773
+  ok(view.$().text() === 'ababab', "helper output is correct");
  1774
+});
1712 1775
 
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.