Get attributes of model in backbone.js - javascript

I have this model
var Item = Backbone.Model.extend({
url: 'http://localhost/InterprisePOS/Product/loaditembycategory/Event Materials'
});
var onSuccess = function(){ alert("success"); };
And a collection
var Items = Backbone.Collection.extend({
model: Item
});
And the rest of my code is here:
var item = new Item();
var items = new Items();
item.fetch({ success: onSuccess });
alert(items.get("ItemCode"));
What I want is to simply get the attributes of the model. Now I have this on firebug. Also when I run it on the browser I get the alert success and the next alert is undefined.
This is the output:
{"ErrorMessage":null,"Items":[{"ErrorMessage":null,"CategoryCode":"Event Materials","ClassCode":null,"Components":null,"GroupCode":null,"ImageURL":null,"ItemCode":"ITEM-123","ItemDescription":"Old World Lamppost\u000d\u000a\u000d\u000a","ItemName":"GET123","ItemType":null,"KitItem":null,"Matrix":null,"Prefix":null,"RetailPrice":107.990000,"SalesTaxCode":null,"UPCCode":null,"UnitMeasureCode":"EACH","UnitsInStock":0,"Value":null,"WholesalePrice":95.000000}]}
NOTE
That is just one of the items it returns. I just posted on item so that it won't be that long.

You are calling get on your collection ( see http://documentcloud.github.com/backbone/#Collection-get)
It seems what you really want is to iterate over the collection, and call get on each item
items.each(function(item) {
item.get('ItemCode');
});
If not, please elaborate!
Additionally, if your model url responds with a list of models, you should be defining the url attribute in your Collection instead of your model.
var Items = Backbone.Collection.extend({
model: Item,
url: 'http://localhost/InterprisePOS/Product/loaditembycategory/Event Materials'
});
And your response should be an array, with Items as array elements [<item1>, <item2>, ...], rather than a JSON object with {'Items': [<item1>, <item2>, ...] }. If you don't want to modify the response, you will have to implement the parse function on your collection ( http://documentcloud.github.com/backbone/#Collection-parse ).
Also, as #chiborg mentions, you are calling get right after fetch (which will complete asynchronously), so there is no guarantee that your data will be available.
The proper solution here is to bind a 'refresh' listener on the collection.
items.on('refresh', function() {
// now you have access to the updated collection
}, items);

This is due to the model loading asynchonously - item.get("ItemCode") will only work after the model has been loaded with fetch. Try calling it in your onSuccess function.
Additionally, note that it won't help to initialize Item directly. What you are trying to do is get an element in the collection Items and then call item.get("ItemCode") on that element, like this:
function onSuccess() {
alert('success')
var item = items.get(13); // get item with id 13
alert(item.get("ItemCode"));
}

Related

Bakbone model extend filtering a json

I am very new in backbone js.
I am trying to filter some specific key and values in backbone js model extend here is the code below.
var items = ["open","close"];
var ReportModel = Backbone.Model.extend({
url: function() {
return tab+".json";
}
});
where tabe is dynamic json file name.In my json file many key value pair are there but I want to load only those key which is mentioned in items list.
I saw some where using parse function but that a;so did not work out.Please do let me know how to filter the specific keys form json using the backbone.
I also tried creating a dict from json and pass it to model like.
var ReportModel = Backbone.Model.extend({
"open":{.......}
});
but there I am getting issue.
throw new Error('A "url" property or function must be specified');
Please help me out with this.
You are missing some steps to be succesfull on your task.
First a note about the error: Backbone expects a string on the url property while you're passing a function. If you want to use a function to return your url dinamically use urlRoot.
Now onto the real coding:
since you talk about a json file that has multiple key value, maybe you should declare your model as a key-value object, and then create a Backbone.Collection that will wrap your models.
A Backbone.Collection expose a lot of utilities that can help us modeling the results, in this case by using the where() function of our collection you will be able to filter the data after you have retrieved from the remote file.
Alternatively to filter your collection if you need more control over the function you can always call the undescore function filter() .
Please refer to the official documentation of underscore and backbone, as you will find a lot of functions that can help you and most of them have an example that shows how to use them.
Now that we have everything lets create our Backbone.Collection that will wrap your already defined model:
var ReportCollection = Backbone.Collection.extend({
model: ReportModel,
urlRoot: function(){
return 'yoururl.json';
}
});
now if you want to filter the result you can simply fetch the collection and perform a filter on it:
var myReports = new ReportCollection();
//call the fetch method to retrieve the information from remote
myReports.fetch({success: function(){
//the collection has been fetched correctly, call the native where function with the key to be used as a filter.
var filteredElements = myReports.where({my_filter_key : my_filter_value});
});
in your filteredElements you will have an array of object made up of all the model that matched the key/value passed to the where function.
If you need a new Collection from that you just need to pass the result as argument: var filteredCollection = new ReportCollection(filteredElements);
You can use _.pick() in the parse method as shown below:
var items = ["open", "close"];
var ReportModel = Backbone.Model.extend({
url: function() {
return tab + ".json";
},
parse: function(response) {
return _.pick(response, items);
}
});

Backbone collection, get specific attribute

I've set an attribute currentPage on my Backbone collection, however I seem to not be able to log it specifically.
onRender: function () {
App.log('this.collection.currentPage onRender')
App.log(this.collection)
App.log(this.collection.accountID)
App.log(this.collection.currentPage)
App.log(this.collection.get('currentPage'))
}
I do the fetch then show, and within onRender, the following console log is produced
where this.collection.currentPage and this.collection.get('currentPage') are undefined even though I can see currentPage as a defined ("2") attribute in the log output of this.collection. this.collection.accountID is working how I expected currentPage to work.
What am I doing wrong?
Edit: I am setting the attribute on the success of .fetch because the data is returned in the response headers. Something like this,
getAccountSegments: function (accountID) {
var accountSegmentsCollection = new Entities.Collections.AccountSegmentCollection({
accountID: accountID
});
accountSegmentsCollection.fetch({
success: function (collection, response, options) {
collection.currentPage = options.xhr.getResponseHeader('X-Current-Page');
}
});
return accountSegmentsCollection;
},
Someone stated below that I am not allowed to set attributes on the collection (except by way of the constructor, but that's before the fetch). So how else could I get this response header data into my view?
Collections in backbone js do not allow you to set attributes.
The best way to store meta information in a backbone collection is through plain javascript object.
For example:
var myCollection = Backbone.Collection.extend({
model: myModel,
metaInfo: {
currentPage: "2"
}
});
Then you can get the current page in your view using this.collection.metaInfo.currentPage
get in this context is a little confusing. In Backbone Models have attributes, but collections do not, this means that get on a collection is different from get on a model.
get on a model retrieves an attribute, while on a collection it will return a model (by id). You could extend your collection to have attribute getters and setters:
var pageCollection = Backbone.Collection.extend({
getAttribute: function(attr) {
return this.attributes?this.attributes[attr]:null;
},
setAttribute: function(attr,val){
this.attributes = this.attributes || {};
this.attributes[attr] = val;
}
});
You could then set your currentPage attribute:
pageCollection.setAttribute('currentPage', 'myPage');
And retrieve it:
App.log(pageCollection.getAttribute('currentPage');
Which should give you the functionality you are after.

Backbone: I am trying to fetch a collection (using a rails server). However, my fetch doesn't look to be working right

I am using a rails server that returns this JSON object when going to the '/todos' route.
[{"id":1,"description":"yo this is my todo","done":false,"user_id":null,"created_at":"2015-03-19T00:26:01.808Z","updated_at":"2015-03-19T00:26:01.808Z"},{"id":2,"description":"Shaurya is awesome","done":false,"user_id":null,"created_at":"2015-03-19T00:40:48.458Z","updated_at":"2015-03-19T00:40:48.458Z"},{"id":3,"description":"your car needs to be cleaned","done":false,"user_id":null,"created_at":"2015-03-19T00:41:08.527Z","updated_at":"2015-03-19T00:41:08.527Z"}]
I am using this code for my collection.
var app = app || {};
var TodoList = Backbone.Collection.extend({
model: app.Todo,
url: '/todos'
});
app.Todos = new TodoList();
However, when trying to fetch the data it states that the object is undefined. I originally thought that my function wasn't parsing the JSON correctly. However, that doesn't look to be the case. I created a parse function with a debugger in it to look at the response. In gives back, an array with three objects.
Here what happens when I try testing the fetch().
var todos = app.Todos.fetch()
todos.length // returns undefined
todos.get(1) // TypeError: undefined is not a function
The todos collection doesn't automatically populate the function get() in console. I am running out of ideas of what can be the problem. Please help. Thanks!
Fetch is a ayncronous, you need to listen to the add event:
var todos = app.Todos.fetch()
todos.on('add', function(model){
console.log(todos.length);
});
If you pass the parameter reset, you could listen for the would new models:
var todos = app.Todos.fetch({reset: true})
todos.on('reset', function(model){
console.log(todos.length);
});
You could also read here.
There are two problems:
Fetch is asynchronous; we don't know exactly when we'll have a result, but we do know that it won't be there when you are calling todos.length.
Fetch sets the collection's contents when it receives a response; calling app.Todos.fetch() will result in app.Todos containing whatever models were fetched by the request. Its return value is not useful for inspecting the collection, so var todos = app.Todos.fetch() won't give you what you want in any case.
If you want to inspect what you receive from the server, your best option is to set a success callback:
app.Todos.fetch({
success: function (collection, response, options) {
console.log(collection);
}
});

Backbonejs - How can I print the results of a fetch?

Hi I'm new to Backbone and I was just playing around with it a little, here is my code:
var Users = Backbone.Collection.extend ({
url : 'http://backbonejs-beginner.herokuapp.com/users'
});
var users = new Users();
users.fetch({
success: function () {
console.log(users);
}
});
The fetch call succeeds and I am returned with an object that looks like:
[
{
"id": "hqel839m1071rbggsxf7",
"firstname": "Thomas",
"lastname": "Davis",
"age": 12
}
]
How can I print different parts of the result?
For example I want to print the "id" parameter of the first item. Can I iterate it like an array?
I tried to do console.log(users[0].id) but it doesn't work.
Thanks.
Not to forget about the arguments passed to success callback of collection.fetch which are (collection, response, options). Check documentation here. You can use the collection argument to select a particular model. Check below code :
var Users = Backbone.Collection.extend ({
url : 'http://backbonejs-beginner.herokuapp.com/users'
});
var users = new Users();
users.fetch({
success: function (collection, response, options) {
//Will log JSON objects of all User objects
console.log(collection.toJSON());
//You can get a Model using 'id'
var user = collection.get("hqesig1ea1br2k6horay");
// Will log User Model for id "hqesig1ea1br2k6horay"
console.log(user);
//You can then fetch Model attributes this way
console.log("ID: ", user.get('id'));
console.log("First name: ", user.get('firstname'));
console.log("Lastname : ", user.get('lastname'));
}
});
A fiddle for your reference.
There are three different ways to access the models in a Backbone.Collection. First, you can use the .get method to find a model based on it's unique ID. This basically looks at all models in the collection and compares their id attribute to the one provided.
var user = collection.get('unique_id'); // return an instance, or null
The second method is to use the .at method to get a model by index. This is useful if your models are sorted. If they are not sorted, they'll be fetched by insertion order (that is, the order in which they were provided to the collection):
var user = collection.at(0); // return the first model in the collection
Lastly, you can access the raw array of models that the Collection wraps. You can access this via the .models attribute, which is just an array. This is not the recommended approach.
var user = collection.models[0];
Once you have a user, you can access any attributes of the user via the .get method on your model:
var age = user.get("age");
user.set("age", 100);
You can view the documentation for the model get method here, and the documentation for Backbone.Collection here.

Backbone.js appending more models to collection

I have a following code that fetches data from the server and add to the collection.
// common function for adding more repos to the collection
var repos_fetch = function() {
repos.fetch({
add: true,
data: {limit:curr_limit, offset:(curr_offset*curr_limit)},
success:function() {
curr_offset++;
console.log(repos.length);
}
});
};
each time I call the function "repos_fetch", the data is retrieved from the server and added to the collection "repos".
My problem is that I want to APPEND to the collection, instead of REPLACING. So I put the option "add: true" there.
But below function looks like it's keep replacing the data in collection.
What's even strange is that if I remove the line "curr_offset++;" then the data gets appended!. "curr_offset" just increments, so I get different sets of data.
What's going on here?

Categories