0
votes

I have a simple example app I'm working on trying to learn Ember + Ember Data. If I set up my relationships in the model, I figured the first party Ember.Select object would manage the relationship, but I'm receiving errors.

For the selection content (options), I'm using an array (computed for sorting) set on the local/current controller, populating it within the route's setupController method, then using the model's relationship property as the the selection property on Ember.Select.

It throws an error on load for the 'New' route, but works on 'Edit' if relationship data already exists...but will throw an error when selecting the null/empty value (supplied with 'prompt' attribute.)

Should this work? Or is this not the Ember + Ember Data way?

Error on New:

Uncaught Error: Assertion Failed: The content property of DS.PromiseArray should be set before modifying it

Error on Edit when selecting prompt/null value:

Uncaught TypeError: Cannot read property 'constructor' of undefined

router.js

Router.map(function() {
    this.resource('menu-items', function(){
        this.route('new');
        this.resource('menu-item', { path: '/:menu-item_id' }, function() {
            this.route('edit');
        });
    });

    this.resource('food-groups', function(){
        this.route('new');
        this.resource('food-group', { path: '/:food-group_id' }, function() {
            this.route('edit');
        });
    });
});

models/menu-item.js

export default DS.Model.extend({
    title: DS.attr('string'),
    description: DS.attr('string'),
    foodGroups: DS.hasMany('food-group', { 'async': true })
});

models/food-group.js

export default DS.Model.extend({
    title: DS.attr('string'),
    description: DS.attr('string'),
    menuItems: DS.hasMany('menu-item')
});

routes/menu-items/new.js

export default Ember.Route.extend({
  model: function(){
    return this.store.createRecord('menu-item');
  },

  setupController: function (controller, model) {
    this._super(controller, model);

    controller.set('foodGroupsAll', this.store.find('food-group'));
  }
});

controllers/menu-items/new.js

export default Ember.ObjectController.extend({
  foodGroupsAll: Ember.A(),
  foodGroupsSorting: ['title:asc'],
  foodGroupsLookup: Ember.computed.sort('foodGroupsAll', 'foodGroupsSorting')

  // foodGroupsAllLog: function() {
  //   console.group(this.toString() + 'foodGroupsAllLog');
  //   console.log('foodGroupsAll', this.get('foodGroupsAll'));
  //   console.groupEnd();
  // }.property('foodGroupsAll'),

  // init: function() {
  //   this._super();
  //   console.group(this.toString() + ':init()');
  //   console.groupEnd();
  // }
});

templates/menu-items/new.js

<div class="form-group">
    <label for="input-food-groups" class="control-label">Food Group(s)</label>
    {{view Ember.Select 
        content=controller.foodGroupsLookup 
        selection=model.foodGroups 
        optionValuePath="content.id" 
        optionLabelPath="content.title" 
        prompt="Choose Food Group" 
        multiple="true" 
        class="form-control" 
        id="input-food-groups"}}
</div>

<dl>
    <dt>controller.foodGroupsLookup.length</dt>
        <dd>{{controller.foodGroupsLookup.length}}</dd>
    <dt>model.foodGroups.length</dt>
        <dd>{{model.foodGroups.length}}</dd>
</dl>

{{log ''}}
{{log 'NEW-FORM'}}
{{log 'form:foodGroupsLookup' foodGroupsLookup}}

Using:

DEBUG: -------------------------------
DEBUG: Ember      : 1.5.1 
DEBUG: Ember Data : 1.0.0-beta.8.2a68c63a
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery     : 1.11.1
DEBUG: -------------------------------
1

1 Answers

1
votes

Finally figured this one out. It's a known issue with current Ember.Select with multiple specified and models with async relationships:

Issue #2111: Ember.Select with multiple=true not working with async properties

The fix for now, until they refactor or release a separate select component, is to use the relationship's content property in the selection attribute.

Joe over at Ember discussion group laid out the solution clearly for me:

Rel == Relationship, in your case it would be foodGroups.content.

In ember data, related records are stored in a ManyArray which proxies the array and does some ED magic. When you declare aysnc: true, the ManyArray is again wrapped in a PromiseProxy. The select view doesn't seem to play nice with PromiseProxies.

My working select is now:

{{view Ember.Select 
    content=controller.foodGroupsLookup 
    selection=model.foodGroups.content 
    optionValuePath="content.id" 
    optionLabelPath="content.title" 
    prompt="Choose Food Group" 
    multiple="true" 
    class="form-control" 
    id="input-food-groups"}}