Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ember.js – Binding a button action from an #each loop to its own model

I can't seem to get a button, generated within an #each template loop, to bind its click action to its associated model. Here's a quick demo of the problem...

The Ember.js app setup:

window.Contacts = Ember.Application.create();

Contacts.Person = Ember.Object.extend({
    first: '',
    last: '',
    save: function() {
        // send updated information to server.
    }
});

Contacts.contactsList = Ember.ArrayController.create({
    content:[],
    init: function() {
        this.pushObject( Contacts.Person.create({
            first:'Tom',
            last:'Riddle'
        }));
    }
});

The template:

<script type="text/x-handlebars">
    {{#each Contacts.contactsList}}
    <li>
        {{view Ember.TextField valueBinding="first" viewName="firstname"}}
        {{view Ember.TextField valueBinding="last" viewName="lastname"}}
        <button {{action "save" on="click"}}>Save</button>
    </li>
    {{/each}}
</script>

The problem:

So, the idea in this simple demo scenario is that the "Save" button for each record will trigger an action to save the state of its own model. However, clicking the Save button gives an error:

Uncaught TypeError: Cannot call method 'call' of undefined

My assumption would be that specifying "save" as the button's action would bind it to the save method on its model. However, this does not appear to be the case. Some other object appears to be handling click actions, wherein a "save" hander is undefined. Am I missing something here? How could I make each line item's button call a handler on its own model?

Thanks in advance for any help!

like image 267
bigmac Avatar asked Jun 01 '12 14:06

bigmac


1 Answers

You can define a target of an action by setting the - surprise - target property, see http://jsfiddle.net/pangratz666/FukKX/:

<script type="text/x-handlebars" >
    {{#each Contacts.contactsList}}
    <li>
        {{view Ember.TextField valueBinding="first" viewName="firstname"}}
        {{view Ember.TextField valueBinding="last" viewName="lastname"}}
        {{#with this as model}}
            <button {{action "save" target="model"}}>Save</button>
        {{/with}}
    </li>
    {{/each}}
</script>​

The {{#with}} helper around the action is needed because somehow the action helper does not accept this as a target.


But a note to your design: actions should be called on views or on a controller. The target is then responsible for executing further actions like saving, ...

So I would implement your example as follows, see http://jsfiddle.net/pangratz666/U2TKJ/:

Handlebars:

<script type="text/x-handlebars" >
    {{#each Contacts.contactsList}}
    <li>
        {{view Ember.TextField valueBinding="first" viewName="firstname"}}
        {{view Ember.TextField valueBinding="last" viewName="lastname"}}
        <button {{action "save" target="Contacts.contactsController" }}>Save</button>
    </li>
    {{/each}}
</script>​

JavaScript:

Contacts.contactsController = Ember.Object.create({
    save: function(event) {
        console.log('do something with: ', event.context);
    }
});
like image 169
pangratz Avatar answered Sep 29 '22 08:09

pangratz