2

I've followed the PeepCode tutorial on Ember.js, and am extending it to remove items from the tab. I'm also implementing a simple RESTful interface on the server to persist changes, and am using DS.RESTAdapter.

There are 2 relavent models:

  • TabItem
  • Tab, with a hasMany relationship to TabItem

Following on from the tutorial, I've added a simple remove link to the tab template:

<script type="text/x-handlebars" data-template-name="tab">
  <ul id="customer-tab">
    {{#each tabItem in tabItems}}
    <li>
      <h3><a href="#" {{ action "removeTabItem" tabItem }}>x</a> {{ tabItem.food.name }} <span>{{ money tabItem.cents}}</span></h3>
    </li>
    {{ else }}
      <li><h3>Click a food to add it</h3></li>
    {{/each}}
    <li id="total">
      <h3>Total <span>{{ money cents }}</span></h3></li>
    </li>
  </ul>
</script>

And in the controller

App.TabController = Ember.ObjectController.extend({
  removeTabItem: function(tabItem) {
    var store = this.get('store');
    store.transaction();
    var t = store.find(App.TabItem,tabItem.get('id'));
    t.deleteRecord();
    this.get('tabItems').removeObject(tabItem);
    store.commit();
  }
});

The above controller code I did by a bit of trial & error & guesswork. The "removeObject" call seems to be necessary to properly remove the item from the user interface, and the "deleteRecord" call seems to be necessary so "commit" will then result in a DELETE call to the server.

The controller code seems a bit long-winded though, and I suspect I'm missing something. Is there a way that is deemed better, maybe using the "tabItem" more directly, and using fewer API calls?

MilkyWayJoe
  • 9,082
  • 2
  • 38
  • 53
Michal Charemza
  • 25,940
  • 14
  • 98
  • 165

1 Answers1

0

To answer my own question:

  • The line:

    var t = store.find(App.TabItem,tabItem.get('id'));
    

    Was just unnecessary, and I could just used the tabItem passed to the method. So my TabController is now:

    App.TabController = Ember.ObjectController.extend({
      removeTabItem: function(tabItem) {
        var store = this.get('store');
        store.transaction();
        tabItem.deleteRecord();
        store.commit();
      }
    });
    
  • The Tab model has a "hasMany" relationship to the TabItem, but there was no automatic relationship back, so when a TabItem changed (or was deleted), then I'm suspect the Tab didn't "know" to redraw itself after a TabItem was deleted. Adding a "belongsTo" relationship to the TabItem seemed to sort this.

    App.TabItem = DS.Model.extend({
      tab: DS.belongsTo('App.Tab'),
      cents: DS.attr('number'),
      food: DS.belongsTo('App.Food')
    });
    
Michal Charemza
  • 25,940
  • 14
  • 98
  • 165
  • I went through a similar process. I found that I also needed to set the tab in the fixture data for each tabItem. The problem I'm seeing is that all the tabItems are removed instead of just the one item. Are you seeing that as well? – Jason Moore Mar 24 '13 at 16:00
  • @JasonMoore I've checked, and I never needed to set the tab in the fixture data for the tabItems. Also, I had problems "half" removing items, in that the data disappeared, but the list item remained, but I didn't have an issue with all the items being removed. – Michal Charemza Mar 24 '13 at 16:41
  • I added a breakpoint in the delete action, and by checking `tabItem.get('tab')` the fixture data doesn't have the tab defined, but dynamically created items do. I think I know what you mean with 'half' removing items - the item is removed, but the price remains, right? I wonder if there is some sort of order problem where the price is recalculated before the item is removed. I also get an error when clicking on another table and then back to the table 4 (with the fixture data): "Cannot call method 'hasOwnProperty' of undefined". Do you also see that when moving between tables? – Jason Moore Mar 25 '13 at 12:31