ember.js can't get pagination from metadata - ember.js

I do an example like this,but still can't get pagination
this is my store.js.coffee
Eme.serializer = DS.RESTSerializer.create()
Eme.serializer.configure
meta: 'meta'
pagination: 'pagination'
Eme.CustomAdapter = DS.RESTAdapter.extend
serializer: Eme.serializer
namespace: "api/v1"
Eme.Store = DS.Store.extend
revision: 13
adapter: 'Eme.CustomAdapter'
this is my controller
Eme.PluginsController = Em.ArrayController.extend
content: []
pagination: (->
if this.get('model.isLoaded')
console.log #get('model.type')
console.log #get('store').typeMapFor(modelType).metadata
modelType = #get('model.type')
#get('store').typeMapFor(modelType).metadata.pagination
).property('model.isLoaded')
this is response
{
"meta":{
"pagination":{
"total_count":16,
"total_pages":2,
"current_page":1
}
},
"plugins":[{
"id":"1",
"name":"zhangsan",
}]
}
this is my log:
Eme.Plugin
Object {}

In the example you pasted, the modelType variable is output to console before it has been defined. That could be why you are not seeing the pagination data as expected.
I've created a jsbin with a slightly modified version of your code and it appears to output pagination data correctly. See: http://jsbin.com/anIKAfO/2/edit
App = Ember.Application.create({});
App.IndexRoute = Ember.Route.extend({
model: function(){
return App.Plugin.find();
}
});
App.IndexController = Ember.ArrayController.extend({
pagination: function() {
if (this.get('model.isLoaded')) {
var store = this.get('store');
modelType = this.get('model.type');
console.log('modeltype: ', this.get('model.type'));
var metadata = store.typeMapFor(modelType).metadata;
console.log('metadata: ', metadata);
return metadata.pagination;
}
}.property('model.isLoaded')
});
App.Store = DS.Store.extend({
adapter: 'App.Adapter'
});
App.Plugin = DS.Model.extend({
name: DS.attr('string')
});
App.serializer = DS.RESTSerializer.create();
App.serializer.configure({
meta: 'meta',
pagination: 'pagination'
});
App.Adapter = DS.RESTAdapter.extend({
serializer: App.serializer,
ajax: function(url, type, hash) {
console.log('App.Adapter.ajax:', url, type, hash);
json = App.RESTDATA[url];
if (json) {
console.log('App.Adapter.ajax: Found RESTDATA: ', json);
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.run(null, resolve, json);
});
} else {
console.log('App.Adapter.ajax: No RESTDATA for url, calling API', url);
return this._super(url, type, hash);
}
}
});
App.RESTDATA = {
'/plugins':
{
"meta":{
"pagination":{
"total_count":16,
"total_pages":2,
"current_page":1
}
},
"plugins":[{
"id":"1",
"name":"zhangsan"
}]
}
};

Related

Set multiple data with Ember and make it persist on Firebase

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);
}
});

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.

Sending REST requests to a nested API endpoint URL using Ember Data

If you imagine two models defined thus:
App.User = DS.Model.extend({
emails: DS.hasMany('email', {embedded: 'always'}),
});
App.Email = DS.Model.extend({
address: DS.attr('string'),
alias: DS.attr('string'),
user: DS.belongsTo('user')
});
... and a REST Adapter:
App.UserAdapter = DS.RESTAdapter.extend({
url: 'http://whatever.com',
namespace: 'api/v1'
});
... with routing set up like so:
App.Router.map(function () {
this.route('index', { path: '/' });
this.resource('users', function () {
this.route('index');
this.route('add');
this.resource('user', { path: ':user_id' }, function () {
this.route('delete');
this.route('edit');
this.resource('emails', function () {
this.route('index');
this.route('add');
this.resource('email', { path: ':email_id' }, function () {
this.route('delete');
this.route('edit');
});
});
});
});
});
... and a controller action to save the edited email, which looks like this:
App.EmailEditController = Ember.ObjectController.extend({
actions: {
save: function () {
var self = this;
var email = this.get('model');
email.save().then(function(){
self.transitionToRoute('email', email);
});
}
}
});
The issue is this...
The PUT request is being sent to: http://whatever.com/api/v1/emails/[email_id]
However the correct API endpoint is: http://whatever.com/api/v1/users/[user_id]/emails/[email_id]
What is the correct way to remedy this issue?
The solution I came up with was just to rewrite createRecord, updateRecord and deleteRecord in the REST adapter.
I added a 'parent' attribute to the models affected. In the *Record hooks, I can check if this is set and edit the path sent to buildURL accordingly.
My createRecord, updateRecord and deleteRecord hooks now looks something similar to this:
App.UserAdapter = DS.RESTAdapter.extend({
createRecord: function (store, type, record) {
if (!record.get('parent') || null === record.get('parent')) {
return this._super(store, type, record);
}
var data = {};
var serializer = store.serializerFor(type.typeKey);
var parent_type = record.get('parent');
var parent_id = record.get(parent_type).get('id');
var child_type = Ember.String.camelize(
Ember.String.pluralize(
type.typeKey.split(
record.get('parent')
).pop()
)
);
var path = Ember.String.pluralize(parent_type) + '/' + parent_id + '/' + child_type;
serializer.serializeIntoHash(data, type, record, { includeId: true });
return this.ajax(this.buildURL(path), "POST", { data: data });
},
updateRecord: function(store, type, record) {
if(!record.get('parent') || null === record.get('parent')){
return this._super(store, type, record);
}
var data = {};
var serializer = store.serializerFor(type.typeKey);
var parent_type = record.get('parent');
var parent_id = record.get(parent_type).get('id');
var child_type = Ember.String.camelize(
Ember.String.pluralize(
type.typeKey.split(
record.get('parent')
).pop()
)
);
var path = Ember.String.pluralize(parent_type) + '/' + parent_id + '/' + child_type;
serializer.serializeIntoHash(data, type, record);
var id = record.get('id');
return this.ajax(this.buildURL(path, id), "PUT", { data: data });
},
deleteRecord: function (store, type, record) {
if (!record.get('parent')) {
return this._super(store, type, record);
}
var parent_type = record.get('parent');
var parent_id = record.get('parent_id');
var child_type = Ember.String.camelize(
Ember.String.pluralize(
type.typeKey.split(
record.get('parent')
).pop()
)
);
var path = Ember.String.pluralize(parent_type) + '/' + parent_id + '/' + child_type;
var id = record.get('id');
return this.ajax(this.buildURL(path, id), "DELETE");
}
});
The Email model in the example would be something like:
App.Email = DS.Model.extend({
address: DS.attr('string'),
alias: DS.attr('string'),
user: DS.belongsTo('user'),
parent: 'user'
});
I solved this by overriding the buildURL method in model-specific adapters when required, using a mixin to encapsulate the method. Basically, it uses the default method to get the URL built according to Ember's rules and then it slices and puts additional info in place. Of course, this works because in buildURL we have access to the record...
Here is the basic idea in CoffeeScript:
module.exports = App.RestWithParentMixin = Ember.Mixin.create
host: App.Environment.get('hostREST')
namespace: App.Environment.get('apiNamespace')
ancestorTypes: null
buildURL: (type, id, record) ->
url = #_super(type, id, record)
ancestorTypes = #get('ancestorTypes')
if ancestorTypes == null
urlFixed = url
else
urlPrefix = #urlPrefix()
urlWithoutPrefix = url.slice(urlPrefix.length)
ancestry = []
ancestorTypes
if not Array.isArray(ancestorTypes)
ancestorTypes = [ancestorTypes]
for ancestorType in ancestorTypes
ancestor = record.get(ancestorType)
ancestorID = ancestor.get('id')
ancestry.push(ancestorType)
ancestry.push(ancestorID)
urlFixed = urlPrefix + '/' + ancestry.join('/') + urlWithoutPrefix
urlFixed
PS: A small edit to add that I this was made using Ember 1.7.1 and Ember Data 1.0.0-beta.11

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 });
}
});