Set multiple data with Ember and make it persist on Firebase - ember.js

I am trying to set data from two models (that has hasMany & belongsTo relationship) and save them to firebase.
'list' data ends up being saved to firebase but not user data.
I think I'm doing something wrong at step 3. I'd appreciate your help!
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.find('list');
},
actions: {
createList: function() {
var newListTitle = this.controllerFor('lists').get('newListTitle');
var username = this.get('session.user.displayName');
alert(this.get('session.user.displayName'));
if (Ember.isBlank(newListTitle)) { return false; }
//1
var list = this.store.createRecord('list', {
title: newListTitle,
user: username,
});
//2
this.controllerFor('lists').set('newListTitle', '');
var _this = this;
//3
list.save().then(function(list) {
user.get('lists').addObject(list);
user.save();
_this.transitionTo('lists.show', list); //4
});
}
}
});

Restructured your adding logic as well as user defined models, also modified your route, which could look like this in Edit and View mode. Meaning you can have more than one item returned from "model".
// Update models
App.List = DS.Model.extend({
value: DS.attr('string')
});
App.User = DS.Model.extend({
name: DS.attr('string')
});
App.UserLists = DS.Model.extend({
user: DS.belongsTo('user'),
list: DS.belongsTo('list')
});
export default Ember.Route.extend({
LIST:SHOW ROUTE
model: function(params) {
var store = this.get('store');
var userPromise = store.find('user', params.id);
return Ember.RSVP.hash({
user: userPromise,
userList : userPromise.then(function(user) {
return store.find(userList, { WhereUserIdIs : user.get('id') })
});
});
},
actions: {
createList: function() {
var self = this;
var failure = function(reason) {
// handle stuff
};
var list = this.store.createRecord('list', {
title: this.get('title'),
});
var user = this.get('user');
var usersList = store.createRecord('userList', {
'user': user,
'list': list
});
list.save().then(function(list) {
user.save().then(function() {
userList.save().then(function() {
self.transitionTo('lists.show', list.get('id'));
}, failure);
}, failure);
}, failure);
}
});

Related

How do you save a many-to-many relationship in Ember and Firebase

Let's say we have many medicines that can be prescribed to many patients. Our model would look like this:
App.Medicine = DS.Model.extend({
name: DS.attr(),
patients: DS.hasMany('user', { async: true }),
});
App.User = DS.Model.extend({
name: DS.attr(),
medicines: DS.hasMany('medicine', { async: true })
});
In this scenario, how do we save records to a Firebase store?
App = Ember.Application.create();
App.ApplicationAdapter = DS.FirebaseAdapter.extend({
firebase: new Firebase('https://YOUR_FIREBASE.firebaseio.com/')
});
App.Router.map(function(){ });
App.Medicine = DS.Model.extend({
name: DS.attr(),
patients: DS.hasMany('user', { async: true }),
});
App.User = DS.Model.extend({
name: DS.attr(),
medicines: DS.hasMany('medicine', { async: true })
});
App.IndexRoute = Ember.Route.extend({
model: function() {
var medicines = this.store.find('medicine');
var users = this.store.find('user');
return {
medicines: medicines,
users: users
};
},
actions: {
savePost: function(){
var store = this.store;
var medicine1 = store.createRecord('medicine', {name: 'aspirin'});
var patient1 = store.createRecord('user', {name: 'Jane'});
var patient2 = store.createRecord('user', {name: 'Peter'});
medicine1.save()
.then(function(){
return Ember.RSVP.Promise.all([
patient1.save(),
patient2.save()
])
.then(function(){
var promises = [];
var patientsOfMedicine1 = medicine1.get('patients');
var medicinesOfPatient1 = patient1.get('medicines');
var medicinesOfPatient2 = patient2.get('medicines');
promises.push(patientsOfMedicine1, medicinesOfPatient1, medicinesOfPatient2);
return Ember.RSVP.Promise.all(promises);
})
.then(function(arrayOfAttachedArrays){
var promises = [];
var patientsOfMedicine1 = arrayOfAttachedArrays[0];
var medicinesOfPatient1 = arrayOfAttachedArrays[1];
var medicinesOfPatient2 = arrayOfAttachedArrays[2];
patientsOfMedicine1.addObjects(patient1, patient2);
medicinesOfPatient1.addObject(medicine1);
medicinesOfPatient2.addObject(medicine1);
promises.addObjects(medicine1.save(),patient1.save(),patient2.save());
return Ember.RSVP.Promise.all(promises);
});
});
}
}
});
Notes:
Thanks to David Govea for showing me how this works.
If there's a better way to do this, please post below.

store.updateRecord is not a function in ember.js

I am newbie to ember.js, I am using ember-1.9.1.js and ember-data for my project.
For back-end configuration I have created a REST API with core php and the db is MySQL.
Now I can create new records (posts) from client side using with DS.RESTAdapter's "createRecord" function.
But I don't know how to update a Record (post) with DS.RESTAdapter's "updateRecord" function.
When I try to call the "updateRecord" function from "App.PostController (doneEditing)" I got this error:
Uncaught TypeError: store.updateRecord is not a function --------- app.js
app.js code below
App = Ember.Application.create();
App.IndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('home');
}
});
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'pran/webapp/rest_adapter/api',
createRecord: function(store, type, snapshot) {
var data = this.serialize(snapshot, { includeId: true });
var url = "api/new_post";
return new Ember.RSVP.Promise(function(resolve, reject) {
jQuery.ajax({
type: 'POST',
url: url,
dataType: 'json',
data: data
}).then(function(data) {
Ember.run(null, resolve, data);
}, function(jqXHR) {
jqXHR.then = null; // tame jQuery's ill mannered promises
Ember.run(null, reject, jqXHR);
});
});
},
updateRecord: function(store, type, snapshot) {
var data = this.serialize(snapshot, { includeId: true });
var id = snapshot.id;
var url = [type, id].join('/');
return new Ember.RSVP.Promise(function(resolve, reject) {
jQuery.ajax({
type: 'PUT',
url: url,
dataType: 'json',
data: data
}).then(function(data) {
Ember.run(null, resolve, data);
}, function(jqXHR) {
jqXHR.then = null; // tame jQuery's ill mannered promises
Ember.run(null, reject, jqXHR);
});
});
}
});
App.Store = DS.Store.extend({
revision: 12,
adapter: 'App.ApplicationAdapter'
});
App.Post = DS.Model.extend({
title: DS.attr('string'),
author: DS.attr('string'),
date: DS.attr('date'),
excerpt: DS.attr('string'),
body: DS.attr('string')
});
App.Router.map(function() {
this.resource('home');
this.resource('about');
this.resource('posts', function(){
this.resource('post', { path: ':post_id' });
});
this.resource('newstory' , {path : 'story/new'});
});
App.PostsRoute = Ember.Route.extend({
model: function() {
return this.store.filter('post', { id: true }, function(post) {
return post.get('id');
return this.store.find('post');
});
}
});
App.PostRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('post', params.post_id);
}
});
App.NewstoryController = Ember.ObjectController.extend({
actions :{
save : function(){
var title = $('#title').val();
var author = $('#author').val();
var excerpt = $('#excerpt').val();
var body = $('#body').val();
var store = this.get('store');
var new_post = store.createRecord('post',{
title : title,
author : author,
date : new(Date),
excerpt : excerpt,
body : body
});
new_post.save();
this.transitionToRoute('posts');
}
}
});
App.PostController = Ember.ObjectController.extend({
isEditing: false,
actions: {
edit: function() {
this.set('isEditing', true);
},
doneEditing: function() {
this.set('isEditing', false);
var title = $('#title').val();
var excerpt = $('#excerpt').val();
var body = $('#body').val();
var store = this.get('store');
var update_post = store.updateRecord('post',{
title : title,
excerpt : excerpt,
body : body
});
update_post.save();
}
}
});
Somebody please suggest a way to fix the issue.
updateRecord is adapter's method not store's
so try next:
store.adapterFor(App.Post).updateRecord(...
this is fast fix
And better create Post object and call method .save() - it's not good practice to work with adapter from controller like
App.Post.create({
title : title,
excerpt : excerpt,
body : body
}).save();
P.S. The final solution was
App.NewstoryController = Ember.ObjectController.extend({
actions :{
save : function(){
var title = $('#title').val();
var author = $('#author').val();
var excerpt = $('#excerpt').val();
var body = $('#body').val();
var store = this.get('store');
var new_post = store.createRecord('Post',{
title : title,
author : author,
date : new(Date),
excerpt : excerpt,
body : body
});
new_post.save();
this.transitionToRoute('posts');
}
}
});

Model is empty after update but data is saved to the database and shown on reload

I'm updating a model using the following controller:
payment_controller.js
App.PaymentNewController = Ember.ObjectController.extend({
needs: ['student'],
isNew: true,
actions: {
createPayment: function() {
var date = new Date(this.get('date'));
if (!date) { return false; }
var amount = this.get('amount');
if (!amount) { return false; }
var studentId = this.get('controllers.student.id');
if (this.isNew)
{
var payment = this.store.createRecord('payment', {
date: date,
amount: amount,
});
}
else
{
var payment = this.get('model');
payment.set('date', date);
payment.set('amount', amount);
}
var self = this;
var onSuccess = function(payment) {
self.set('date', '');
self.set('amount', '');
self.transitionToRoute('student', studentId);
};
var onFail = function(payment) {
};
if (this.isNew)
{
this.store.find('student', studentId).then(function(student){
payment.set('student', student);
payment.save().then(onSuccess, onFail);
});
}
else
{
payment.save().then(onSuccess, onFail);
}
},
}
});
The data returned from the server is the following, and it looks in the correct format expected by ember:
{"payment":{"amount":1111,"date":"2014-09-09T00:00:00.000Z","student":"54024bb9cd52254e181325af","_id":"54024bdacd52254e181325b0"}}
The issue is that after saving the data is correctly saved to the database, but in the store is empty (UPDATE: except the id). As soon as I reload the page the data is shown correctly and is the updated version of the model. This made me think to the fact that the error could lie in the response of the PUT request, but it looks fine to me.
I've been trying many different things with no success. I can provide additional code or info if needed.
UPDATE 1
Here are the involved routes:
App.StudentsRoute = Ember.Route.extend({
model: function() {
return this.store.find('student');
}
});
App.StudentRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('student', params.student_id);
}
});
App.StudentEditRoute = Ember.Route.extend({
setupController: function(controller, model) {
this.controllerFor('student.new').setProperties({isNew:false, content:model});
},
renderTemplate: function() {
this.render('student/new');
}
});
App.PaymentNewRoute = Ember.Route.extend({
model: function() {
return this.store.createRecord('payment');
}
});
App.PaymentEditRoute = Ember.Route.extend({
setupController: function(controller, model) {
this.controllerFor('payment.new').setProperties({isNew:false, content:model});
},
renderTemplate: function() {
this.render('payment/new');
}
});
UPDATE 2
Here are the serializer and the adapter:
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: 'http://localhost:3000',
});
App.ApplicationSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
primaryKey: '_id',
serializeId: function(id) {
return id.toString();
},
attrs: {
payments: {embedded: 'always'},
lessons: {embedded: 'always'}
}
});
UPDATE 3
Here are the models:
App.Student = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
email: DS.attr('string'),
nationality: DS.attr('string'),
dateOfBirth: DS.attr('date'),
payments: DS.hasMany('payment'),
lessons: DS.hasMany('lesson'),
});
App.Payment = DS.Model.extend({
student: DS.belongsTo('student'),
date: DS.attr('date'),
amount: DS.attr('number'),
});
UPDATE 4
While inspecting the store using the Ember Inspector in Chrome I've noticed that after the update is completed, the only property that contains data in the payment object (in the store) is the id. Both date and amount are empty.

model returns null on controller

i'm working with a a router and a controller, and i need to complete some operations on the controller, this is my model code
AcornsTest.StockRoute = Ember.Route.extend({
model: function(params) {
"use strict";
var url_params = params.slug.split('|'),
url = AcornsTest.Config.quandl.URL + '/' + url_params[0] + '/' + url_params[1] + '.json',
stockInStore = this.store.getById('stock', url_params[1]),
today = new Date(),
yearAgo = new Date(),
self = this;
yearAgo.setFullYear(today.getFullYear() - 1);
today = today.getFullYear()+'-'+today.getMonth()+'-'+today.getDate();
yearAgo = yearAgo.getFullYear()+'-'+yearAgo.getMonth()+'-'+yearAgo.getDate();
if(stockInStore && stockInStore.get('data').length) {
return stockInStore;
}
return Ember.$.getJSON(url,{ trim_start: yearAgo, trim_end: today, auth_token: AcornsTest.Config.quandl.APIKEY })
.then(function(data) {
if(stockInStore) {
return stockInStore.set('data', data.data);
} else {
return self.store.createRecord('stock', {
id: data.code,
source_code: data.source_code,
code: data.code,
name: data.name,
description: data.description,
display_url: data.display_url,
source_name: data.source_name,
data: data.data,
slug: data.source_code+'|'+data.code
});
}
});
}
});
and this is my controller
AcornsTest.StockController = Ember.ObjectController.extend({
init: function() {
"use strict";
this.send('generateChartInfo');
},
actions: {
generateChartInfo: function() {
"use strict";
console.log(this.model);
console.log(this.get('model'));
}
}
});
from the controller i'm trying to get access to the model to get some information and format it, and send it to the view
but this.model or this.get('model') always returns null, how can i successful get access to the model from the controller? thanks
You are overriding the init method, but its broken, do this:
AcornsTest.StockController = Ember.ObjectController.extend({
init: function() {
"use strict";
this._super();
this.send('generateChartInfo');
});
You need to call the parent method.
See this test case: http://emberjs.jsbin.com/gijon/3/edit?js,console,output
The model is not ready at init time. If anyone has official docs please share.

Why don't nested resources in Ember.js preserve the params hash?

Given the following Ember.js application (using Ember 1.0.0.rc.6.1 and Ember Data 0.13):
App = Ember.Application.create({ LOG_TRANSITIONS: true });
App.Store = DS.Store.extend();
App.Router.map(function() {
this.resource('promotions', function() {
this.resource('promotion', { path: '/:promotion_id' }, function() {
this.resource('entrants', function() {
this.resource('entrant', { path: '/:entrant_id' });
});
});
});
});
App.PromotionRoute = Ember.Route.extend({
model: function() {
return { id: 1, name: 'My Promotion' };
}
});
App.EntrantsIndexRoute = Ember.Route.extend({
model: function(params) {
console.warn('EntrantsIndexRoute', '\nparams:', params, '\nparams.promotion_id:', params.promotion_id, '\narguments:', arguments);
console.log('params should be:', { promotion_id: 1 });
console.log('The queried URL should be:', '/entrants?promotion_id=1');
return App.Entrant.find({promotion_id: params.promotion_id});
}
});
App.Entrant = DS.Model.extend({
name: DS.attr('string')
});
If you enter the url #/promotions/1/entrants, which should be a nested resource, the params is an empty object. How can I access promotion_id there? JSFiddle here, take a look at the console after clicking on "Click me": http://jsfiddle.net/Kerrick/4GufZ/
While you can't access the dynamic segments of the parent route, you still can retrieve the model for the parent route and get its ID, like this:
App.EntrantsIndexRoute = Ember.Route.extend({
model: function() {
var promotion_id = this.modelFor('promotion').id;
return App.Entrant.find({ promotion_id: promotion_id });
}
});
Or, if there is a has-many relation between promotion and entrants, you even might do:
App.EntrantsIndexRoute = Ember.Route.extend({
model: function() {
return this.modelFor('promotion').get('entrants');
}
});
Try this code:
App.EntrantsIndexRoute = Ember.Route.extend({
model: function() {
var promotion_id = this.modelFor('promotion').query.promotion_id;
return App.Entrant.find({ promotion_id: promotion_id });
}
});