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.
Related
The question is quite simple,
All I want is to get the data after the AJAX post saved in Vue instace's data.
Here is my code:
const VMList = new Vue({
el: '#MODAL_USER_DATA',
data: {
user: []//,
//userAcc: []
},
methods: {
getUserAcc: function ( userID ) {
this.user = { _id : userID };
var self = this
$.ajax({
url: "/listuser",
type: "POST",
data: this.user,
success: function(data) {
this.user = data ;
//this.userAcc = Object.assign({}, this.userAcc, data );
alert(JSON.stringify(this.user));//show the user correctly (e.g user = data)
$('#popupDeleteModal').modal('show');
alert(JSON.stringify(data));//show data,the entire json object,everything is good
},
error: function(err) {
console.log('error: ',err);
},
});
}
}
});
And after I trigger the getUserAcc(id) method,I try to verify the VMList.user value in browser console,and I get only the id.Seems like after the function is over the data is reset.How could I store the data from the AJAX post request in the user object from data:{...} ?
Thank you for help!!!
The problem is that this inside your ajax return function doesn't refer to the vue instance anymore.
The solution is to save the this keyword into a variable inside the function. Example:
getUserAcc: function ( userID ) {
var that = this;
this.user = { _id : userID };
$.ajax({
url: "/listuser",
type: "POST",
data: this.user,
success: function(data) {
that.user = data;
//Rest of your code
},
error: function(err) {
console.log('error: ',err);
},
});
}
Here is more information about the behavior of the keyword this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
I have a navigation bar that is pretty much the only piece of persistant template in my web application (in that is always there regardless of route).
In that navbar I show a Login link if the user is not logged in, and if they are I show their name, the problem I having is that I can't get the nav to keep it's state. The uses logins,
runLogin: function(e) {
e.preventDefault();
var element = $(e.currentTarget),
self = this;
$.when($.ajax({
url: 'http://app-api.dev/api/oauth/access_token?grant_type=password&client_id=1&client_secret=xyz',
method: 'POST',
data: element.serialize(),
dataType: 'json',
success: function(data) {
// Set the cookie, this will need to be sent in every singal request going foward.
$.cookie('access_token', data.access_token);
// So we have the access token we use this to populate our user details
},
error: function(response) {
// We can build a universal error view that would be quite and pretty easy to do.
}
})).done(function() {
$.ajax({
url: 'http://app-api.dev/api/users/me',
dataType: 'json',
method: 'GET',
success:function(user) {
self.model.set(user);
self.launchDashboard();
}
});
})
},
launchDashboard: function() {
localStorage.setItem('user', '');
localStorage.setItem('user', JSON.stringify(this.me));
App.Routes.Application.navigate('dashboard', { trigger: true } );
}
Basically I login, request my details from the API, and use those to set a model, the model I am setting has already been passed in to the navigation view, and has a change listener on it.
showUserDetails: function() {
this.loggedInUserMenu = new App.Views.navigationViewLoggedIn({
model : this.model
});
},
the above fires this,
App.Views.navigationViewLoggedIn = Backbone.View.extend({
el: '.navbar-right',
template: _.template( $('#tpl-navigation-logged-in').html() ),
events: {
},
initialize: function() {
this.render();
},
render: function() {
this.$('.li-login').replaceWith( this.template({
user: this.model.toJSON()
}));
}
});
Router
initialize: function() {
Pops.Models.AuthUser = new Pops.Models.User;
this.navigation_bar = new Pops.Views.navigationView({
model: Pops.Models.AuthUser
});
},
On successful login the loggedInNavigation is visisble, and I am at app-client.dev/#dashboard however if I navigate to `app-client.dev/#groups I lose the loggedInNavigation and it reverts back to just saying "login".
Why?
=== Edit I ahve attached the method that creates the main nav it is done on the initialize of the routes. The method that does the view update is all the in the previous code, login sets the model that is int he navigation view, listening for a change ===
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.
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.
I would like to have an infinite/endless scroll data rendering from a JSON feed. I am interested in accomplishing something similar to Pinterest or Google Reader using Backbone/Underscore/jQuery.
How do I apply the infiniScroll.js module to my backbone view? The goal is to fetch and append the next page's ("page" URL parameter) tweets when you scroll near the end of the page. Problem: when reaching the bottom of page, same JSON page feed is fetched. How to change the page parameter in the URL to be &page=2, etc.
Demo: http://dl.dropbox.com/u/19974044/test.html OR http://jsfiddle.net/k4rPP/3/
// Define the model
Tweet = Backbone.Model.extend();
// Define the collection
Tweets = Backbone.Collection.extend({
model: Tweet,
// Url to request when fetch() is called
url: 'https://api.twitter.com/1/statuses/user_timeline.json?include_entities=true&include_rts=true&trim_user=false&count=10&screen_name=cnn&page=1&callback=?',
parse: function (response) {
return response;
},
// Overwrite the sync method to pass over the Same Origin Policy
sync: function (method, model, options) {
var that = this;
var params = _.extend({
type: 'GET',
dataType: 'jsonp',
url: that.url,
processData: false
}, options);
return $.ajax(params);
}
});
// Define the View
TweetsView = Backbone.View.extend({
initialize: function () {
_.bindAll(this, 'render');
// create a collection
this.collection = new Tweets;
// Fetch the collection and call render() method
var that = this;
this.collection.fetch({
success: function () {
that.render();
}
});
// infiniScroll.js integration
this.infiniScroll = new Backbone.InfiniScroll(this.collection, {success: this.appendRender, param:'page', includePage:true});
},
// Use an extern template
template: _.template($('#tweetsTemplate').html()),
render: function () {
// Fill the html with the template and the collection
$(this.el).html(this.template({
tweets: this.collection.toJSON()
}));
}
});
var app = new TweetsView({
// define the el where the view will render
el: $('body')
});
The url attribute can be specified as a function rather than a string. So you could replace it with something like this:
...
currentPage: 0,
url: function() {
this.currentPage++;
return 'https://path.to.url/?page=' + this.currentPage;
},
...