Backbone collection not triggering add event on fetch - javascript

I have been banging my head against a wall for hours on this one....
Looked at many-a-page and I feel like I have my script correct, but my collection is not triggering an add event with add: true passed in the fetch method. I can bind to the reset event, but the add event doesn't trigger..
Model:
test.Models.AppBlock = Backbone.Model.extend({
defaults: {
AppID: null,
AppName: null,
AppDescription: null
},
idAttribute: "AppID"
});
Collection:
test.Collections.AppBlock = Backbone.Collection.extend({
model: test.Models.AppBlock,
url: ApiPath + "apps/byuser",
Loading: false,
initialize: function () {
},
getAppBlocks: function () {
if (!this.Loading) {
this.Loading = true;
this.fetch({
data: JSON.stringify({
Token: test.Session.Token
}),
add: true, // OMG WTF ?!?!
type: 'POST',
dataType: 'json',
contentType: 'application/json',
cache: false,
success: this.getAppBlocksSuccess,
error: this.getAppBlocksError
});
}
},
parse: function (response) {
return response.Data;
},
getAppBlocksSuccess: function (that, response) {
},
getAppBlocksError: function (that, response) {
}
});
View:
test.Views.DashboardLatestMain = Backbone.View.extend({
Loading: null,
initialize: function () {
this.template = _.template(test.Templates.DashboardLatestMain);
this.collection.bind('add', this.addAppBlock);
this.render();
},
render: function () {
$('#latest').prepend(this.template);
this.Loading = new test.Views.Loading({
el: '.main'
});
this.collection.getAppBlocks();
},
addAppBlock: function (appBlockModel) {
alert(appBlockModel); // no dice....
var appBlockView = new test.Views.AppBlock({
model: appBlockModel,
el: '#latest .main h3',
After: true
});
}
});
Any help is greatly appreciated.
edit
Data returned from api:
{
"Status":["1","OK"],
"Data":[{"AppID":1,"AppName":"test","AppDescription":"test"},
{"AppID":2,"AppName":"test","AppDescription":"test"}]
}

In Backbone 0.9.9 collection's fetch did a reset by default, which triggered only the 'reset' event. In 1.0, fetch does an update (now called set), and triggers 'add', 'remove' and 'change' events by default.
So, either update to 1.0 and your existing code should work. Or, add update:true to your fetch call (you don't need add:true then because that is the default).

Related

BackBone Views Events Hash

I am new to backbone and am doing a project to teach myself. For some reason I cannot get the events hash to work so I did a good amount of things in the initialize function instead. How would I use the events hash in my view below?
var PictureView = Backbone.View.extend({
el: "#app",
initialize: function() {
$('.button').click(function() {
this.request();
}.bind(this))
},
request: function(text) {
var text = $('#text').val();
this.getPicture(text, function(url) {
console.log(arguments)
//append it to the image tag;
$("#random").attr("src", url)
});
},
getPicture: function(tags, cb) {
$.getJSON(
"https://api.flickr.com/services/rest/?jsoncallback=?", {
method: 'flickr.photos.search',
tags: tags,
api_key: apiKey,
format: 'json',
nojsoncallback: 1,
per_page: 10 // you can increase this to get a bigger array
},
function(data) {
if (data.stat === 'ok') {
var photo = data.photos.photo[Math.floor(Math.random() * data.photos.photo.length)];
$.getJSON(
"https://api.flickr.com/services/rest/?jsoncallback=?", {
method: 'flickr.photos.getSizes',
api_key: apiKey,
photo_id: photo.id,
format: 'json',
nojsoncallback: 1
},
function(response) {
console.log(response);
if (response.stat === 'ok') {
var the_url = response.sizes.size[5].source;
cb(the_url);
} else {
console.log(" The request to get the picture was not good :\ ")
}
}
);
} else {
alert("no pictures found for that tag :'(");
}
}
);
}
})
Your button is outside the div with id #app. In Backbone, for the events hash to work, the elements you want to use the events on, should be inside your el.
<center><div id="app">
<center><button class="button">Click Me to add an image</button</center>
</div></center>
Now you can use the events hash as
el: "#app",
events: { 'click .button': 'request' },
initialize : function(){}

How to add multiple models to collection in Backbone

How to add multiple models to collection in Backbone
formatChannelIds: function() {
_this = this;
// var activeIds ='';
_.filter(_this.modelChannelList.toJSON(), function(channelObj) {
if (channelObj['isactive'] == true) {
// activeIds =activeIds+','+channelObj['id'];
console.log(channelObj['id']);
_this.modelChannelStats.fetch({
data: {
channel: channelObj['id']
},
processData: true
}, {
success: function(model, response, options) {
_this.channelstatsCollection.push(model);
}
});
}
});
console.log(_this.channelstatsCollection);
console.log(_this.modelChannelStats);
}
My collection shows a null in the Array.
Fetch method accepts one object containing all necessary params.
_this.modelChannelStats.fetch({
data: {
channel: channelObj['id']
},
processData: true,
success: function(model, response, options) {
_this.channelstatsCollection.push(model);
}
});
Try to use this piece of code.

using backbone with third party api

I'm trying to use backbone to grab hold of an instagram feed. This doesn't require authenticating the user, it is pulling a public feed available through:
https://api.instagram.com/v1/users/<user_id>/media/recent/?client_id=<client_id>
I've gotten as far as outputting the JSON response into the console, but I'm unable to make it display on my page.
In the code below, I use fetchData to grab the feed, and I'd like to eventually get it to a point where render outputs everything stylized on #social. However, despite setting the feed property to the JSON response, render still returns an empty object. console.log in fetchData however displays the proper information.
var social = {}
social.Instagram = Backbone.Model.extend();
social.InstagramFeed = Backbone.Collection.extend({
model: social.Instagram,
url: 'https://api.instagram.com/v1/users/<user_id>/media/recent/?client_id=<client_id>',
parse: function(response) {
return response.results;
},
sync: function(method, model, options) {
var params = _.extend({
type: 'GET',
dataType: 'jsonp',
url: this.url,
processData: false
}, options);
return $.ajax(params);
}
});
social.InstagramView = Backbone.View.extend({
el: '#social',
feed: {},
initialize: function() {
this.collection = new social.InstagramFeed();
this.fetchData();
this.render();
},
render: function() {
console.log(this.feed);
},
fetchData: function() {
this.collection.fetch({
success: function(collection, response) {
// console.log(response);
feed = response;
// console.log(this.feed);
},
error: function() {
console.log("failed to find instagram feed...");
}
});
}
});
social.instagramview = new social.InstagramView;
I've tried to output the information using just the fetchData function however this.el.append(response) results in a notice saying that el is undefined.
Your render method is called before the fetching has completed. You should bind to the sync event of the collection and call render in the event handler.
social.InstagramView = Backbone.View.extend({
el: '#social',
feed: {},
initialize: function() {
this.collection = new social.InstagramFeed();
this.fetchData();
this.collection.on('sync', function(){
this.render();
}, this);
// this.render();
},
...
})
Quoting Backbone.js documentation : sync event is fired :
when a model or collection has been successfully synced with the server.

create instance of model on AJAX call success

I have a User model:
var UserModel = Backbone.Model.extend({
defaults: {
handle: '',
email: '',
uuid: '',
userpic: '',
tokenlogin: ''
}
});
I also have a collection called UserSignIn, although I'm not sure why:
var UserSignIn = Backbone.Collection.extend({ model: UserModel });
And inside of my SignInView view, I have the following function...
signIn: function(e) {
e.preventDefault();
this.collection.fetch({
type: 'POST',
url: 'http://localhost/app/api/User.php',
dataType: "json",
data: $.param({
req: "REQUSERSIGNIN",
platform: "WEB",
useremail: $('#userSignIn #userEmail').val(),
userpass: $('#userSignIn #userPassword').val()
}),
success: function(data) {
// In here, I'd like to create an
// instance of the model which I'd
// like to pass around my app.
var user = new UserModel({
handle: data.HANDLE,
email: data.EMAIL,
uuid: data.UUIDUSER,
userpic: data.USERPIC,
tokenlogin: data.TOKENLOGIN
});
}
});
}
As you can see, all I am trying to do is create an instance of a User on success of the BackBone.fetch() function.
I'd like to understand how to then pass around this new "user" UserModel() instance around my app. When I try to console.log(user) I get a "ReferenceError: user is not defined" when clearly I just created it in the success callback of the fetch function.
Can someone explain to me why?
you have to insert it into your collection if you wanna follow the right way in backbone.
I think that you can do this:
into your initialize in the view insert this:
initialize: function(){
//..... your code in initialize
this.userModel = null;
this.collection = new UserCollection();
},
signIn: function(e) {
e.preventDefault();
var here = this;
this.collection.fetch({
type: 'POST',
url: 'http://localhost/app/api/User.php',
dataType: "json",
data: $.param({
req: "REQUSERSIGNIN",
platform: "WEB",
useremail: $('#userSignIn #userEmail').val(),
userpass: $('#userSignIn #userPassword').val()
}),
success: function(data) {
var user = {handle: data.HANDLE,email: data.EMAIL,uuid: data.UUIDUSER,userpic: data.USERPIC,tokenlogin: data.TOKENLOGIN};
here.userModel = new UserModel(user);
here.collection.addUser(here.userModel);
}
});
}
You UserCollection must be something like this:
var UserCollection = Backbone.Collection.extend({
model: UserModel,
initialize:function(){
console.log('Initialized User collection');
},
addUser: function(users, options) {
return this.add(users, options);
}
});
To console each element of your collection you can try this (if you run this code inside your success function use here instead of this):
this.collection.each(function(user, index) {
console.log(user);
//if you want to set a value of your model:
user.set('email', 'yournewemail#email.it');
//if you want to get some value
user.get('email');
});
The variable user is scoped only to within the success function of your SignInView view, so you can't console.log(user) which is looking for a user variable from the global scope. You could put console.log(user) right after creating the user within the success function to see that it is created, since this would find the local variable user.
To access it from the app, you could also declare var user; outside the fetch function and then simply set it within the fetch function.

Difference between $.ajax() and Backbone's .fetch() or .save() functions?

I'm trying to set data on my user model via the "signIn" function in my view:
initialize: function() {
console.log('Sign in view initialized');
this.render();
this.userModel = new UserModel();
this.collection = new UserCollection();
},
signIn: function(e) {
e.preventDefault();
var self = this;
$.ajax({
type: 'POST',
url: 'http://localhost/app/api/User.php',
dataType: "json",
data: $.param({
req: "REQUSERSIGNIN",
platform: "WEB",
useremail: $('#userSignIn #userEmail').val(),
userpass: $('#userSignIn #userPassword').val()
}),
success: function(response) {
self.userModel.set({
handle: response.HANDLE,
email: response.EMAIL,
uuid: response.UUIDUSER,
userpic: response.USERPIC,
tokenlogin: response.TOKENLOGIN
});
console.log(self.userModel.get("tokenlogin"));
}
});
},
I've read that the .fetch() or .save() is the backbone way of doing things, but I can't seem to set my UserModel when I use fetch. When I do it the jQuery.ajax() way though, it acts as desired.
Can someone explain to me the difference between doing it in $.ajax() or doing it via .fetch etc.
edit:
Here is my model code
var UserModel = Backbone.Model.extend({
defaults: {
handle: '',
email: '',
uuid: '',
userpic: '',
tokenlogin: ''
},
});
You should be able to do this by overriding your model's fetch method:
UserModel = Backbone.model.extend({
defaults: {
// ....
},
// set url for model (assumes app root is http://localhost/app)
url: '/api/User.php',
// pass custom parameters on fetch
fetch: function (options) {
var options = _.clone(options);
// set our custom parameters
options.req = "REQUSERSIGNIN";
options.platform = "WEB";
options.useremail = $('#userSignIn #userEmail').val();
options.userpass = $('#userSignIn #userPassword').val();
// call the Backbone method, which in turn calls $.ajax
Backbone.sync.apply(this, options);
},
});
Your model's Parse method should handle the response from the server just fine, since it seems like there is a one to one (response.handle will match model.attributes.handle). Without seeing the actual response it is a bit hard to know.

Categories

Resources