I am creating a client view of an application and I need help with retrieving specific data from my JSON file. I am using Backbone.js along with Underscore.js to achieve this.
(function($) {
window.Node = Backbone.Model.extend({
getName: function(){
return this.get('Name');
}
});
window.Nodes = Backbone.Collection.extend({
model:Node,
url: '/packageview.json'
});
window.NodeView = Backbone.View.extend({
tagName: "div",
className: "package-template",
events:{
"click #display-name" : "displayname",
},
//.. I have a render and initialize function here which should not be a concern
displayname: function(){
var node = new Node();
alert(node.getName()); //trying to alert
},
});
});
I am trying to get the name from model and alert it. I have a button in my html with an id, and when I press that button I get "undefined" as an alert. Here is how my JSON file looks:
{
"Id": 2,
"Name": "Some Package",
"IsComplete": false,
"IsNodeTagComplete": false
}
I think I am making a silly mistake somewhere. Am I expecting way to much from model?
What I am doing here is this
window.jsonAccess = Node.extend({ // Here Node is my above mentioned model
getJSON: function(){
var collection = nodeInstance.toJSON(); // nodeInstance is an instance of my collection Nodes
return collection; //returns JSON
}
});
jAccess = new jsonAccess();
So here is what I am doing to access the JSON
getNodeId: function(){ //Function to get Node Id from JSON
objectJSON = jAccess.getJSON(); // Get JSON
_.each(objectJSON, function(action){
_.each(action.Nodes, function(action){
This solves my purpose but not quite the way getters would be used in backbone.
Since a lot of context is missing I too may be making a mistake but here's my guess - you are creating an empty Node Model. Try doing something like this in display:
displayName: function() {
var myJSON = window.getJSONObject(); //wherever your json object is or how to get it...
var node = new Node({
id:myJSON.Id,
name:myJSON.Name,
isComplete: myJSON.IsComplete,
...
});
alert(node.get('name'));
alert("Getter: "+node.getName()); //your version...
}
This is just a hunch though...maybe I'm missing your context but this seems to be the case for now...
Related
I am new to Backbone.js so please bear with me.
I have the following code that correctly fetches JSON onSearchClicked. I can see the JSON in the console view. I would like to render the retrieved responseJSON to a view or pass the data through an existing model (under car_view.js) - so I can view on a HTML page. How can I do this?
Any help much appreciated.
view.js
--------------
var View = Backbone.View.extend({
tagName: 'div',
ranking: 0,
events:{
'click .search-button': 'onSearchClicked'
},
onSearchClicked : function(){
var searchString = $('.search-field input').val();
$('#gallery ul').empty();
var search = new carCollection([], {query: searchString});
search.fetch( {success: this.searchResults.bind(this) });
console.log(search.fetch());
},
},
search_collection.js
--------------
var Backbone = require('backbone');
var BurgerModel = require('../models/car');
var CarCollection = Backbone.Collection.extend({
model:CarModel,
initialize : function(models, options){
this.query = options.query;
},
url: function(){
return "/api/cars?name="+this.query;
}
});
module.exports = CarCollection;
car_view.js
--------------
carCard: function( burger ){
var carView = new CarView({
model: car
});
this.$el.append( carView.el );
},
There is a typo - Make 'C' capital in this line:
var search = new carCollection([], {query: searchString});
I am not going to provide the working code but I can provide you steps:
Please create a new class CarList which should have a reference to CarCollection
When User enters search query, a method of CarList should be invoked in which you should call fetch of collection
In success callback of fetch invoke a method renderCars
Inside renderCars For each search result create an instance of CarView and render it in an element.
Hope this is what you want. If you are looking for exact code, then nobody is going to help you on SO!!
I am using backbone.js I need a very simple way to render a local json file into the users local storage only one time. I am building a cordova app and I just want to work with local storage data.
I have hard coded a decent size .json file (list of players) into my collection, and I just want to load the .json file into the local storage if local storage on that device is empty which will only be once, upon initialization of the app.
I could use ajax, but I don't know how to write it to only inject data one time as "starter" data. So if you know how to do this I can upload the json file to my server and somehow fetch it.
I can inject the data if I go through a series of tasks, I have to disable the fetch method and render this code below in an each statement, plus the json has to be hardcoded into the collection, with a certain format.
playersCollection.create({
name: player.get('name'),
team: player.get('team'),
team_id: player.get('team_id'),
number: player.get('number'),
points: player.get('points')
})
I am trying to finish this lol I need to use it tonight to keep stats, I am almost there the structure works, when data is loaded I can add stats etc, but I need to get that data loaded, I pray someone can help!
Edit: I was able to put together some sloppy code last minuet that at least worked, thanks to #VLS I will have a much better solution, but Ill post the bad code I used.
// I fire renderData method on click
events: {
'click .renderData':'renderData'
},
// Inside my render method I check if "players-backbone" is in local storage
render: function() {
var self = this;
if (localStorage.getItem("players-backbone") === null) {
alert('yup null');
//playersCollection.fetch();
this.$el.append('<button class="renderData">Dont click</button>')
} else {
alert('isnt null');
this.$el.find('.renderData').remove();
playersCollection.fetch();
}
this.teams.each(function(team) {
var teamView = new TeamView({ model: team });
var teamHtml = teamView.render().el;
console.log($(''))
var teamPlayers = this.players.where({team_id: team.get('id')})
_.each(teamPlayers, function(player) {
var playerView = new PlayerView({ model: player });
var playerHtml = playerView.render().el;
$(teamHtml).append(playerHtml);
}, this);
this.$el.append(teamHtml);
}, this);
return this;
},
// method that populates local storage and fires when you click a button with the class .renderData
renderData: function() {
var self = this;
this.teams.each(function(team) {
var teamPlayers = this.players.where({team_id: team.get('id')})
_.each(teamPlayers, function(player) {
playersCollection.create({
name: player.get('name'),
team: player.get('team'),
team_id: player.get('team_id'),
number: player.get('number'),
points: player.get('points')
})
}, this);
}, this);
playersCollection.fetch();
return this;
}
This is obviously not the best way to go about it, but it worked and I was in such a hurry. The caveats are you have to click a button that populates the data, the collection is hard coded in, it's just overall not very elegant (but it works) the app did what it needed.
So big thanks to #VLS, I appreciate the effort to explain your code, and create a fiddle. Sorry I was so late!
You can extend your collection's fetch method and use it in conjunction with Backbone.localStorage, so inside your collection you'd have something like:
localStorage: new Backbone.LocalStorage("TestCollection"),
fetch: function(options) {
// check if localStorage for this collection exists
if(!localStorage.getItem("TestCollection")) {
var self = this;
// fetch from server once
$.ajax({
url: 'collection.json'
}).done(function(response) {
$.each(response.items, function(i, item) {
self.create(item); // saves model to local storage
});
});
} else {
// call original fetch method
return Backbone.Collection.prototype.fetch.call(this, options);
}
}
Demo: http://jsfiddle.net/5nz8p/
More on Backbone.localStorage: https://github.com/jeromegn/Backbone.localStorage
I am trying to parse a multilevel json file, create a model and then add that model to a backbone collection but i can't seem to figure out how to push the model to the collection. This should be a pretty easy problem to solve, i just can't seem to figure it out. Thanks in advance for your help. Below is my model and collection code:
var Performer = Backbone.Model.extend({
defaults: {
name: null,
top5 : [],
bottom5 : []
},
initialize: function(){
console.log("==> NEW Performer");
// you can add event handlers here...
}
});
var Performers = Backbone.Collection.extend({
url:'../json_samples/performers.json',
model:Performer,
parse : function(data) {
// 'data' contains the raw JSON object
console.log("performer collection - "+data.response.success);
if(data.response.success)
{
_.each(data.result.performers, function(item,key,list){
console.log("running for "+key);
var tmpObject = {};
tmpObject.name = key;
tmpObject.top5 = item.top5;
tmpObject.bottom5 = item.bottom5;
var tmpModel = new Performer(tmpObject);
this.models.push(tmpModel);
});
}
else
{
console.log("Failed to load performers");
}
}
});
As has been said in comments to your question, parse() is not intended to be used this way. If data.results.performers was an Array, all you would have to do is returning it. In your case the code will be slightly different.
var Performers = Backbone.Collection.extend({
...
parse: function(resp, options) {
return _.map(resp.result.performers, function(item, key) {
return _.extend(item, {name: key});
});
}
...
});
On the advice side, if you have the chance to change the API server-side, you'd probably be better off treating collections of objects as arrays and not as objects. Even if it is sometimes convenient to access an object by some ad-hoc key, the data really is an array.
You'll be able to transform it later when you need performers-by-name with a function like underscore's IndexBy
Currently I am fetching a collection that has over 1000 models which has a decent delay. How can I fetch 50 at a time? Also, is it possible to hit a "more" button to fetch another 50 that is not currently there?
Trying to advoid grabing the entire collection at once and have more of a "lazy loading" type of scheme.
Here is my current render method
render: function(){
var self = this
var collection = this.collection
collection.each(function(tenant){
var view = new TenantView({
model: tenant,
collection: collection
})
self.$el.append(view.render().el)
})
return this
}
You have to specify {add: true} and your pagination arguments in collection.fetch call. It will append to collection instead of reseting its contents.
collection.fetch({data: {page: 3}, add: true})
Then simply listen to collection's add event and append item to your view.
UPDATE: in the current version of backbone you need to call:
collection.fetch({data: {page: 3}, remove: false});
From the backbone.org website under Collection method fetch.
Backbone.sync = function(method, model) {
alert(method + ": " + model.url);
};
var Accounts = new Backbone.Collection;
Accounts.url = '/accounts';
Accounts.fetch();
You could set a limit in the query string of the url like /accountants?offset=0&limit=50.
Limit the query results from your database using these variables (offset, limit).
Modify the query string variables after fetching the requested models so when the user presses a button or scrolls down on your page the request for the next batch of models would be /accountants?offset=50&limit=50
I would do this on the view itself, rather than overwriting sync or fetch itself.
Something like:
// when extending your view
initialize: function(options) {
//...
this.collection.on('add', this.renderTenant, this);
},
events: {
// change the selector to match your "more" button
'click button.more': 'uiMore'
},
// Just tacking this on the view. You could make it an option, or whatever.
perPage: 50,
// this would produce a query with `offset` and `length`. Change it to
// however your request should paginate: page/perPage, just page, etc.
uiMore: function() {
var $more = this.$('.more');
var data = {};
data.offset = this.collection.length;
data.length = this.perPage;
$more.prop('disabled', true);
this.collection.fetch({data: data, add: true, success: function() {
$more.prop('disabled', false);
});
},
renderTenant: function(tenant) {
var view = new TenantView({
model: tenant,
collection: this.collection
})
this.$el.append(view.render().el);
},
render: function(){
this.collection.each(this.renderTenant.bind(this));
return this;
}
I'm trying to add a list of models to a collection to be stored locally. I don't fully understand backbone yet which is really the cause of this problem.
I basically pull in an RSS feed, assign each item in the feed to a Model and try place the list of Models into a collection so I can iterate over them later.
I am getting an error saying that I need to specify a Url for the collection.
It would be brilliant if someone could explain to me the correct process I need to follow to achieve my goal.
Currently I have:
var DetailIndividual = Backbone.Model.extend();
var DetailsIndividual = Backbone.Collection.extend({
model: DetailIndividual
});
var Search = Backbone.View.extend({
events: {
'click a.individualCast' : 'pullIndividual'
},
initialize: function() {
this.detailsIndividual = new DetailsIndividual();
_this = this;
this.detailsIndividual.bind('reset', function(collection) {
collection.each(function(item) {
//code to handle update
});
});
},
pullIndividual: function(e){
e.preventDefault();
//Logic to pull in RSS feed
for (var i = 0; i < result.feed.entries.length; i++) {
entry[i] = new DetailIndividual({ title: result.feed.entries[i].title, link: result.feed.entries[i].link, });
}
this.detailsIndividual.add(entry);
}
});
The error is reported out from here,because model must have url attribute:
http://backbonejs.org/docs/backbone.html#section-167
do you model have url attribute?
The reason why you're getting the error is because you're binding the 'reset' event. 'reset' is only fired on a collection.fetch or an explicit call to collection.reset, and in your case you're never fetching from the server with your collection - I'm assuming from your code you already have the feed in memory - so unless you're explicitly resetting, there's no need to listen for the reset.
In your code, you're not really extending Collection and Model, so it's actually not necessary to make extended objects - just use Backbone.Collection. You don't even need to create a Model extension because by default, when you add a JSON, a Backbone.Model is automatically created. It's only necessary to assign the collection.model if you're creating a truly custom model (with method overrides and additions).
Here's a way you could load your collection:
var search = Backbone.View.extend({
events: {
'click a.individualCast' : 'pullIndividual'
},
initialize: function() {
this.detailsIndividual = new Backbone.Collection();
},
pullIndividual: function(e) {
e.preventDefault();
//Logic to pull in RSS feed
for (var i = 0; i < result.feed.entries.length; i++) {
this.detailsIndividual.add({
title: result.feed.entries[i].title,
link: result.feed.entries[i].link
});
}
}
});
You didn't provide any code of how you wanted to parse collection (except in the 'reset'), but essentially you'd load the collection from the feed as shown.