Closed rickard2 closed 10 years ago
I believe this is a longstanding, known issue. See ember.js issue 1333 for discussion. They discuss some workarounds in the thread... I've switched to using non-async options for select boxes when possible, to avoid the issue altogether.
I'm having the same issue as you, they describe it as "not a bug" in https://github.com/emberjs/ember.js/issues/1333 but it's actually a pain.
It will also switch your select to an empty mode if you call model.save() since Ember Data will set your fields to a promise.
Tested with Ember 1.1.2 and ember data 1.0.0-beta3
@rickard2 your problem is that item.author
returns a PromiseObject
instead of the record, when the PromiseObject
is resolved, it set a record instance in the content
property. So you can update your code to use item.author.content
and will works.
Here is your updated jsbin http://emberjs.jsbin.com/uzUNaQA/6/edit
@marcioj that seems to solve the problem, still getting used to ember-data 1.0
thanks!
@marcioj & @rickard2 this is an Ember.select bug that we should fix. Please check embers issue list, if no similar issue exists please open one. That being said, I am pretty sure an issue such as this is already open.
There is a subtle issue with @marcioj solution to this one that I've tried to highlight: http://emberjs.jsbin.com/uzUNaQA/20/edit?html,js,output
If you do this with a fresh object that doesn't have the belongs to explicitly set to null, accessing the content property isn't going to do you much good.
If you do set the author to null when you instantiate the class, it goes through the correct setters and gives you an object with the content property of null.
The real issue comes in when you load an existing model with a null belongsTo because you can't reasonably force it though the setters and are therefore unable to manipulate the relationship. This isn't really a problem with the select or Ember Data (at least not a simple one), but it is a bit of an unintuitive incompatibility.
You can get around this by binding the properties to the controller and then manually setting them on the object, but it's not my favorite approach and I'd love to hear some alternatives.
I believe I have a similar issue here - http://stackoverflow.com/questions/22799094/setting-a-belongsto-attribute-via-an-action-on-controller-not-working/22799776?noredirect=1#comment34785844_22799776
Looking at the answer of this post, just having a selectionBinding attached to a belongsTo (async) of a model doesn't render the selection correctly.
I might be wrong in this so wanted to have a second opinion on it.
My solution for the time being is to do something like this on my controller:
# I have an ArrayController dedicated to the list
needs: ["selections"]
selections: Ember.computed.alias "controllers.selections"
selectedObject: null # so it doesn't get proxied to the model
objectSelected: (->
@set "myModelProperty", @get "selectedObject"
).observes "selectedObject"
I have selection=selectedObject
on the Select. And in the route:
setupController: (controller, model) ->
@_super controller, model
@store.findAll("selections").then (selections) =>
@controllerFor("selections").set "model", selections
# There needs to be a selection made even if the user doesn't touch the element
controller.set "selectedModel", investmentModels.get "firstObject"
Alright, I've made some progress on the workarounds to get this situation to work. I'm sure there are better ways to do this, but this is (so far) the only one I've found to cover all the problems without excessive manual intervention.
For existing records, you need to do something like the following in your route:
// your-route
beforeModel: function() {
var self = this;
return Em.RSVP.hash({
firstBelongsTo: this.store.find('first-belongs-to'),
secondBelongsTo: this.store.find('second-belongs-to')
}).then(function (models) {
self.controllerFor('this-route').setProperties(models);
});
And in your controller, be sure to declare the properties before setting them as Ember tries to throw then into content when they don't exist:
// your-controller
App.MyController = Ember.Controller.extend({
firstBelongsTo: null,
secondBelongsTo: null
});
By returning a promise in the beforeModel hook, you are telling the route to resolve the promise BEFORE loading the model, which also mean before any rendering occurs. This gives your application time to load the data up front before binding it to the select boxes.
New records present an unexpected quirk in this situation because the belongsTo
relationships aren't null, they are undefined. This (quietly) blows up the select boxes.
To solve this, I'm currently manually setting all of the relationships to null in the model hook:
// your-route
model: function() {
this.store.createRecord('your-record', {
firstbelongsTo: null,
secondBelongsTo: null
});
Not ideal, but by their powers combined, you can use async belongTo
without tossing weird proxy properties in your controller.
There is undoubtably more to this issue, but this seems to have drastically improved the situation for me.
Thanks for this @WMeldon. I ran into this problem recently and your comments helped me figure out what I was doing wrong.
Has this been fixed?
I'm also curious to know if this is something that will be fixed soon. Thanks.
Any news? :) :+1:
use relation.content
as the property path and all will work fine, ember select needs to be aware of async relationships, currently it doesn't monitor the change events correctly.
This is not an ember-data issue.
I don't know if this is the right place, so I posted my question at Stackoverflow also: http://stackoverflow.com/questions/26543093/how-to-preselect-a-value-on-an-ember-select-view
Thanks for your help. My select works now, but I don't know how to preselect a value dynamically - or isn't it possible at the moment?
This is my select:
{{view select
class="uk-width-1-1"
content=services
optionLabelPath="content.name"
optionValuePath="content.id"
prompt="Service"
selectionBinding="selectedService"
}}
It works fine when I try to get the current active value: this.get('selectedService')
, but when I try to set a specific customer, nothing happens:
var service = timetracking.get('service');
this.set('selectedService', service);
These are my models:
App.Timetracking = DS.Model.extend({
duration: DS.attr('number'),
day: DS.attr('date'),
notice: DS.attr('string'),
project: DS.belongsTo('project', {async: true}),
service: DS.belongsTo('service', {async: true}),
user: DS.belongsTo('user', {async: true})
});
App.Service = DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string'),
timetrackings: DS.hasMany('timetracking', {async: true}),
archived: DS.attr('boolean')
});
Thanks @stefanpenner !
I found using relation.content
works well with an alias on your controllers:
export default Ember.ObjectController.extend({
relation: Ember.computed.alias('content.relation.content')
});
Be aware the relation.content
trick will not work correctly if you are using a buffered proxy on your controllers since the extra .content
key path segment will effectively go via the proxy buffer to the underlying promise object content thus mutating the model directly. I was able to work around this issue with a computed property helper that uses the buffer value if its been set on the controller, and otherwise obtains the value from relation.content
.
As a result when using Ember.Select
in my templates I don't have to worry about async belongsTo relationships, they can just use selection=relation
until Ember.Select
is taught to handle promise proxies.
When you have a asynchronous belongsTo relationship and bind that to a
Ember.Select
it seems that the correct value is not selected in the view.Example here: http://emberjs.jsbin.com/uzUNaQA/1/
Tested with Ember Data Canary as of today and Ember 1.0.0