EmberJS Formatting hasMany relation - ember.js

I have the following model setup:
deliveryMethods: DS.hasMany("delivery-method", { async: true })
With this computed property:
### COMPUTED PROPERTIES ###
formattedDeliveryOptions: (->
#get('deliveryMethods').map((dm) ->
console.log dm.toJSON()
return { key: dm.get('name').underscore, value: dm.get('name') }
)
).property("deliveryMethods.#each")
And I am trying to access this property in a controller like so:
deliveryMethodsArray: (->
org = #get('controllers.application.currentOrganization')
console.log org.get('formattedDeliveryOptions')
return org.get('formattedDeliveryOptions')
).property()
But when the console.log dm.toJSON() runs, the organization property is set but nothing else. Not sure what I am doing wrong
console.log output:

Because the async is true, i believe you need to do a then() on the get promise.
org.get('formattedDeliveryOptions').then((fmtOpts) => { /* do something*/ });
Please excuse my syntax, you use a slightly different shorthand version than i do. The concept should be the same though.

Related

Ember hasMany relationship save on create

I'm trying to create an ember data record with a hasMany relationship from a POJO, and it's been remarkably difficult. This is using ember-concurrency (hence the task and yield syntax.
saveEntry: task(function* (obj){
let entry = yield this.model.get('entries').createRecord({
groupId: obj.objectID,
name: obj.name,
...
}).save();
obj.owner_ids.forEach((user_id) => {
this.store.findRecord('user', user_id).then((user) => {
entry.get('owners').pushObject(user);
entry.save();
});
})
}).drop();
So the tough bits are the 'obj.owner_ids', which is an array of user_ids. I add each to the array, but then need to save after every pushObject or it doesn't work. And even when it does work, it is throwing a bunch of network errors (probably due to race conditions on the save). There must be a better way, but I haven't found it.
I'm not sure what this.model represents in your code, but you could try fetching all of the users you need and then attaching them at the time you create and save like:
import { all } from 'rsvp';
saveEntry: task(function* (obj){
let users = obj.owner_ids.map(userId => this.store.findRecord('user', user_id));
let promises = this.model.get('entries').createRecord({
groupId: obj.objectID,
name: obj.name,
owners: users,
...
}).save()
// all() waits for an an array of promises to return
yield all(promises);
}).drop();

Ember-data peekRecord returns null [duplicate]

A lot of the other posts on this topic are 2+ years old, so here goes a potentially simple question.
I am using Ember data relationships to have a 'bizinfo' record belong to a 'user' record. Seems simple, but I am having the worst time of it.
In app/models/bizinfo.js I have the line:
'ownedBy': DS.belongsTo('user')
And in my route, where I validate and then save the model, I have the following code:
user_id: Ember.computed(function(){
return `${this.get('session.data.authenticated.user_id')}`;
}),
user: Ember.computed(function(){
return this.store.findRecord('user', this.get('user_id'));
}),
model(params){
return this.store.createRecord('bizinfo', {'ownedBy': this.get('user')});
},
at this point if I go into the Ember inspector to look at the 'bizinfo' data object, I see the following under the belongsTo tab:
ownedBy : <(subclass of Ember.ObjectProxy):ember1053>
Here is the code from my submit action:
submit() {
let model = this.currentModel;
console.log(model.ownedBy);
console.log(`what does the model look like?`);
console.log(model.toJSON());
model.validate().then(({model, validations}) => {
if (validations.get('isValid')) {
this.setProperties({
showAlert: false,
isRegistered: true,
showCode: false
});
let success = (response) => {
console.log(`Server responded with ${response.toJSON()}`);
};
let failure = (response) => {
console.log(`Server responded with ${response}`);
};
model.save().then(success, failure);
} else {
this.set('showAlert', true);
}
this.set('didValidate', true);
}, (errors) => {
console.log(`errors from failed validation: ${errors}`);
});
},
So here is the result of the first console.log statement:
ComputedProperty {isDescriptor: true, _dependentKeys: undefined, _suspended: undefined, _meta: Object, _volatile: false…}
And when I look at the model.toJSON() log, I see
ownedBy: null
Can anyone see what's going wrong here? Is it the create record statement? I have tried a lot of different permutations (such as submitting just the id as the 'user' parameter.
findRecord will return a promise. A simple way to get around the issue is
model(params){
return this.store.findRecord('user', this.get('user_id')) .
then(ownedBy => this.store.createRecord('bizinfo', {ownedBy});
}
This will wait for the findRecord to resolve, then return a new record with the resolved value as the ownedBy property.

Ember data dependent keys undefined

A lot of the other posts on this topic are 2+ years old, so here goes a potentially simple question.
I am using Ember data relationships to have a 'bizinfo' record belong to a 'user' record. Seems simple, but I am having the worst time of it.
In app/models/bizinfo.js I have the line:
'ownedBy': DS.belongsTo('user')
And in my route, where I validate and then save the model, I have the following code:
user_id: Ember.computed(function(){
return `${this.get('session.data.authenticated.user_id')}`;
}),
user: Ember.computed(function(){
return this.store.findRecord('user', this.get('user_id'));
}),
model(params){
return this.store.createRecord('bizinfo', {'ownedBy': this.get('user')});
},
at this point if I go into the Ember inspector to look at the 'bizinfo' data object, I see the following under the belongsTo tab:
ownedBy : <(subclass of Ember.ObjectProxy):ember1053>
Here is the code from my submit action:
submit() {
let model = this.currentModel;
console.log(model.ownedBy);
console.log(`what does the model look like?`);
console.log(model.toJSON());
model.validate().then(({model, validations}) => {
if (validations.get('isValid')) {
this.setProperties({
showAlert: false,
isRegistered: true,
showCode: false
});
let success = (response) => {
console.log(`Server responded with ${response.toJSON()}`);
};
let failure = (response) => {
console.log(`Server responded with ${response}`);
};
model.save().then(success, failure);
} else {
this.set('showAlert', true);
}
this.set('didValidate', true);
}, (errors) => {
console.log(`errors from failed validation: ${errors}`);
});
},
So here is the result of the first console.log statement:
ComputedProperty {isDescriptor: true, _dependentKeys: undefined, _suspended: undefined, _meta: Object, _volatile: false…}
And when I look at the model.toJSON() log, I see
ownedBy: null
Can anyone see what's going wrong here? Is it the create record statement? I have tried a lot of different permutations (such as submitting just the id as the 'user' parameter.
findRecord will return a promise. A simple way to get around the issue is
model(params){
return this.store.findRecord('user', this.get('user_id')) .
then(ownedBy => this.store.createRecord('bizinfo', {ownedBy});
}
This will wait for the findRecord to resolve, then return a new record with the resolved value as the ownedBy property.

Ember CLI Controller Test: Uncaught TypeError: Cannot read property 'transitionToRoute' of null

I have a controller I'm testing with Ember CLI, but the controller's promise will not resolve, as the controller's transitionToRoute method is returning null:
Uncaught TypeError: Cannot read property 'transitionToRoute' of null
login.coffee
success: (response) ->
# ...
attemptedTransition = #get("attemptedTransition")
if attemptedTransition
attemptedTransition.retry()
#set "attemptedTransition", null
else
#transitionToRoute "dashboard"
login-test.coffee
`import {test, moduleFor} from "ember-qunit"`
moduleFor "controller:login", "LoginController", {
}
# Replace this with your real tests.
test "it exists", ->
controller = #subject()
ok controller
###
Test whether the authentication token is passed back in JSON response, with `token`
###
test "obtains authentication token", ->
expect 2
workingLogin = {
username: "user#pass.com",
password: "pass"
}
controller = #subject()
Ember.run(->
controller.setProperties({
username: "user#pass.com",
password: "pass"
})
controller.login().then(->
token = controller.get("token")
ok(controller.get("token") isnt null)
equal(controller.get("token").length, 64)
)
)
When the line #transitionToRoute("dashboard") is removed, the test passes; otherwise, the test fails.
How can I fix this error, while still maintaining my controller logic?
Work around: bypass transitionToRoute if target is null. Something like:
if (this.get('target')) {
this.transitionToRoute("dashboard");
}
I ran into the same error and dug into Ember source code a little bit. In my case this error is thrown by ControllerMixin because get(this, 'target') is null at this line. The test module probably has no idea what target should be in a controller unit test like this without further context, so you may need to manually set it or just bypass it.
Since you're not interested in the transition itself, you can just stub out the transitionToRoute method on the controller.
JS:
test('Name', function() {
var controller = this.subject();
controller.transitionToRoute = Ember.K;
...
}
Coffee:
test "it exists", ->
controller = #subject()
controller.transitionToRoute = Ember.K
ok controller
Not sure why transitionToRoute method is undefined when you execute it within an unit test - it is probably related to the fact that the execution context is different.
One possible workaround to this would be if you move your transitionToRoute call to the route instead of it being in the controller. That way your controller will send action to its route and you'll keep routing only in the route.
There is a big discussion around which is better practice - routing from controller or not but this is another story.

How do I observe *all* property changes on a model object?

I have a model built from a JSON object.
// extend the json model to get all props
App.Model = Ember.Object.extend(window.jsonModel);
I want to automatically save the model when anything is updated. Is there any way I can add an observer to the whole model?
EDIT: // adding the solution I currently go
For now I do:
// XXX Can't be right
for (var prop in window.jsonModel) {
if (window.jsonModel.hasOwnProperty(prop)) {
App.model.addObserver(prop, scheduleSave);
}
}
This is a large form, which means I'm adding tons of observers – it seems so inefficient.
A firebug breakpoint at Ember.sendEvent() reveals that there are events called App.model.lastName:change being sent. I could hack in an intercept there, but was hoping for an official way.
You can bind to isDirty property of subclass of DS.Model. The isDirty changes from false to true when one of model properties changes. It will not serve well for all cases because it changes only once until reset or committed, but for your case -
I want to automatically save the model when anything is updated. Is there any way I can add an observer to the whole model?
it may work fine.
From the article:
autosave: function(){
this.save();
}.observes('attributes'),
save: function(){
var self = this,
url = this.get('isNew') ? '/todos.json' : '/todos/'+this.get('id')+'.json',
method = this.get('isNew') ? 'POST' : 'PUT';
$.ajax(url, {
type: 'POST',
// _method is used by Rails to spoof HTTP methods not supported by all browsers
data: { todo: this.get('attributes'), _method: method },
// Sometimes Rails returns an empty string that blows up as JSON
dataType: 'text',
success: function(data, response) {
data = $.trim(data);
if (data) { data = JSON.parse(data); }
if (self.get('isNew')) { self.set('id', data['todo']['id']); }
}
});
},
isNew: function(){
return !this.get('id');
}.property('id').cacheable(),
I had the same requirement, and not finding a suitable answer, I implemented one.
Try this: https://gist.github.com/4279559
Essentially, the object you want to observe all the properties of MUST be a mixed of Ember.Stalkable. You can observe the properties of that object as 'item.#properties' (or, if you bake observers directly on the Stalkable, '#properties' alone works. "#ownProperties", "#initProperties" and "#prototypeProperties" also work, and refer to (properties that are unique to an instance and not defined on any prototype), (properties that are defined as part of the create() invocation), and (properties that are defined as part of the class definition).
In your observers, if you want to know what properties changed and invoked the handler, the property "modifiedProperties", an array, will be available with the names of the changed properties.
I created a virtual property _anyProperty that can be used as a dependent key:
import Ember from 'ember';
Ember.Object.reopen({
// Virtual property for dependencies on any property changing
_anyPropertyName: '_anyProperty',
_anyProperty: null,
propertyWillChange(keyName) {
if (keyName !== this._anyPropertyName) {
this._super(this._anyPropertyName);
}
return this._super(keyName);
},
propertyDidChange(keyName) {
if (keyName !== this._anyPropertyName) {
this._super(this._anyPropertyName);
}
return this._super(keyName);
}
});