When adding data to a ExtJS TreeStore, the data is transformed into a TreeModel. When you call getData() on these TreeModels, it returns not just the fields specified in the original Ext.data.Model for the object, but also a bunch of other fields like qshowDelay, isFirst, allowDrag,...
What is the best way to get rid of all of these extra added fields so that I can POST just the fields specified in the original Ext.data.Model for the object?
The persist property is false for the added fields. So if you only want the modified fields for posting, you can use the model's modified property, and it will not include the added fields. If you want the data from all the original fields you can do something like:
var fields = Ext.Array.filter(MyModel.getFields(), function(field){
return field.persist!=false;
});
var data = Ext.copyTo(data, record.data, Ext.Array.pluck(fields, 'name'));
Related
I'm trying to design a load more type of system where every time you press load more you add data to the existing collection. This is a rough sketch of how the UI looks.
Everything works pretty great except as you would except everytime I re-run the
items.fetch
What it does: It overrides the entire collection with the new data
What I want it to do: I want the new records returned to be added to the records collection not override old 'records'
How can I make this work so that the newly fetched records are appended to existing records and not overridden?
Add { remove: false } to your fetch call:
items.fetch({ remove: false, data: { nextId: this.info.get('nextId') } });
What's happening here is Collection#fetch will synchronize its models with the data the server returns. That includes adding new models, updating models already present, and removing models that are not included in the response.
The behavior of fetch can be customized by using the available set options. For example, to fetch a collection, getting an "add" event for every new model, and a "change" event for every changed existing model, without removing anything: collection.fetch({remove: false})
The available set options are add, remove, and merge. Setting one (or all) to false will disable that functionality in the fetch.
It sounds like you just want { remove: false }, leaving the add and merge functionality.
I'm not familiar with backbone-relational,
But with a normal collection, you can do the following in parse method:
Backbone.Collection.extend({
parse: function(response){
// you can update the info here like this.info = response.info or similar
return _.union(this.toJSON(), response.records);
}
});
Basically we combine the response with existing data and return it so that we maintain the previous data when the collection updates
I'm trying to PUT the data and my model doesn't have an id.
Is it possible to explicitly tell the Save() method to PUT the data irrespective of ID.
The save method has an options parameter that can override anything on the XHR:
model.save(newVals, { type: 'PUT' })
You can also override the isNew method. PUT vs POST is determined by the result of that method. You'll also want to make sure the URL is being created correctly for new and non-new objects.
Also consider setting the idAttribute correctly so that your model does have an id field that can be used to generate a correct url. Using POST and PUT correctly (POST new items, PUT updates to items) makes your api more intuitive.
Let say you are defining a Backbone.js Model. From the documentation we have ...
new Model([attributes], [options])
This seems great for passing some default attributes to a model. When passed the model automatically inherits those attributes and their respective values. Nothing to do. Awesome!
On they other hand lets say we have a Collection of that model.
new Backbone.Collection([models], [options])
Okay, cool we can pass some initial models and some options. But, I have no initial models and no options I need to pass so let's continue. I am going to fetch the models from the server.
collection.fetch([options])
Well I don't have any options, but I want to pass some attributes to add to each models as it is fetched. I could do this by passing them as options and then adding them to the attributes hash in the initialize for the model, but this seems messy.
Is their a Backbone.js native way to do this?
You can pass the attributes as options to fetch and over-ride the collection's parse method to extend the passed options (attributes) on the response.
The solution would look like the following:
var Collection = Backbone.Collection.extend({
url:'someUrl',
parse:function(resp,options) {
if (options.attributesToAdd) {
for (var i=0;i<resp.length;i++)
_.extend(resp[i],options.attributesToAdd);
}
return resp;
}
});
Then to add attributes when you call fetch on the collection, you can:
var collection = new Collection();
collection.fetch({
attributesToAdd:{foo:'bar',more:'foobar'}
});
You may have to tweak the code a bit to work with your JSON structure, but hopefully this will get you started in the correct direction.
I am still new to backbone:
Here is my problem that I find hard to explain:
on initialisation there is a model something like this:
Model:
{
Id:xxx,
Questions:
[
{
Id: "yy",
Selections:
[
{OptionId:"aaa"},
...,
{OptionId:"zzz"}
]
},
....
]
}
there is a event method updates Selections Collection.
After event triggers I got two different result by with two code below:
window.pkg.Questions.get(this.Id).Selections.reset(selectedoptions);
console.log(window.pkg.Questions.get(this.Id).Selections.toJSON());
console.log(window.pkg.Questions.get(this.Id).toJSON().Selections);
The first log shows the updated model, however the later shows initial default value.
why it is working like this?
They are two different copies. Your QuestionModel has a SelectionsCollection property called Selections, and a Backbone attribute, also called Selections. I assume you want to use the SelectionsCollection, and the attribute will not stay in sync with that. The attribute is the original json which I assume was inadvertently added to the model.
Hard to say exactly how to fix it, because you did not show the code where you create and fetch these models and collections. Wherever you take the Selections JSON and and initially reset it into the collection, you can remove it from the JSON and/or unset it on the QuestionModel if it is already there....
This would also print the wrong, original data:
console.log(window.pkg.Questions.get(this.Id).get('Selections')); // print original JSON
You can remove it in QuestionModel's parse:
parse: function(data) {
// removing Selections from data here will prevent
// it from being added as an attribute.
delete data.Selections;
return data;
}
If you do this, and you want the Selections to be included in the toJSON output of QuestionModel, you would also need to override toJSON.
toJSON: function() {
// get json for Question
var json = Backbone.Model.prototype.toJSON.call(this);
// add updated json for selections
json.Selections = this.Selections.toJSON();
return json;
}
I have the following Backbone.js collection:
var Tags = Backbone.Collection.extend({
url: "/api/v1/tags/"
}),
How do I update one of the models in the collection so that it posts to /api/v1/tags/id and saves the data for that model.
So if I change name of model with id 2 in the collection
It should PUT to
/api/v1/tags/2 with the following data:
name: new name id: 2
I've also recently wanted to update particular model in the collection. The problem was that if I did use just model.save it didn't update the collection. The goal was to change the model in collection, change it on the server, update collection accordingly and not use the sync method. So for example I have my variable collection and I want to change the model with id = 2. So the first thing, I will create an instance model, like this: var model = collection.get(2)Then I will update the attributes on this particular model:model.set({name: 'new name'})Then I will save it to the server:model.save({}, {url:'/api/v1/tags/'+model.get('id')})Then we have to update collection accordingly to the changes:collection.set({model},{remove: false})set method - it's a 'smart' update of the collection with the list of the models you passed in parameters. remove: false parameter - it's a restriction for a collection to remove existing models in collection. More here.
The first thing you can miss is that in your corresponding Tag model you'll need to set "urlRoot" to match the Collection's "url". Otherwise it doesn't know about the collection at all:
var Tag = Backbone.Model.extend({
urlRoot: "/api/v1/tags"
});
var Tags = Backbone.Collection.Extend({
model: Tag,
url: "/api/v1/tags"
});
This is useful if you want to save the tag separately:
var tag = collection.get(2);
tag.set({key: "something"});
tag.save(); // model.save works because you set "urlRoot"
On the collection, "create()" is also "update()" if id is not null. That's not confusing. :) Therefore, this is pretty much equivalent to the previous sample:
collection.create({id: 2; key: "something"});
This will update the existing tag with id=2 and then trigger a PUT.
This is an ancient question; answering because I was searching for the same answer--you've probably long since solved this problem and moved on. :)
You can pass variables to the save method. It accepts all the options which jQuery's ajax method uses (unless you overrided Backbone.Sync)
You could do something like:
model.save( { name:'new name' } );
The id and PUT method will automatically be added by Backbone for you.