I try to use backbone in my project. But I have met problem when try to overide parse method of Backbone. The server has send back more data than I want.For example:
What I want is:
[{
id: "123",
name: "david"
},{
id: "456",
name: "kevin"
}]
but the server's result is :
{
total: 1000,
items:[{
id: "123",
name: "david"
},{
id: "456",
name: "kevin"
}]
}
so I want process result in parse method and return only the array. How can I do this? When I try I got error. How should I do?
In your backbone model, define the parse function the way you would like:
Model = Backbone.Model.extend({
parse: function () {
return {
id: this.get("id"),
name: this.get("name")
}
}
});
But, it would be better to handle and set the data in the model initializer, like so:
Model = Backbone.Model.extend({
initialize: function (attrs) {
try {
//TODO HERE: test for correct values and throw errors
// set object variables here
this.set({
name: attrs.name,
id: attrs.id
});
} catch (e) {
console.log(e);
}
}
});
No need to overwrite the parse function now. This way you know the data that your model is handling is good, and you set what variables it contains. This avoids many errors from invalid data.
Each item in the array should really be a submodel, which is what I have written above. Your parent model should look like:
Model = Backbone.Model.extend({
initialize: function (items) {
this.subModels = [];
items.forEach(function (item) {
this.subModels.push( new SubModel(item) )
});
}
});
Or as a collection:
Collection = Backbone.Collection.extend({
model: ItemModel,
});
To which you would pass response.items
From Backbone Parse docs
Collection = Backbone.Collection.extend({
model: YourModel,
parse: function(response){
return response.items;
}
});
Related
I'm trying to deal with a server response, and am a little confused how to turn the json response into Backbone Models.
My Backbone model looks like so:
Entities.Recipe = Backbone.Model.extend({
defaults: {
id: '',
name: '',
introduction: ''
},
parse: function (response)
{
if(._isObject(response.results)){
return response.results
else {
return response
}
})
Entities.RecipeCollection = Backbone.Collection.extend({
url: 'recipes',
model: Entities.Recipe
)}
var API = {
getRecipeEntities: function (){
var recipes = new Entities.RecipeCollection()
var defer = $.Deferred()
recipes.fetch({
url: 'http://3rdpartyApilocation.com/recipes'
success: function (data) {
defer.resolve(data)
}
})
var promise = defer.promise()
$.when(promise).done(function (fetchedData)
{})
return promise
}
RecipeManager.reqres.setHandler('recipe:entities', function()
{
return API.getRecipeEntities()
}
And the response.results is an Array of objects - with each object having an id key, a name key and an introduction key. But because I am so inexperienced with Backbone I have no idea how to map those results to the model?
I have installed Chromes Marionette inspector and when I look at the entire array of results seems to be passed to the model, rather than each individual object within each response.result being set to each individual model. Sorry if I can't be more clear - I'm very new to Backbone...
Perhaps your confusion is because you're in fact able to use parse on a model or on a collection. And from your explanation it looks like the response.results object returns a list of objects that you want to become models in your application. But because you're catching that object in a model, the model doesn't know what to do with that array.
Let's say you have a response like this:
{
"status": "ok",
"results": [
{
"id": 1,
"name": "Pie"
}, {
"id": 2,
"name": "Rice"
}, {
"id": 3,
"name": "Meatballs"
}
]
}
Then you would just use parse on your Collection to let it know the response isn't array itself, and help it find it in the results property.
Here's a working example:
var Recipe = Backbone.Model.extend();
var Recipes = Backbone.Collection.extend({
model: Recipe,
url: 'http://www.mocky.io/v2/56390090120000fa08a61a57',
parse: function(response){
return response.results;
}
});
var recipes = new Recipes();
recipes.fetch().done(function(){
recipes.each(function(recipe){
/** Just demo of the fetched data */
$(document.body).append('<p>'+ recipe.get('name') +'</p>');
});
});
<script src='http://code.jquery.com/jquery.js'></script>
<script src='http://underscorejs.org/underscore.js'></script>
<script src='http://backbonejs.org/backbone.js'></script>
I have a backbone model and collection. In the model, the default attribute values are defined:
var Person = Backbone.Model.extend({
defaults: {
name: "mark",
middle: "-"
}
});
var People = Backbone.Collection.extend({
model: Person
});
var collection = new People();
collection.add({name: "paul", middle: null});
console.log('collection is ');
console.log(collection);
I want the default value for "middle", which is "-", to be taken if "null" is passed in for the attribute "middle". However, "null" overrides the default instead. How do I do this? The jsfiddle is here
The cleanest way probably is to add a parse method and normalize the data:
var Person = Backbone.Model.extend({
defaults: {
name: 'mark',
middle: '-'
},
parse: function (payload) {
return {
name: payload.name || undefined,
middle: payload.middle || undefined
};
}
});
collection.add({name: "paul", middle: null}, {parse: true});
Note that when the data is returning from the server via fetch it will automatically go through parse and there's no need to call pass the option flag.
You could do it either on the model level or at the collection level.
check for value when initialize
initialize: function() {
if (!this.get("middle") || $.trim(this.get("middle") || '') === '') {
this.set({"middle": this.defaults.middle});
}
},
I have my promise function inside my route as
setupController: function (controller,model) {
// Set the IndexController's `title`
this.controllerFor('New').set('model', model);
this.store.find('selectFill', { x: "20", y: "30" }).then(function (data) {
controller.set('selectFill',data.?????);
});
}
my model looks like this,
App.SelectFill = DS.Model.extend({
users: DS.hasMany('user', {
embedded: true
})
});
App.User = DS.Model.extend({
userId:DS.attr('string'),
department: DS.attr('string')
});
anyway once the promise get hit, i have the data in the store.My question is, how do i extract the users from it?
here is the class i get from the promise function.
Please refer to this image here.
Users array u can see on the bottom. but how do i get there from the promise callback?
sorry if my question is silly, but i'm still new to ember.
this.store.find('selectFill', { x: "20", y: "30" }) will resolve a array like object (DS.AdapterPopulatedRecordArray), in that sample is the selectFills variable. Because it's a kind of array, you can use forEach to iterate in each selectFill and get the user calling selectFill.get('users'). Like this:
setupController: function (controller,model) {
// Set the IndexController's `title`
this.controllerFor('New').set('model', model);
this.store.find('selectFill', { x: "20", y: "30" }).then(function (selectFills) {
selectFills.forEach(function(selectFill) {
var users = selectFill.get('users');
// do something with the users
});
});
}
I'm new to backbone and I'm trying to set a collection of models with data loaded from a json-file. But it won't get set. Whats the problem here? Anyone having an idea? When i fetch the collections it seems that its empty.
JSON
{
"items": [
{
"id": "0",
"media": "",
"desc": "lorem",
"img": "ipsum"
},
{
"id": "1",
"media": "",
"desc": "lorem",
"img": "ipsum"
}
]
}
Javscript
var Card = Backbone.Model.extend({
defaults: function() {
return {
items: {
id: "lorem",
media: "lorem",
desc:"lorem",
img: "lorem"
}
};
},
clear: function() {
this.destroy();
}
});
var CardCollection = Backbone.Collection.extend({
model: Card,
url: "file.json",
parse: function (response) {
for (var i = 0; i<response.items.length; i++) {
}
}
});
var cards = new CardCollection();
cards.fetch();
console.log(cards)
fetch is asynchronous, it returns immediately before the data has been loaded.
Try this
var cards = new CardCollection();
cards.fetch({
success: function () {
console.log(cards);
}
});
The CardCollection.parse method is called with the response. If no transformation is required to the response from the server, you can remove the parse method of the CardCollection. The default implementation is pass thru and the response is used as-is.
Basically parse should return the array to be added to the collection. The current implementation does not do anything. return is missing for the implementation.
Just return something from your parse method and you are good to go. It is expected to return an array of objects and each object will fit into your model. So finally you will have a collection of models corresponding to array of objects being returned from parse method.
Try this
var CardCollection = Backbone.Collection.extend({
model: Card,
url: "file.json",
parse: function (response) {
return response.items;
}
});
Read this Documentation on Parse Method for more information.
I'm newbie to MongoDB and Backbone, so I try to understand them, but it is hard. I have a big, big problem: I cannot understand how to manipulate attributes in Backbone.Model to use in Views only what I need. More specific - I have a model:
window.User = Backbone.Model.extend({
urlRoot:"/user",
idAttribute: "_id",
defaults: {
_id: null,
name: "",
email: "foo#bar.baz"
}
});
window.UserCollection = Backbone.Collection.extend({
model: User,
url: "user/:id"
});
And I have a View:
beforeSave: function(){
var self = this;
var check = this.model.validateAll();
if (check.isValid === false) {
utils.displayValidationErrors(check.messages);
return false;
}
this.saveUser();
return false;
},
saveUser: function(){
var self = this;
console.log('before save');
this.model.save(null, {
success: function(model){
self.render();
app.navigate('user/' + model.id, false);
utils.showAlert('Success!', 'User saved successfully', 'alert-success');
},
error: function(){
utils.showAlert('Error', 'An error occurred while trying to save this item', 'alert-error');
}
});
}
I have to use 'put' method whit data from any fields except '_id', so it must be smth like:
{"name": "Foo", "email": "foo#bar.baz"}
But every time, doesn't depend on what I do it send
{**"_id": "5083e4a7f4c0c4e270000001"**, "name": "Foo", "email": "foo#bar.baz"}
and this error from server:
MongoError: cannot change _id of a document old:{ _id: ObjectId('5083e4a7f4c0c4e270000001'), name: "Foo" } new:{ _id:
"5083e4a7f4c0c4e270000001", name: "Bar", email: "foo#bar.baz" }
Github link: https://github.com/pruntoff/habo
Thanks in advance!
From looking at your mongo error, the problem is not with mongo, it is just doing what it's supposed to do. It had an object with _id of ObjectId type: ObjectId('xxx') and now you're trying to change that object to have an _id of a String type (_id: "5083e4a7f4c0c4e270000001") and that Mongo apparently does not like.
So, the question is: why did the object have an id of type ObjectId in the first place? How did you set it the first time? If you used some other method to initialize it (I'm guessing server side), you should set the id type to be a String so that it is the same as the one coming from your script library. If you want it to stay an ObjectId, you will need to convert the String coming from your script to an ObjectId before you save it to Mongo.
HTH.
MongoDB creates _id as an ObjectID, but doesn't retrieve _id as an ObjectID.
Whether this inconsistency is 'correct behaviour' or not, it is certainly an annoying surprise for most MongoDB users.
You can fix it with:
if ( this._id && ( typeof(this._id) === 'string' ) ) {
log('Fixing id')
this._id = mongodb.ObjectID.createFromHexString(this._id)
}
See MongoDB can't update document because _id is string, not ObjectId