Circular bindings and transforms

by machty

HTML

<script src="https://github.com/downloads/wycats/handlebars.js/handlebars-1.0.0.beta.6.js"></script>
<script src="https://github.com/downloads/emberjs/ember.js/ember-1.0.pre.js"></script>
<script type="text/x-handlebars" data-template-name="application">

  Foo is: {{App.number}}<br/> 
  {{view Em.TextField valueBinding="App.moneyAsString"}}: vanilla Em.TextField<br/>
  {{view App.SlowTextField valueBinding="App.moneyAsString"}}: only updates on `change` event (losing focus)<br/>
  <input type="text" {{bindAttr value="App.moneyAsString"}}/>: raw input field with bindAttr value, can only respond to changes to App.number, can't cause them.<br/>

</script>

CSS

body {
  font-size: 13px;
  font-family: Arial, sans-serif;
}

JavaScript

App = Ember.Application.create({
  money: 1.23,
  
  // Formats numeric 'money' property as
  // 2-decimal string, and converts
  // strings to valid money.
  moneyAsString: function(key, value) {
    //console.log("(" + key + ", " + value + ")");
    
    var isSet = arguments.length === 2;
    if(!isSet) { value = this.get('money'); }
    
    // Stringify, remove non number characters...
    value = value.toString().replace(/[^0-9.]/g, '');
    
    // Make it a number.
    value = parseFloat(value);
    if(isNaN(value)) { value = 0; }
    
    // We've done everything we can to make sure it's a valid number.
    // If we're setting, now is the time to do it.
    if(isSet) { this.set('money', value) }
    
    // Whether it's get or set, we need to return the stringified
    // version of the valid number.
    return value.toFixed(2);
  }.property('money')
});

App.ApplicationView = Ember.View.extend({
  templateName: "application"
});
App.ApplicationController = Ember.Controller.extend();

App.SlowTextField = Ember.TextField.extend({
  
  // Override this method defined in TextSupport mixin.
  interpretKeyEvents: function(event) {
    var map = Ember.TextSupport.KEY_EVENTS;
    var method = map[event.keyCode];

    // Disabling this means the value only gets
    // propagated once the field loses focus.
    // this._elementValueDidChange();
    if (method) { return this[method](event); }
  }, 
  focusOut: function() {
    this.get('valueBinding').fromDidChange(this);
    //  fromDidChange: function(target) {
    //this._scheduleSync(target, 'fwd');
   //},

    //console.log("ASASD");
    //this.notifyPropertyChange('value');
    //this.set('value', 'barf');
    //debugger;
  }
});

App.Router = Ember.Router.extend({
  root: Ember.Route.extend()
});

App.initialize();