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.
Related
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);
}
});
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.
I'm trying to use a simple collection and view to write out data from my backbone collection to my website. I just want to iterate over the collection and display properties like Id, Name, etc. in my template.
My collection gets its data from an api controller(a sample of the data is shown below).
My limited knowledge leads me to guess that the api controller is returning an object and not JSON.
So I'm guessing that is messing up my results. I've written out the collection to my Chrome console and attached a screenshot of what I see below.
So looking at the code below, is there a way that I can format the data returned from the api so that my collection can use it effectively?
Here is the code:
var ResearchCollection = Backbone.Collection.extend({
url: '/api/lab',
getresearch: function() {
this.fetch({
url: this.url
});
}
});
var researchCollection = new ResearchCollection();
return Backbone.View.extend({
className: 'labRender',
template: _.template(tmpl, null, { variable: 'x' }),
render: function () {
researchCollection.getresearch();
console.log('collection: ', researchCollection);
}
Basically, I just want to iterate over my collection and display properties like Id, Name, etc. in my template.
Here is the raw data from the api controller that I am using to populate my collection:
{
"odata.metadata":"http://sol.edu/SOM/Api/v1/$metadata#ApiKeys","value":[
{
"odata.id":"http://sol.edu/SOM/Api/v1/ApiKeys('2f2627ed-3a97-43aa-ac77-92f227888835')","Id":"2f2627ed-3a97-43aa-ac77-92f227888835","Name":"VideoSearch","TimeoutInMinutes":20160,"IsDefault":false,"CreateAuthTicketsForResources":false,"ReportAuthFailureAsError":false,"ExcludePrivatePresentations":true,"Internal":true,"ViewOnlyAccessContext":true
}
]
}
when piped to the browser's console(why is each character a separate attribute?):
I think maybe this is because you mixed up collection and model. In Backbone, Model are fundamental unit, a Model can be used to render a template.However, Collection are ordered sets of 'Models'. So, if you just want to transform a data like you describe above, you may better select a Model instead of 'Collection'. Just try this:
var ResearchModel = Backbone.Model.extend({
initialize: function(attributes) {
this.url = 'api/lab'
}
});
// when you initialize a Model or collection, the first parameter is the attribute you want to initialize
var researchModel = new ResearchModel({});
return Backbone.View.extend({
className: 'labRender',
template: _.template(tmpl, null, { variable: 'x' }),
render: function () {
researchModel.fetch();
console.log('collection: ', researchModel);
}
Otherwise, if you just want to use collection, you had better specify its Model.Backbone use JSON, so you can also specify the model with your key.
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"));
}
I have a basic backbone model, its urlRoot attribute is set and the corresponding target on the server side returns a correct JSON output (both JSON string and application/json header).
I call a fetch like this:
var athlete = new Athlete({ id: 1 });
athlete.fetch();
at this point if I add a
console.log(athlete);
I can see the model, and inspecting it in firebug I can open the attributes object and see all the values returned from the server.
BUT if I do a:
console.log(athlete.get('name'));
I get undefined (the name appears under the attributes in the DOM inspection I mentioned above)
also doing a:
console.log(athlete.attributes);
returns an object containing only {id: 1} which is the argument I passed while creating the model.
If I create the model like this:
var athlete = new Athlete(<JSON string copypasted from the server response>);
then everything works fine, the .get() method returns whatever I ask, and athlete.attributes shows all the values.
What am I doing wrong?
fetch is asynchronous, which means that the data won't be available if you immediatly call console.log(athlete.get('name')) after the fetch.
Use events to be notified when the data is available, for example
var athlete = new Athlete({id: 1});
athlete.on("change", function (model) {
console.log(model.get('name'));
});
athlete.fetch();
or add a callback to your fetch
var athlete = new Athlete({ id: 1 });
athlete.fetch({
success: function (model) {
console.log(model.get('name'));
}
});
or take advantage of the promise returned by fetch:
athlete.fetch().then(function () {
console.log(athlete.get('name'));
});
Just as a quick remark when using events in this example. It did not work with change in my case because this events fire on every change. So sync does
the trick.
var athlete = new Athlete({id: 1});
athlete.on("sync", function (model) {
console.log(model.get('name'));
});
athlete.fetch();