isEditing nested within an #each... unable to edit


#1

I’m having a problem trying to get my edit action working on a list created by #each model. When I take out the #each I obviously can’t see anything but my edit button works. Is it because within the #each the edit button needs to pass an ID through?

<script type="text/x-handlebars" data-template-name="clientTimeSheet">
{{#each model}}
{{#if isEditing}}
{{partial 'clientTimeSheet/edit'}}
<button {{action 'doneEditing'}}>Done</button>
{{else}}
<button {{action 'edit'}}>Edit</button>
{{/if}}
<table>
  <tr><td>{{timeLogDate}}</td></tr>
  <tr><td>{{firstName}}</td></tr>
  <tr><td>{{lastActivity}}</td></tr>
  <tr><td>{{timeIn}}</td></tr>
  <tr><td>{{timeOut}}</td></tr>
  {{#each activity in activities}}
    <tr><td>{{activity.content }}</tr></td>
  {{/each}}
  <tr><td>Ratio</td></tr>
</table>
{{/each}}
</script>

Is my nesting incorrect? I’m new to Ember + to JS so please go easy on me :slight_smile:


#2

Your edit and doneEditing actions are called on the controller. The controller won’t know which model you are trying to edit. You can pass a model to the {{action}} handler as the second argument. See the docs under “Additional parameters”.

So your template should look like this:

{{#each model}}
{{#if isEditing}}
{{partial 'clientTimeSheet/edit'}}
<button {{action 'doneEditing' this}}>Done</button>
{{else}}
<button {{action 'edit' this}}>Edit</button>
{{/if}}
....rest of template

And then handle it in your controller like this:

App.WhatheverController = Ember.ArrayController.extend({
  edit: function(item) {
    item.set('isEditing', true);
  },
  doneEditing: function() {
    item.set('isEditing', false);
    //Commit the record...
  }
});

Better solution

An even better solution would use the non-block version of {{each}} and use a separate controller and template for each item.

See this example: http://jsbin.com/epeyip/1/edit

If you have more questions, then please create a JS Bin or JSFiddle with an example. That makes it SO much easier for people to help you :smiley:


#3

Wow, thank seilund. I took a look at your JS Bin and man do I like how clean your code is. As a beggar looking for food, do you mind helping me understand this:

{{each model itemController="thing" itemViewClass="App.ThingView"}}

Why do you prefer separate controller and view? I mean, I understand that each model will get the same controller and view (at least in my case because it’s all the same thing). Do you mind clarifying the itemController and itemViewClass? I’ve looked at the API and it makes some sense but I’m seeking some plain joe terminology if possible.


#4

@DrewOJensen You’re very welcome.

Have you read http://emberjs.com/api/classes/Ember.Handlebars.helpers.html#method_each ?

The biggest issue with not using a controller per model in your case above, is that you put the isEditing property ON the model. It’s not the model’s property. What if you used the same model instance in multiple views where isEditing=true in one view does not imply that it should be editing in another view. Besides that it’s just cleaner and makes your code a bit more modular.


#5

Seilund, thanks again for the huge help. Since I’ve sort of already got your ear… it seems from the guides that a .find() with a parameter doesn’t work w/ the ember-data fixtures correct? I’m just trying to figure out the best way to retrieve data for a particular user. For example:

Clients have a #, and each job contains a client number. I want to return (display) job’s that are relevant to that client when I select their name.

I figure if I could just get a bump in the right direction on how to query fixtures (will be doing a rails back end eventually) but I was hoping to have it for fixtures so I can work locally and understand more of ember. I’m just not sure how to pass the data along when the client creates a new job and/or wants to retrieve previous jobs.


#6

I belive that you can simply override queryFixtures in DS.FixtureAdapter. See: https://github.com/emberjs/data/blob/master/packages/ember-data/lib/adapters/fixture_adapter.js#L53


#7

I saw that, but I’m just not sure how to over ride or what to do with that.


#8

You override a prototype method by calling reopen on the class itself:

DS.FixtureAdapter.reopen({
  queryFixtures: function(fixtures, query, type) {
    /*
    TODO: Return a new array that only contains the records from fixtures, that
    match your query. What that means is up to you.
    */
  }}
});

#9

As a n00b, I’m running into the same problem, found this post and thought my worries were over. I implemented this similarly in the app I’m working on, but that was a no-go. I then noticed that the JSBin sited above was using Ember 1.0.0.rc3 and I’m using rc6, so I changed the JSBin to use rc4, and the Output no longer rendered anything. Thus, I’m wondering how this same solution would work in newer versions of Ember…

Any chance I could get some love on this? I feel like I’m so close to wrapping my head around this stuff, but it’s not quite there…