Kendo UI datasource sync() will not work - javascript

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.

Related

Id is lost while trying to JSON.stringify Ember model

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.

Ember get not getting certain attribute

When running the following from the UserController on Google Chrome, with ember-couchdb-kit-0.9, Ember Data v1.0.0-beta.3-56-g8367aa5, Ember v1.0.0, and this couchdb adapter:
customerSignUp: function () {
var model = this.get('model');
var customer = this.get('store').createRecord('customer', {
description: 'Why hello sir',
user: model
});
customer.save().then(function() {
model.set('customer', customer);
model.save();
});
}
with these models:
App.User = App.Person.extend({
name: DS.attr('string'),
customer: DS.belongsTo('customer', {async: true })
App.Customer = DS.Model.extend({
user: DS.belongsTo('user', {async: true}),
description: DS.attr('string')
});
neither the user nor the customer has their relationship set properly (in the Ember Debugger the user has null and the customer has <computed>, rather than some sort of <EmberPromiseObject> which is what they have when it works).
This only happens when the object in question is persisted. If the save() calls are omitted, both have correctly set relationships, but of course the database hasn't been updated with this information. Whenever the saves happen, the relationships are overwritten with empty entries.
I found that the problem was in the adapter's serializeBelongsTo function, which I've now changed my copy to the following:
serializeBelongsTo: function(record, json, relationship) {
console.log("serializeBelongsTo");
console.log(record.get('user'));
console.log(json);
console.log(relationship);
var attribute, belongsTo, key;
attribute = relationship.options.attribute || "id";
console.log(attribute);
key = relationship.key;
console.log(key);
belongsTo = Ember.get(record, key);
console.log(belongsTo);
if (Ember.isNone(belongsTo)) {
return;
}
json[key] = Ember.get(belongsTo, attribute);
console.log(Ember.get(belongsTo, attribute));
console.log(json);
if (relationship.options.polymorphic) {
return json[key + "_type"] = belongsTo.constructor.typeKey;
}
else {
return json;
}
}
attribute, belongsTo, and key all log as correct, but
console.log(Ember.get(belongsTo, attribute)); returns undefined,
which I've tried to change to
console.log(Ember.get(Ember.get(belongsTo, 'content'), attribute));
since console.log(belongsTo); told me the id attribute was hidden inside a content object. Attached is a screenshot showing what I mean.
The change doesn't fix the problem though, and I keep getting undefined. No matter what method I use to try to get the id out of the belongsTo object, I always get either null or undefined. Here are some examples of things I've tried to get content out of the object:
var content = belongsTo.content;
var content = Ember.get(belongsTo, 'content');
var content = belongsTo.get('content');
console.log(json); returns Object {description: "Why hello sir", user: undefined}
Here's a pastebin showing relevant output: http://pastebin.com/v4mb3PJ2
Update
A very confusing update!
When I save the model from a different function:
saveModel: function() {
this.get('model').save().then(
function( data, textStatus, jqXHR ) {
console.log('Saved successfully.');
},
function( jqXHR, textStatus, errorThrown ) {
console.log(jqXHR);
console.log(errorThrown);
console.log(textStatus);
}
);
}
The model is correctly saved. Everything in serializeBelongsto works exactly as expected.
Here's a different pastebin showing output for this case: http://pastebin.com/Vawur8Q0
I figured out the problem. Basically the belongsTo object in serializeBelongsTo wasn't really resolved by the time it was being referenced, which I found out by querying isFulfilled. So I implemented by saving side this way:
function saveOn (target, attribute) {
target.addObserver(attribute, function () {
if (target.get(attribute)) {
console.log("Inside with %#".fmt(attribute));
target.removeObserver(attribute);
Ember.run.once(target, function() {
target.save();
});
}
});
};
customerSignUp: function () {
var model = this.get('model');
var customer = this.get('store').createRecord('customer', {
description: 'Why hello sir'
});
customer.save().then(function () {
model.set('customer', customer);
customer.set('user', model);
saveOn(customer, 'user.isFulfilled');
saveOn(model, 'customer.isFulfilled');
});
}
Now everything works like a charm. It might be a good idea for serializeBelongsTo to take this into account though. This line: console.log(Ember.get(belongsTo, 'isFulfilled')); was coming up false in my case. There was just a race condition of some sort between the creation of the record and it's serialization!
I'd like to make my saveOn function return a promise though, which I could then use to chain multiple saveOns together. That way I wouldn't have to do a customer.save() to make sure the id's were populated.

Ember data difference between find() and getById()

I know that there is a question named : Ember data: what is difference between find and findById?. However, correct if I'm wrong, but I think that it relates to an older version of Ember data since I can't find this method in the embet-data doc.
I was trying to insert a new category in my catalog. This wouldn't work:
newRecord: function() {
catalog = this.store.find('catalog', 1);
record = this.store.createRecord( 'category', {category_name_fr_sh: 'Nouvelle categorie'});
catalog.get('catalog_categories_ids').pushObject(record);
this.set('content', record);
},
But this work :
newRecord: function() {
catalog = this.store.getById('catalog', 1);
record = this.store.createRecord( 'category', {category_name_fr_sh: 'Nouvelle categorie'});
catalog.get('catalog_categories_ids').pushObject(record);
this.set('content', record);
},
The doc says
Get a record by a given type and ID without triggering a fetch.
This method will synchronously return the record if it's available. Otherwise, it will return null.
I really don't understand why "trggering the fetch" wouldn't work. I tought that the find() first look if it's in the store cache and only fetch if it doesn't find it. Can someone enlighten me?
this.store.find('catalog', 1); doesn't return the record, it return a DS.PromiseObject. Because, if your record is not present in the record cache, a request to the server is needed. If the record is already loaded, you still have the promise object, to keep the same method behavior, but no request is sent to the server.
this.store.getById('catalog', 1); return the object from the record cache if present. Probably this work because you already loaded the catalogs using this.store.find('catalog'); or this.store.find('catalog', 1);
You can get the catalog record from DS.PromiseObject using then method:
newRecord: function() {
var self = this;
var catalogPromise = this.store.find('catalog', 1);
catalogPromise.then(function(catalog) {
var record = this.store.createRecord( 'category', {category_name_fr_sh: 'Nouvelle categorie'});
catalog.get('catalog_categories_ids').pushObject(record);
self.set('content', record);
})
},

Another Backbone post part data

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.

Backbone collection not updating with JSONP request

I just recently started using Backbone.js and I'm working on an app now using Brunch that does a JSONP request to an external API to populate my collection and models. I'm following these previous posts (this and this) on doing JSONP requests with Backbone, but my collection still isn't getting the data for some reason.
My model (app/models/model.js):
module.exports = Backbone.Model.extend({
});
My collection (app/models/collection.js):
var Post = require('./model');
module.exports = Backbone.Collection.extend({
model: Post,
url: "http://somedata.com/api/posts/list/stuff",
sync: function(method, model, options) {
options.timeout = 10000;
options.dataType = "jsonp";
options.jsonp = "JSONPcallback";
return Backbone.sync(method, model, options);
},
parse: function(response) {
if (response) {
var parsed = [];
for(var i = 0; i < response.results.length; i++) {
parsed.push(response.results[i][0]);
}
return parsed;
}
}
});
Then, in the initialize method in app/application.js I'm calling it by:
var Category = require('models/collection');
this.cat = new Category();
this.cat.fetch();
Now, when I look at the parse function in console.log, I see the data being fetched, so the request is going through successfully. However, when my views are rendered and I do console.log(application.cat.models) in app/views/view.js, I get nothing -- why's this happening? Is there anything wrong with the code on my model/collection?
Also, the JSONP data has the following format, which is why looping through for response.results[i][0] and returning an array with all of it, that should do the trick, right?
{"results":[
{"0":{"id":xxx,"title":xxx,"link":xxx},
"description":xxx},
{"0":{"id":xxx,"title":xxx,"link":xxx},
"description":xxx},
{"0":{"id":xxx,"title":xxx,"link":xxx},
"description":xxx},...
]}
Would really appreciate any help...
I have 2 comments here :
I see that you have names both your model and collection as module.exports , a common practice is to make the model as singular (module.export) and make the collection for those models plural module.exports , just common practice , nothing "wrong" otherwise
You can have 2 callbacks in your code , when the collection is done fetching data(asynchronous event) also considering module.exports as your collection here ,
A. You could do this :
module.exports.fetch({
success : function(data){
console.log(JSON.stringiy(data));
//do remaining programming here
}
});
B. you could have a event listener for reset , from the documentation here , the collection fires a reset event when it completes the fetch , so could add an event listener on the collection like this :
module.exports.on('reset',function(data){
console.log(JSON.stringify(data));
//do remaining programming here
},this);

Categories