2
votes

I'm new to Ember and am finding some of their concepts a bit opaque. I have a app that manages inventory for a company. There is a screen that lists the entirety of their inventory and allows them to edit each inventory item. The text fields are disabled by default and I want to have an 'edit item' button that will set disabled / true to disabled / false. I have created the following which renders out correctly:

Inv.InventoryitemsRoute = Ember.Route.extend({
      model: function(params) {
            return Ember.$.getJSON("/arc/v1/api/inventory_items/" + params.location_id);
    }

<script type="text/x-handlebars" data-template-name="inventoryitems">
    {{#each}}
      <div class='row'>
          <p>{{input type="text" value=header disabled="true"}}</p>
          <p>{{input type="text" value=detail disabled="true"}}</p>
          <button {{action "editInventoryItem" data-id=id}}>edit item</button>
          <button {{action "saveInventoryItem" data-id=id}}>save item</button>
       </div>
    {{/each}}
</script>

So this renders in the UI fine but I am not sure how to access the specific model to change the text input from disabled/true to disabled/false. If I were just doing this as normal jQuery, I would add the id value of that specific model and place an id in the text input so that I could set the textfield. Based upon reading through docs, it seems like I would want a controller - would I want an ArrayController for this model instance or could Ember figure that out on its own?

I'm thinking I want to do something like the following but alerting the id give me undefined:

Inv.InventoryitemsController=Ember.ArrayController.extend({
    isEditing: false,

    actions: {
        editInventoryItem: function(){
          var model = this.get('model');  
          /*
          ^^^^
          should this be a reference to that specific instance of a single model or the list of models provided by the InventoryitemsRoute
          */
          alert('you want to edit this:' + model.id);  // <-undefined
        }
    }
});

In the Ember docs, they use a playlist example (here: http://emberjs.com/guides/controllers/representing-multiple-models-with-arraycontroller/) like this:

App.SongsRoute = Ember.Route.extend({
  setupController: function(controller, playlist) {
    controller.set('model', playlist.get('songs'));
  }
});

But this example is a bit confusing (for a couple of reasons) but in this particular case - how would I map their concept of playlist to me trying to edit a single inventory item?

2

2 Answers

1
votes

Ok, that's because as you said, you're just starting with Ember. I would probably do this:

<script type="text/x-handlebars" data-template-name="inventoryitems">
  {{#each}}
    <div class='row'>
      <p>{{input type="text" value=header disabled=headerEnabled}}</p>
      <p>{{input type="text" value=detail disabled=detailEnabled}}</p>
      <button {{action "editInventoryItem"}}>edit item</button>
      <button {{action "saveInventoryItem"}}>save item</button>
    </div>
  {{/each}}
</script>

with this, you need to define a headerEnabled property in the InventoryitemController(Note that it is singular, not the one that contains all the items), and the same for detailEnabled, and the actions, you can define them also either in the same controller or in the route:

App.InventoryitemController = Ember.ObjectController.extend({
  headerEnabled: false,
  detailEnabled: false,

  actions: {
    editInventoryItem: function() {
      this.set('headerEnabled', true);
      this.set('detailEnabled', true);
    }
  }
});

that's just an example how you can access the data, in case the same property will enable both text fields, then you only need one, instead of the two that I put . In case the 'each' loop doesn't pick up the right controller, just specify itemController.

2
votes
<script type="text/x-handlebars" data-template-name="inventoryitems">
    {{#each}}
      <div class='row'>
          <p>{{input type="text" value=header disabled="true"}}</p>
          <p>{{input type="text" value=detail disabled="true"}}</p>
          <button {{action "editInventoryItem" this}}>edit item</button>
          <button {{action "saveInventoryItem" this}}>save item</button>
       </div>
    {{/each}}
</script>

and

actions: {
    editInventoryItem: function(object){
      alert('you want to edit this:' + object.id);
    }
}

Is what you need. But let me explain in a bit more detail:

First of all, terminology: Your "model" is the entire object tied to your controller. When you call this.get('model') on an action within an array controller, you will receive the entire model, in this case an array of inventory items.

The {{#each}} handlebars tag iterates through a selected array (by default it uses your entire model as the selected array). While within the {{#each}} block helper, you can reference the specific object you are currently on by saying this. You could also name the iteration object instead of relying on a this declaration by typing {{#each thing in model}}, within which each object would be referenced as thing.

Lastly, your actions are capable of taking inputs. You can declare these inputs simply by giving the variable name after the action name. Above, I demonstrated this with {{action "saveInventoryItem" this}} which will pass this to the action saveInventoryItem. You also need to add an input parameter to that action in order for it to be accepted.