Understanding actions in components after 1.13


#1

Hi, I’d like to have some help understanding how I should handle one-way binding in components after 1.13.

For example, if I have a simple each in a template:

{{#each model as |item|}}
    {{editable-item item=item submit=(action 'saveItem')}}
{{/each}}

The component template has all display stuff but also allows users to edit item’s content and save the changes on the item pressing a button.

editable-item.hbs

{{item.title}}
{{input value=item.title enter='edit'}}
{{input value=item.foo enter='edit}}
{{input value=item.bar enter='edit}}

editable-item.js

import Ember from "ember";

export default Ember.Component.extend({
  actions: {
    edit() {
      this.attrs.submit(this.get('item'));
    }
  }
});

Should I send the item as parameter and then re-find it from the store on the route and finally save it to the server. Or should I send the submit function a parameter per each item field? Or is this all wrong? I’d like to know what’s the Ember way to handle actions now.

Thanks!


#2

You might want to take a look at the Improved Actions RFC that describes how the closure actions are designed to work.


#3

That looks all good except I’m not sure that the edit action in the component will be fired automatically as it is, to my knowledge, not a UI event.

Other than that, the way it is set up now, the saveItem action handler in your controller will receive the item that was edited/clicked/whatever and can then save it:

actions: {
  saveItem(item) {
    return item.save();
  }
}

#4

Curious why these are called “closure actions”. What is the closure, what is being closed over?

The RFC says

closed over functions

I have no idea what this means.


#5

They are closed over the variables in their (template) scope :slight_smile: including the scope.

// app/templates/application.hbs
{{! scope here is controller, the action helper creates a closure that binds the scope as oppose to...}}
{{#my-component do-things=(action "action")}}
{{/my-component}}

// app/templates/components/my-component.hbs
{{! the scope here is the component, the resulting closure binds the component as the action handler's "this" }}
{{yield (action "action")}}