Adding Model to a hasmany relationship wont unpdate - ember.js

I am trying to add model to a hasmany relationship. In my route I have:
App.CourseRoute = Ember.Route.extend({
model: function(){
return this.store.find('course','-JNPcfHFQC8FNwyt_-Wh');
}
});
and in my controller I have a save action:
App.CourseController=Ember.ObjectController.extend({
actions: {
save: function() {
var _this = this;
var course = this.get('model');
_this.get('session').get('user').get("courses").pushObject(course)
_this.get('session').get('user').save()
}
}
});
The session property refers a global sessions object that is injected into the controller. This project is using firebase and emberFire data adapter. No errors are being thrown and no data is updated on the firebase backend. I can't seem to figure out what is going on.

Breakpoint your code before the save call and you'll probably see that this.get('session').get('user') has an isDirty property of false. So the save becomes a no-op. You can try to solve that by callingthis.get('session').get('user').notifyPropertyChange('courses').

Related

Show the newly created record on .save()

Ember 2.5
I have a page that displays a list of all types of commutes (/commutetypes). To create a new commute type, I go to commutetypes/new.
Once I save the new commute type and transition back to /commutetypes. The new commute type does not display on the list. Can I refresh the model to display it?
// save action in route.
save: function() {
var _this = this;
var com = this.store.createRecord('commutetype', {
name: document.getElementById('nameInput').value,
description: document.getElementById('descriptionInput').value
});
com.save().then(function(){
_this.transitionTo('commutetypes');
});
}
Added model for commutetypes route.
model: function(params) {
return Ember.RSVP.hash({
commutetypes: this.store.query('commutetype', params)
});
},
Can you try to pass in your model inside transitionTo. Also make sure that you endpoint returns a 201 with model instance
com.save().then(function(data){
_this.transitionTo('commutetypes', data);
}
I would also need to make sure that from server side you get instance of model back to ember.
Can you post your route code commute types...maybe you are not loading data there properly
hope it helps

How to remove a newly created model using Ember data?

I'm implementing a view for creating a new user.
App.UserNewRoute = Ember.Route.extend({
model : function(params) {
return this.store.createRecord('user');
}
});
On the UserNewController there is a method which is triggered if the user presses cancel.
App.UserNewController = Ember.ObjectController.extend({
//... code
actions: {
//.. other actions
cancel: function(){
var model = this.get('model');
model.destroyRecord();
this.transitionToRoute('users');
}
}
});
I'm always getting the following error:
Uncaught Error: Attempted to handle event `willCommit` on <App.User:ember751:null> while in state root.deleted.saved.
I've tried using an alternative:
model.deleteRecord();
model.save();
I get the same error.
What am I doing wrong?
The issue might have to do with the fact that model.destroyRecord() returns a promise and that you are transitioning before that promise fulfilled. I have been using the following:
var model = this.get('model');
var _this = this;
// assuming you are working with a new model and not on say an edit page
// this will delete the new record and once the promise returns will transition routes
if (model.get('isNew')) {
model.destroyRecord().then(function() {
_this.transitionToRoute('route name');
}
}
So that the transition only happens once the promise has been fulfilled. I am still an ember scrub but I figured it wouldn't hurt.
According to this https://github.com/emberjs/data/issues/1669, the issue might be already fixed in newer Ember versions. I'm using Ember version 1.5.1 and Ember-Data version 1.0.0-beta.6
The workaround was to do a dirty check.
var model = this.get('model');
model.deleteRecord();
if (model.get('isDirty')) {
model.save();
}
this.transitionToRoute('users');

Best Practice for Creating New Record with belongsTo Relationship

I am wondering about the best practice for creating a new record in Ember with createRecord() and then persisting it to the API? Specifically, should Ember's POST request generally be a single JSON that embeds all the model's relationships, or is it customary to POST each relationship individually?
In my code, I'm not able to get a single JSON, so I'm wondering if I'm missing the "Ember Way" or (more likely) I have a mistake in my code?
DETAILS:
Here are the details of my setup. I have two models:
/models/OrgUser.js:
DS.Model.extend({
...
orgPerson: DS.belongsTo('org-person', { inverse: 'org-user', async: true, embedded: 'always' }),
});
/models/OrgPerson.js:
DS.Model.extend({
...
orgUser: DS.belongsTo('org-user'),
})
I'm attempting to create a new user on the "Create New User" page. The route for that page is below. Is this the best place to call createRecord() for my new models?
/routes/org-users/add.js:
Ember.Route.extend({
model: function() {
var orgPerson = this.store.createRecord('org-person');
var orgUser = this.store.createRecord('org-user' );
orgUser.set('orgPerson', orgPerson);
return orgUser;
},
...
}
Using Chrome console to look at the orgUser object after I call set shows no evidence at all that I have added anything to orgUser. The "Ember" tab of Chrome Debug Tools does reflect the relationship, though.
On my "Create New User" page, my input fields all correspond to both OrgUser properties and OrgUser.OrgPerson properties. Here's an example:
/templates/org-users/add.hbs
...
{{input value=username}} // a property of OrgUser
{{input value=orgPerson.firstName}} // a property of OrgUser.orgPerson
...
In my route, when I go to save() Ember Data POSTs only the orgUser JSON with a null value for orgPerson. I'd like it to embed the orgPerson serialized object in the orgPerson property.
/routes/org-users/add.js:
Ember.Route.extend({
...
actions: {
submitForm: function() {
...
this.currentModel.save().then( onSuccess ).catch( onFailure );
...
}
}
});
This results in a POST request with the following body:
{
"orgUser":{
"username":"MyUsername",
"orgPerson":null,
"id":null
}
Note that orgPerson is null. Thanks in advance for any assistance!
UPDATE: Once again, I think I will need to take a fresh look at my serializer. Here's how it's currently defined.
/serializers/application.js:
DS.RESTSerializer.extend({
// Use the default approach to serializing, but add the id property
serialize: function(record, options) {
var json = this._super.apply(this, arguments);
json.id = record.id;
return json;
},
serializeBelongsTo: function(record, json, relationship) {
var key = relationship.key;
key = this.keyForRelationship ? this.keyForRelationship(key, 'belongsTo') : key;
var data = record.get('data');
if (relationship.options.embedded && relationship.options.embedded === 'always') {
json[key] = data[relationship.key] ? data[relationship.key].serialize( { includeId: true } ) : null;
}
else {
json[key] = data[relationship.key] ? data[relationship.key].get('id') : null;
}
if (relationship.options.polymorphic) {
this.serializePolymorphicType(record, json, relationship);
}
}
});
Per #Kingpin2k's comment, there appears to be some ambiguity (and bugs!) on how best to handle serialize() for a belongsTo relationship. My serializer customization above works great for records that are obtained through this.store.find(), but now I need to enable them for createRecord(). Additional suggestions, pointers are welcome!
It's a bug. https://github.com/emberjs/data/issues/1542#issuecomment-49443496
A workaround is to get the async belongsTo record before attempting to save (It tricks Ember Data into initializing it). In your case you could do it in the model hook.
model: function() {
var orgPerson = this.store.createRecord('org-person');
var orgUser = this.store.createRecord('org-user');
orgUser.set('orgPerson', orgPerson);
return orgUser.get('orgPerson').then(function(){
return orgUser;
});
},
So, I finally figured this out. With the release of Ember-Data-1.0.0-Beta.9, http://emberjs.com/blog/2014/08/18/ember-data-1-0-beta-9-released.html, the EmbeddedRecordsMixin has been introduced. This pretty much solves all my issues!
So, I wound up doing the following:
Upgraded to Ember-Data-1.0.0-Beta.9
Deleted my serializeBelongsTo customization from my serializer
I now define a custom serializer for each model using the EmbeddedRecordsMixin as documented at http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html.
This wound up working perfectly, because I get full declarative control over how and when my records are embedded.
Special thanks to #Kingpin2k for helping me realize my serializer was the problem and for the discussion to help me understand the options.

Getting model data from controller

In Ember if I have a model that is a list of users, if in the UsersController I do:
users = this.get('model');
users.map(function(user) {
user.name
});
should it not resolve the promise and return the user records? I'm confused on why this is not working for me, or how to get the model data the correct way. Thank you in advance.
The model promise is resolved by the router. Ember, by default, sets the controller's content property as the route's model unless you override the route's setupController() method. Your issue lies in the formatting of the map function.
It seems like you're using an array controller, because the model is an array, so do the following:
App.UsersController = Em.ArrayController.extend({
users: function() {
return this.map(function(user) {
return user.get('name');
});
}.property('#each.user'),
});
You can make this code even more streamlined by using Em.Array's mapBy() method, as follows:
App.UsersController = Em.ArrayController.extend({
users: function() {
return this.mapBy('name');
}.property('#each.user'),
});
If you're using the list of users in your template you can do this easily with a {{#each users}} helper. However, if you're using this list for other properties in the controller, be sure to to use the right observer to watch for items being added to the array:
someOtherProperty: function() {
var users = this.get('users');
// Do stuff with users array here...
}.observes('users.[]')
See setting up a route's model and setting up a controller if you're unfamiliar with how the models stuff works.

Duplicate null-id records in ember-data

I'm using ember 1.0 and ember-data 1.0.0 beta 1. I have the following routes and controller to create and save simple notes ('AuthenticatedRoute' is just a custom made route for logged-in users):
App.Note = DS.Model.extend({
title: DS.attr(),
author: DS.attr(),
body: DS.attr(),
createdAt: DS.attr()
});
App.NotesRoute = App.AuthenticatedRoute.extend({
model: function() { return this.store.find('note'); },
});
App.NotesNewRoute = App.AuthenticatedRoute.extend({
model: function() {
return this.store.createRecord('note');
}
});
App.NotesNewController = Ember.ObjectController.extend({
actions: {
save: function() {
var self = this, model = this.get('model');
model.set('author', localStorage.username);
model.set('createdAt', new Date());
model.save().then(function() {
self.get('target.router').transitionTo('notes.index');
});
}
}
});
When I save a new note everything works as expected. But when I navigate away from the notes route and then back into it, the notes list is populated with a duplicate entry. One entry has an id and can be edited, deleted etc, the other has all the data of the first entry except the id attribute is null. It seems to me ember-data keeps the newly created record (that hasn't been committed to the database and thus has no id yet) alive even when the record becomes committed but I am uncertain as to why. When I reload the page, the list is correctly displayed, no duplicates appear. What am I doing wrong?
For the record, I am using mongodb so I use a custom serializer to convert '_id' attributes to ember-data friendly 'id's, essentially copied from here:
App.NoteSerializer = DS.RESTSerializer.extend({
normalize: function(type, hash, property) {
// normalize the '_id'
var json = { id: hash._id };
delete hash._id;
// normalize the underscored properties
for (var prop in hash) {
json[prop.camelize()] = hash[prop];
}
// delegate to any type-specific normalizations
return this._super(type, json, property);
}
});
I should also mention that this problem existed in ember-data 0.13 as well.
It was a stupid mistake in my RESTful server. I was responding to POST requests with a 204 (empty) response instead of what ember-data expected, that is a 201 ("created") response with the newly created record as the payload. This post made me realize it.
It would be nice though to include this information in the official REST adapter documentation.
That is certainly strange behaviour indeed. Unfortunately I'm not able to explain why you're experiencing this, however:
You can use the willTransition callback in the actions object in your Route to ensure that when it is transitioned away from, if NotesNewController's content property is dirty (i.e. has not been persisted yet), it will have its transaction rolled back.
App.NotesNewRoute = App.AuthenticatedRoute.extend({
model: function() {
return this.store.createRecord('note');
},
actions: {
willTransition: function (transition) {
var model = this.controllerFor('notesNew').get('content');
if (model.get('isDirty') === true) {
model.get('transaction').rollback();
}
return this._super(transition);
}
}
});