Appending data to same collection after every pagination fetch - backbone.js

I am trying to populate instagram images using backbone,
I have basically 3 models as follows,
User model store all the user info related to instagram
App.Models.User = Backbone.Model.extend({
defaults: {
id: '',
access_token: '',
userid: '',
username: '',
full_name: '',
profile_picture: ''
},
urlRoot: "/api/user/",
initurl: function() {
return "https://api.instagram.com/v1/users/"+this.get('userid')+"/media/recent/?access_token=" + this.get('access_token');
},
initialize: function() {
this.set('id', $('#domdump .id').val());
this.fetch({
success: function(model) {
var photos = new App.Collections.Ig_photos([],{
url: model.initurl()
});
}
});
}
});
A model to store the next url for pagination
App.Models.Ig_next_url = Backbone.Model.extend({
defaults: {
next_url: ''
},
next_url:function(){
return this.get('next_url');
}
});
A model for the photo
App.Models.Ig_photo = Backbone.Model.extend({});
A collection for the multiple photo
App.Collections.Ig_photos = Backbone.Collection.extend({
model: App.Models.Ig_photo,
initialize: function(model, options) {
this.url = options.url;
this.nextSet();
},
sync: sync_jsonp,
parse: function( response ) {
if(response.pagination && response.pagination.next_url && response.pagination.next_url != this.url){
var next_url = new App.Models.Ig_next_url({ next_url: response.pagination.next_url });
this.url = next_url.next_url();
}
return response.data;
},
nextSet: function(){
this.fetch({
success: function(photos){
var ig_photos_views = new App.Views.Ig_photos_view({ collection: photos});
console.log(photos);
}
});
}
});
Also i have some views that does the render with a load more button that calls the nextset of the collection.
What i was trying to achieve is the photos get appended to the collection upon nextset() and the collection get updated with pervious data + new data but right now its getting overwritten.
Also is it okay to instantiate new collection from the modelfetch ?

You shouldn't need to make a new view. You should instead listen to the "add" event being triggered on the collection and render new items accordingly.
nextSet: function(){
this.fetch({add : true}); // The add option appends to the collection
}
This option is detailed in the very good documentation.

Related

BackboneJS fetch collection based on parameters

I want to display multiple musical artists based on the genre in a view. So, first of all I have my menu tabs:
<a data-name="hiphop" class="genre">HipHop</a>
<a data-name="rock" class="genre">Rock</a>
<a data-name="alternative" class="genre">Alternative</a>
<a data-name="jazz" class="genre">Jazz</a>
then my genre.js contains:
Genres.Collection = Backbone.Collection.extend({
url: function() {
return 'path to my json';
},
parse: function(response, genre){
return response.data.genres[genre];
// when I do: return response.data.genres.rock;
// I get all artists from the genre "rock".
// but I want the response to be based on the variable "genre"
}
});
then, in my mainView.js:
events: {
'click .genre' : 'genre'
},
genre: function(event, genre){
event.preventDefault();
// get the clicked genre
var genreName = $(event.target).data('name');
var genresCollection = new Genres.Collection({genre:genreName });
genresCollection.fetch();
this.insertView('.genres', new Genres.View({collection: genresCollection}));
},
but no matter which genre I click, I get an empty Collection. can someone tlel me what I'm doing wrong here?
Many thanks!
Options are not stored by default, but you can override your initialize method to provide this functionality. You would then use this stored value in your parse method :
Genres.Collection = Backbone.Collection.extend({
url: function() {
return 'path to my json';
},
initialize: function(opts) {
opts = opts || {};
this.genre = opts.genre || 'rock';
},
parse: function(response){
return response.data.genres[this.genre];
}
});
You need to define a success callback. Try:
var genresCollection = new Genres.Collection();
genresCollection.fetch({
data: {
genre: genreName
},
success: (function (coll_genres) {
console.log(coll_genres.toJSON());
}),
error: (function (e) {
console.log(e);
})
});

Backbone model is plain text file. How to fetch?

I have a model File which contains a plain text file. For example Github Gists have this url structure: https://gist.githubusercontent.com/140bytes/962807/raw/dfb480a5038214d152544bddb412dfe2e8656413/LICENSE.txt.
To do this, should I override fetch/save/etc, or should I override the model's sync?
var File = Backbone.Model.extend({
path: '',
contents: '',
initialize: function(options) {
this.path = options.path || '';
},
fetch: function() {
// Do I override fetch/save/etc?
$.get(this.path).done(function(contents) {this.contents = contents});
},
sync: function (method, model, options, error) {
// Or do I override sync?
}
});
You can just override parse, fetch and url method a little:
var File = Backbone.Model.extend({
url: function(){
return this.get('path')
},
// call original Backbone.Model#fetch with `dataType` equal `text` for $.ajax
fetch: function(options){
options = _.extend(options || {}, {
dataType: 'text'
});
this.constructor.__super__.fetch.call(this, options);
},
// store response in content attribute
parse: function(response){
return {content: response};
}
});
In this case your code will be more idiomatic and you will have all benefits of Backbone native methods (success and error callbacks to fetch, request and sync events, change events etc). You can use it like:
var someFile = new File({
path: 'http:/example.com/someFile.txt'
});
someFile.fetch({
success: function(){
console.log(someFile.get('content'); // => content of someFile.txt
}
});

Fetching data from model with backbone posts wierd parameters

I have created a model and collection like this:
var TestModel = Backbone.Model.extend({
initialize: function () {
},
defaults: {
'id': null,
'title': '',
'description': ''
}
});
TestCollection = Backbone.Collection.extend({
model: TestModel,
url: function () {
return 'Test/GetAll';
},
});
I then have a view I try to load like this:
var testCollection = new TestCollection();
var testListView = new TestListView({ collection: testCollection });
testCollection.fetch();
But it creates a request like:
Test/GetAll?_=1349272902901 which fails. Do any of you know why it appends this id-like parameter to the request?
Try:
testCollection.fetch({ cache: false });

backbone.js Newbie Collection

I am trying to write some backbone.js stuff to get a better understanding on where and if it fits in better for me on projects. Any way I have a site and I am loading a collection with page content.
Json data comes back with (pid,name,title,content) on my router the default is
defaultRoute: function (actions)
{
this.showInfo('food');
},
showInfo: function (id)
{
var view = new ContentView({ model: this._items.at(id) });
$(".active").removeClass("active");
$("#" + id).addClass("active");
view.render();
}
if I put a 0 in place of id in this "new ContentView({ model: this._items.at(0) })" I will get the first item in the collection and if I do this in the View:
var ContentView = Backbone.View.extend({
el: $('#content'),
render: function ()
{
this.el.empty();
$(this.el).append(this.model.attributes.content);
return this;
}
});
I get the content displayed perfectly but of course may not be the content I wanted
Is it possible to select from a collection based on name == "food"?? I dont want to have to map the content to id numbers defeats the purpose of storing in a db
Sorry if this seems like a foolish question but I have crawled all over looking and Im sure Im missing something simple
here is my full NavigationRouter code in case it helps
var NavigationRouter = Backbone.Router.extend({
_data: null,
_items: null,
_view: null,
routes: {
"p/:id": "showInfo",
"*actions": "defaultRoute"
},
initialize: function (options)
{
var _this = this;
$.ajax({
url: "page_data.php",
dataType: 'json',
data: {},
async: false,
success: function (data)
{
_this._data = data;
_this._items = new ItemCollection(data);
_this._view.render();
Backbone.history.loadUrl();
}
});
return this;
},
defaultRoute: function (actions)
{
this.showInfo('home');
},
showInfo: function (id)
{
var view = new ContentView({ model: this._items.at(id) });
$(".active").removeClass("active");
$("#l_" + id).parent().addClass("active");
view.render();
}
});
Backbone mixes in a bunch of Underscore's functions into its Collections.
So if you want to find the model in the collection where name === 'food', you can do:
var foodModel = this._items.find(function(model) {
return model.get('name') === 'food';
});
// this will set foodModel to the first model whose name is 'food'
As a side note, you don't need to call empty in your render function, which can just be:
render: function() {
$(this.el).html(this.model.get('content'));
return this;
}
jQuery's html function just replaces the content of an element with the html string you pass in.

Backbone performing a GET immediately after a POST

I'm experimenting for the first time with backbone.js and I have a very simple Grails application with a single domain called Book. Things seem to be working well however, I've noticed that when I POST the data from the form to the server backbone then does a GET to the server with the ID of the new record. However, the POST returns the results as JSON and populates the table accordingly. I'm not sure I understand the need for the GET following the POST or how to stop this from happening.
$(function() {
// Model
window.Book = Backbone.Model.extend({
url: function() {
return this.id ? '/BackboneTest/books/' + this.id : '/BackboneTest/books.json';
},
defaults: { book: {
title: 'None entered',
description: 'None entered',
isbn: 'None entered'
}},
initialize: function() {
// can be used to initialize model attributes
}
});
// Collection
window.BookCollection = Backbone.Collection.extend({
model: Book,
url: '/BackboneTest/books.json'
});
window.Books = new BookCollection;
//View
window.BookView = Backbone.View.extend({
tagName: 'tr',
events: {
// can be used for handling events on the template
},
initialize: function() {
//this.render();
},
render: function() {
var book = this.model.toJSON();
//Template stuff
$(this.el).html(ich.book_template(book));
return this;
}
});
// Application View
window.AppView = Backbone.View.extend({
el: $('#book_app'),
events: {
"submit form":"createBook"
},
initialize: function() {
_.bindAll(this, 'addOne', 'addAll');
Books.bind('add', this.addOne);
Books.bind('refresh', this.addAll);
Books.bind('all', this.render);
Books.fetch();
},
addOne: function(book) {
var view = new BookView({model:book});
this.$('#book_table').append(view.render().el);
},
addAll: function() {
Books.each(this.addOne);
},
newAttributes: function(event) {
return { book: {
title: $('#title').val(),
description: $('#description').val(),
isbn: $('#isbn').val()
} }
},
createBook: function(e) {
e.preventDefault();
var params = this.newAttributes(e);
Books.create(params)
//TODO clear form fields
}
});
// Start the backbone app
window.App = new AppView;
});
I've determined that the cause of this was server side. Because of some scaffolded code that got generated for testing purposes, on the save, there was an additional redirect which resulted in a 302. This caused the GET after the POST. Once I cleaned up the server side code, I only get the POST, as expected.
Backbone usesPOST as a factory (getting the id from the server) with:
a payload request { title: 'None entered' }
a response { id: 12, title: 'None entered' }
It seems that your code trigger a GET action after the POST success. The code Books.bind('all', this.render) do not seems to be related to anything. It is not binded like add and there is no such method in the View.

Resources