13

I am trying to do something pretty basic with Ember and Ember Data.

1) Posts belongsTo Users; Users hasMany Posts

2) In the create new Post form, I want to have a select/dropdown of all Users

3) When I edit a post (using the same form), I want to bind it correctly back to the dropbox

Question: What is the best practice to do the dropdown that binds to the list of users? How can I bind the edit form to populate the dropdown again?

User Model:

App.User = DS.Model.extend({
  posts: DS.hasMany('post', {async: true}),
});

Post Model:

App.Post = DS.Model.extend(Ember.Validations.Mixin, {
  user: DS.belongsTo('user', {async: true}),
});

Create New Post Form:

{{view Em.Select
  content=users <<<<< How do I bind this.store.find("user") here?
  optionValuePath='content.id'
  optionLabelPath='content.name'
}}

I don't understand the best practice to bind the select content with users.

Attempt 1:

*I am using Ember-Form

  {{em-select
    property="user_id"
    label="user"
    prompt="Select user:"
    content=controllers.users.content
    optionValuePath="content.id"
    optionLabelPath="content.first_name"
  }}

And on the save action:

newItem.set('user', this.store.getById('user', this.get('user_id')));

I tried to use user_id as my property for the form, and translate back to a user object to assign to the post when I save. However, this method is kind of stupid because I am actively translating user_id to user object every time I save. I feel like there should be a way that that is done automatically if I did the correct binding, instead of jumping through hoops to bind the property as user_id. This also makes it hard for me to bind back when I use the same form for editing the post. Since all the relationship has been setup, I have a feeling that I am doing something wrong here. I think there must be a better way.

Thanks!

Min Ming Lo
  • 2,398
  • 2
  • 18
  • 25

4 Answers4

7

As of September 2014 there is an issue with Ember.Select plus { async: true }. They don't play well together.

myModel.get('myAsyncRel') will return a promise, Ember.Select is not promise aware, so it cannot handle this properly.

One workaround is to use a non-async relationship.

Another workaround is to use something like this:

sandstrom
  • 14,554
  • 7
  • 65
  • 62
2

The ember team has opened an issue (#5259) for this problem, they are planning to rewrite the whole Ember.Select part.

In the meantime you can use this Add-on from thefrontside:

{{#x-select value=bob action="selectPerson"}}
  {{#x-option value=fred}}Fred Flintstone{{/x-option}}
  {{#x-option value=bob}}Bob Newhart{{/x-option}}
{{/x-select}}

Install it with ember install emberx-select


EDIT As Stefan Penner wrote, you can now use the ember select as follows (jsbin):

<select onchange={{action "changed" value="target.value"}}>
    {{#each model.choices key="@identity" as |choice|}}
      <option value={{choice}} selected={{is-equal currentValue choice}}>{{choice}}</option>
    {{/each}}
</select>  
adriaan
  • 1,088
  • 1
  • 12
  • 29
  • Down voted your answer as it doesn't show how resolve the asynchronous belongsTo. – Denzo Aug 24 '15 at 05:33
  • Handlebars are able to resolve promises. So you can just do an each loop in the template with the `x-option` within the loop. So what do you mean with your comment? – adriaan Aug 24 '15 at 09:36
0

When you say dropdown I presume you mean a select box? Ember's API has a select view that handles all of the data binding. Here are the docs for Ember.Select.

You can use it in your post form like so:

{{view Em.Select
  content=users
  selection=user
  optionValuePath='content.id'
  optionLabelPath='content.name'
}}

If you're using Dockyard's awesome ember-easyForm library you can utilize an Em.Select like this:

{{input user type='as'
  collection='users'
  selection='user'
  optionValuePath='content.id'
  optionLabelPath='content.name'
  prompt='Choose type...'
}}

Advanced UI using Chosen can be easily integrated with Ember like this.

Duncan Walker
  • 2,182
  • 19
  • 28
  • Thanks for your response. My issue is not so much how to use the select view. I am already using ember-form select. My problem is trying to bind the users store to the selection itself. The Ember example demonstrate how to bind static data, but not data from the data store. I updated the question to make it much clearer now. Thanks! – Min Ming Lo Jul 16 '14 at 06:51
  • You would usually set that in your route using the `model` and/or `setupController` methods and the bindings update automatically. If your selection/content is a promise you can bind in your `Em.Select` using the `content` property (e.g. `selection=users` becomes `selection=users.content`). – Duncan Walker Jul 16 '14 at 15:32
  • I cannot bind the property `users` directly on the Select. Ember complains about `Uncaught Error: Assertion Failed: You can only add a 'user' record to this relationship` which is why I bind to a user_id, then adding it to the model when save `newItem.set('user', this.store.getById('user', this.get('user_id')));`. Again I think this method is too troublesome and I think there must be a direct easy binding method that I am missing out. – Min Ming Lo Jul 16 '14 at 20:14
  • Hmm. I bind to arrays from promises all the time. In the route's `setupController()` method: `this.store.find('user').then(function(users) { controller.set('users', users); });`. The `Em.Select` `content=users` or `content=users.content` binding automatically updates. I think there is something going wrong with your model and route. – Duncan Walker Jul 16 '14 at 20:36
  • @MinMingLo I've gotten the `Assertion Failed: You can only add a 'user' record to this relationship` from two scenarios. 1) I have not done the `this.store.find('user')` as Duncan Walker has stated; all the `users` must be in the store and accessible from a controller 2) When I left a parameter in the Handlebars `{{select ...}}` that shouldn't have been there. For example, if you have `selection=controller.user` then make sure you remove `value=model.user`. These have both caught me before and both cause that unhelpful Ember generated error, even with Ember Data 1.0.0-beta.11 – Eric D. Johnson Sep 11 '14 at 19:54
0

New deprecation information was added in Ember 1.13 for Ember Select, see http://emberjs.com/deprecations/v1.x/#toc_ember-select.

The new recommended approach in Ember 1.13/2.0 is to implement a component yourself:

e.g. /components/my-select.hbs

<select>
  {{#each users "id" as |user|}}
  {{log address}}
    <option value="{{user.id}}">
      user.name
    </option>
  {{/each}}
</select>

The ember link shows how to implement selection with selected={{is-equal item selectedValue}} and creation of a is-equal helper.

Adam Knights
  • 2,141
  • 1
  • 25
  • 48