I'm trying to JSON.stringify() the model of a route inside the controller by using the below code. It works and it returns all model attributes, except for the actual id of the model. Can we receive the id as well?
var plan = this.get('model');
var reqBody = JSON.stringify(
{
plan,
token
});
You need to pass in the includeId option to the toJSON method in order to get the ID in the JSON.
var plan = this.get('model');
var reqBody = JSON.stringify({
plan: plan.toJSON({ includeId: true }),
token
});
And if you didn't know, JSON.stringify() will call toJSON() for you (which is what is happening in your case). If you want to call JSON.stringify() instead of model.toJSON({}), you can always override it:
App.Plan = DS.Model.extend({
toJSON: function() {
return this._super({ includeId: true });
}
});
That way JSON.stringify(plan) will give you exactly what you want.
Related
In the code below, the fetch() and sync() methods are not doing anything.
I am trying to see how the data in my localStorage gets updated and the methods are not updating it (example LS string is in the code)
Where am I going wrong?
function makeWorkingLS(collDesc, projDesc, Id, Description, ElapsedSeconds, ElapsedTime, WorkItemType){
//Create observable object from params
var activeTaskObject = kendo.observable ({
client: collDesc,
project: projDesc,
taskId: Id,
description: Description,
elapsedSeconds: ElapsedSeconds,
elapsedTime: ElapsedTime,
comment: WorkItemType
});
// example string in localStorage:
//{"client":"Morken Mindy","project":"Shazbat creation engine","taskId":183,"description":"Create the Shazbat 100% efficiency engine","elapsedSeconds":296803,"elapsedTime":"82h43m","comment":"Task"}
// Convert to JSON string for localStorage
var activeTask = JSON.stringify(activeTaskObject);
console.info(activeTask);
//Write to localStorage
window.localStorage.setItem("activeTask",activeTask);
//Set it as the active datasource for updating to webservice
var activeTaskDS = new kendo.data.DataSource({
transport: {
read: function(options){
taskItem = JSON.parse(localStorage["activeTask"]);
},
update: {
url: remUpd, //url var declared earlier in the process
dataType: "json"
}
},
schema: {
model: {
client: "client",
taskId: "taskId"
},
data: function(){
return taskItem;
}
}
});
activeTaskDS.fetch(function(){
activeTaskDS.data()[0].set("client", "NOBODY");
activeTaskDS.sync();
cosole.log("activeTaskDS.data()[0] : "+activeTaskDS.data()[0]); //should read 'NOBODY' but reads 'Morken Mindy'
});
}
Thanks in advance,
Neil.
I'm not sure what is the problem actually, but I have to point some important things:
AFAIK, when you customize any transport methods you have to pass the data into a callback in the options object:
transport: {
read: function(options){
taskItem = JSON.parse(localStorage["activeTask"]);
// Tells the widget to handle that collection
options.success(taskItem);
}
}
In schema.data it seems that you want to pass your data through this method(correct me if I'm wrong). But this method isn't for that purpose. It is used just to tell the widget which field to read(in case of passing a string to it) or to read a property from a response, which comes as a parameter that you are not using. Check the second example here. So this may not be right way to read the taskItem object as data;
Speaking about the taskItem object, it seems that its the base data of your dataSource but it isn't defined(at least on the snippet you posted). What I mean is, if you follow the step 1 you won't even need to read from that object no more.
Please let me know if this is helpful and if you need anyting more.
I am trying to parse a multilevel json file, create a model and then add that model to a backbone collection but i can't seem to figure out how to push the model to the collection. This should be a pretty easy problem to solve, i just can't seem to figure it out. Thanks in advance for your help. Below is my model and collection code:
var Performer = Backbone.Model.extend({
defaults: {
name: null,
top5 : [],
bottom5 : []
},
initialize: function(){
console.log("==> NEW Performer");
// you can add event handlers here...
}
});
var Performers = Backbone.Collection.extend({
url:'../json_samples/performers.json',
model:Performer,
parse : function(data) {
// 'data' contains the raw JSON object
console.log("performer collection - "+data.response.success);
if(data.response.success)
{
_.each(data.result.performers, function(item,key,list){
console.log("running for "+key);
var tmpObject = {};
tmpObject.name = key;
tmpObject.top5 = item.top5;
tmpObject.bottom5 = item.bottom5;
var tmpModel = new Performer(tmpObject);
this.models.push(tmpModel);
});
}
else
{
console.log("Failed to load performers");
}
}
});
As has been said in comments to your question, parse() is not intended to be used this way. If data.results.performers was an Array, all you would have to do is returning it. In your case the code will be slightly different.
var Performers = Backbone.Collection.extend({
...
parse: function(resp, options) {
return _.map(resp.result.performers, function(item, key) {
return _.extend(item, {name: key});
});
}
...
});
On the advice side, if you have the chance to change the API server-side, you'd probably be better off treating collections of objects as arrays and not as objects. Even if it is sometimes convenient to access an object by some ad-hoc key, the data really is an array.
You'll be able to transform it later when you need performers-by-name with a function like underscore's IndexBy
I want use Backbone.save the model,and the model's nest data need to be filter,so i use
model.save(null,{
success: ...,
error:...,
data: {
id:null,
name:'myname',
nestmodel: {
id:'xx'/*Other data i don't need it,so just id column*/
}
}
}
And I don't want to use patch HTTP METHOD. Because i just add a new model,not change part data.
And i don't want to post some nestmodel data,Because it's to big and i just want the id is ok.
And nestmodel just need the id.
I have read Exclude model properties when syncing (Backbone.js) and Backbone.js/express.js parameters for model.save()
There is a way to solve that problem.
That's whole my code:
sync: function(method, model, options) {
var data, orderSuiteItems;
if (method === 'create') {
options.url = this.url;
} else {
// MUST setting the url .options's url is undefined
options.url = this.url + this.idUrl(this.get('id'));
}
// IF `create` or `update` , pick the we need properties
if (method === 'create' || method === 'update') {
orderSuiteItems = [];
if (this.has('orderSuiteItems')) {
// Because the `dishes` and `dishesUnitPrice` have a lot of prop,
// Each of `dishes` or `dishesUnitPrice` may each have 10K data
orderSuiteItems = _.map(this.get('orderSuiteItems'), function(osi) {
return {
id: osi.id,
qty: osi.qty,
servingQty: osi.qty,
confirmQty: osi.confirmQty,
deleted: osi.deleted,
orderItem: _.pick(osi.orderItem, 'id'),
dishes: _.pick(osi.dishes, 'id'), // HAVE a large prop
dishesUnitPrice: _.pick(osi.dishesUnitPrice, 'id'), // HAVE a large prop
orderItemStatus: osi.orderItemStatus,
piece: osi.piece
};
});
}
data = {
id: this.get('id'),
order: this.get('order'),
price: this.get('price'),
dishes: _.pick(this.get('dishes'), 'id', 'isSuite'),
dishesUnitPrice: _.pick(this.get('dishesUnitPrice'), 'id'),
qty: this.get('qty'),
servingQty: this.get('servingQty'),
confirmQty: this.get('confirmQty'),
sum: this.get('sum'),
orderSuiteItems: orderSuiteItems,
orderItemStatus: this.get('orderItemStatus')
};
// Setting attrs with pick data.
options.attrs = data;
return Backbone.sync(method, model, options);
} else {
return Backbone.sync(method, model, options);
}
}
I hope you just put the data option for the sake of the example's clarity.
Anyway, how about using unset to remove your attribute just before using Model#save? Re-set it just afterwards.
Another solution would be to override the Model#save method.
You could also shadow the same method by defining it as a property and not in the prototype (that'd give you the opportunity to switch back).
Solution #1 or something similar would be the easiest. Solution #2 may be more, let's say, risky, but would have maybe less boilerplate. I would use the #3 only in some very specific case (can't even think about one as of now) that would include: object being a singleton (because we're not using the prototype)(or only in a limited number), need to switch the 2 modes a lot, better to have only 1 method.
Edit:
Solution #1:
var nestedModel = myModel.get('nestmodel');
myModel.save('nestmodel', nestedModel.id, {silent: true});
myModel.set('nestmodel', nestedModel, {silent: true});
I added the silent flag as I don't know if you're listening to your nestmodel attribute's changes. I'll add code for the other solutions if this one doesn't suit you.
I am working with mongoLab and the model id looks like this
"_id": {
"$oid": "50f9a0f5e4b007f27f766cf3"
},
I am using the idAttribute to set the model id to _id and everything works fine until I attempt to update the model.
Because the _id attribute exists in the model, I am getting an error when I attempt to insert.
Do I need to remove the attribute _id from my attributes? I was under the assumption that the magic of Backbone would clean up the attributes appropriately
You would need to remove the _id attribute.
In the MongoLab REST API, the id isn't part of the data payload itself, but that isn't the case for all backends. It probably makes more sense for Backbone to assume that the id should be present in the payload, than it would to assume it should not.
That being said there's no real nice way to get Backbone to clean the id from the payload automatically. Your best bet without monkeypatching/rewriting too much of the code would probably be to override Model#toJSON, something akin to:
Backbone.Model.prototype.toJSON = function (options) {
var attrs = _.clone(this.attributes);
// In this case you'd have to pass `includeId: true` to `toJSON` when you
// actually *want* the _id in the output.
return options && options.includeId ? attrs : _.omit(attrs, '_id');
};
You could also monkeypatch sync, something like:
var sync = Backbone.sync;
Backbone.sync = function (method, model, options) {
options || (options = {});
// if options.attrs is present, Backbone will use it over dumping toJSON
if (!options.attrs) options.attrs = _.omit(model.attributes, '_id');
return sync.call(Backbone, method, model, options);
};
had the same issue where _id translated to null when in javascript..
had to do something like..
var myModel = Backbone.Model.extend({
parse: function(response){
var response = response.whatever;
response.id = response.null;
delete response.null;
return appointment;
}
});
or for a collection
systems.forEach(function(system){
console.log(system);
system.id = system.null;
delete system.null;
});
I'm looking for a classy strategy to retrieve the current user information with emberjs (and ember-data).
Currently, I do the following :
My API responds to /users/me with the current user.
In my adapter, when the retrieved object id isn't the one I'm hoping for, I add a real_id which is the id (the user's id in the database) and I replace the real returned id by what I'm expecting.
So when my adapter has "me" as user's id, but the server returns 1, I get the following json :
{"real_id": 1, "id": "me"}
This works. But I'm not a big fan, and I'd like to avoid as mush as possible to change the default content of the adapter.
Do you use any strategy for this ? What would you recommend ?
I would use a controller App.currentUserController for this.
App.CurrentUserController = Ember.ObjectController.extend({
content: null,
retrieveCurrentUser: function() {
var controller = this;
Ember.$.getJSON('/users/me', function(data) {
App.store.load(App.User, data);
var currentUser = App.store.find(data.id);
controller.set('content', currentUser);
});
}
});
get = Em.get
set = Em.set
App.AccountController = Em.Controller.extend
contentBinding: '_content.firstObject'
init: ->
set #, "_content", App.User.find()