Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use one-way binding on emberjs?

I'm starting to play around with ember but one thing I haven't been able to wrap my head around is how to use one-way bindings, consider the following code:

HTML

<script type="text/x-handlebars">
    <h1>Some App</h1>
    <p>
        My Name is: {{name}}
    </p>
    <form {{action 'updateName' on="submit"}}>
        {{view Ember.TextField valueBinding="name"}}
        <input type="submit" value="Save">
    </form>
</script>

JS

var App = Ember.Application.create();

App.ApplicationRoute = Ember.Route.extend({
    model: function() {
        return {
            name: 'John Doe'   
        }
    },
    events: {
        updateName: function() {
            console.log('Name Updated!');   
        }
    }
});

JS Fiddle for reference

By default the Ember.TextField's value will be bound to my model and viceversa which means that when I type on the text the model and view will be updated live, however what I'm trying to do is bind the model to the textfield (so the initial name will be displayed) but update the model only when the form is submitted. Is there an easy way to do it?

Thanks in advance.

EDIT: Just for reference I updated my fiddle to use Ember.Binding.oneWay I think the end result is cleaner than @c4p answer: http://jsfiddle.net/X2LmC/3/ however I'm not sure if doing $('#user-name').val() to get the field value is the right way to do it.

like image 461
Javier Villanueva Avatar asked May 09 '13 16:05

Javier Villanueva


2 Answers

You can use an observer, an intermediate bound variable on the controller, and an event handler on the controller to accomplish what want to do.

The nameOnController property of the controller will be updated when the nameDidChange() observer fires, making sure that the nameOnController property will initialize to the model's name property and reflect any future changes to name. Bind this intermediate property to the TextField to insulate the name property from immediate typing changes and use an event on the controller to read and set the name attribute only when the button is clicked.

template:

{{view Ember.TextField valueBinding="nameOnController"}}

JS:

App.ApplicationController = Ember.ObjectController.extend({
    nameOnController: null,

    nameDidChange: function() {
      var name = this.get('name');
      this.set('nameOnController', name); 
    }.observes('name'),

    updateName: function() {
      var controllerName = this.get('nameOnController'); 
      this.set('name', controllerName);
    },

    setName: function() {
      this.set('name', "new name");
    }
});

update JSFiddle example

You can check that changes to the name property are still reflected in the text box by clicking the Set New Name button.

like image 181
CraigTeegarden Avatar answered Nov 10 '22 16:11

CraigTeegarden


Heres an updated solution.

I had a similar problem, that I needed a one way binding, but upon some action I needed the latest value. I also needed the current edited value. Below is my proof of concept --

http://emberjs.jsbin.com/nocadubixi/edit?html,js,output

Handlebars:

    <h1>Some App</h1>
    <p>My Name is: {{model.name}}</p>
    <p>current value: {{currentName}}</p>

    {{one-way-field id="user-name" source=model.name action='handleNameChange'}}
    <button {{action 'updateName'}}>Save</button>

JS:

App = Ember.Application.create();

App.ApplicationController = Em.Controller.extend({
    model: {
      name: 'John Doe'
    },
    actions: {
      updateName: function() {
        this.set('model.name', this.get('currentName'));
      },
      handleNameChange: function(newValue) {
        this.set('currentName', newValue);
      },

    }
});


App.OneWayFieldComponent = Ember.TextField.extend({
  valueBinding: Ember.Binding.oneWay('source'),
  onValueChange: function() {
    this.sendAction('action', this.get('value'));
  }.observes('value'),
});
like image 1
hewsonism Avatar answered Nov 10 '22 15:11

hewsonism