In my index.html I call the Facebook SDK. In there I have the following code that triggers a controller in my Backbone application.
The trigger runs a function that calls the FB.api() that gets the logged in user.
The first example of backbone code works fine, but the second has a middle function that I pass the data to, but it gives me an error back from facebooks all.js file which is minified.
The reasons for wanting the middle function is to be able to fire them in different orders later on.
Facebook SDK:
FB.Event.subscribe("auth.statusChange", function (response) {
MyApp.trigger("fb:initialize", response);
});
backbone.js controller code WORKING:
initialize: function() {
App.on("fb:initialize", this.getUser);
},
getUser: function(event) {
if (event.status === "connected") {
FB.api("/me", function (response) {
if (response && !response.error) {
console.log(response);
}
});
} else {
//do nothing
}
}
backbone.js controller code NOT WORKING:
initialize: function() {
App.on("fb:initialize", this.testFunction);
},
testFunction: function(event) {
var status = event.status;
this.getUser(status);
},
getUser: function(status) {
if (status === "connected") {
FB.api("/me", function (response) {
if (response && !response.error) {
console.log(response);
}
});
} else {
//do nothing
}
}
I have tried so far using what I think is called "closures". As the FB.api() is asynchronous, this relates to the window instead of the current object. So I tried setting a variable to this outside the call. But it also doesn't work.
For example:
var oThis = this;
var apiString = '/' + this.model.id + '/photos';
FB.api(apiString, function(response){
loadPhoto(response, 1, oThis.model);
});
Try
initialize: function() {
var _this = this;
App.on("fb:initialize", function(event) {
_this.getUser(event.status);
});
},
getUser: function(status) {
if (status === "connected") {
FB.api("/me", function (response) {
if (response && !response.error) {
console.log(response);
}
});
} else {
//do nothing
}
}
or alternatively use underscore's .bind() to always bind to the right this. http://underscorejs.org/#bind
Try to use listenTo instead of App.on. Something like that:
this.listenTo(App, 'eventName', (function(_this) {
return function() {
return _this.getUser();
};
})(this));
Related
Just to make my code refactored I have written google SignOut function as follows
function googleSignOut() {
if (typeof module_google_login == 'undefined') {
return false;
}
gapi.load('auth2', function () {
var gApiAuth = gapi.auth2;
gApiAuth.init().then(doGoogleLogout(gApiAuth));
});
};
function doGoogleLogout(gApiAuth) {
console.log(gApiAuth);
var googleAuth = gApiAuth.getAuthInstance();
googleAuth.signOut().then(function () {
$.ajax({
type: 'POST',
url: '/account/logout/',
success: function () {
auth2.disconnect();
window.location = "/account";
}
});
});
}
But it gives an error in the console like this
Uncaught Error: nb
at tE (cb=gapi.loaded_0:201)
at jF.<anonymous> (cb=gapi.loaded_0:248)
at new _.C (cb=gapi.loaded_0:123)
at jF.BT (cb=gapi.loaded_0:248)
at Ay.Qv.a.<computed> [as signOut] (cb=gapi.loaded_0:227)
at doGoogleLogout (main.js:48)
at main.js:41
at platform.js:18
at Sa (platform.js:10)
at Y (platform.js:18)
But I implement it like this
function googleSignOut() {
if (typeof module_google_login == 'undefined') {
return false;
}
gapi.load('auth2', function () {
gapi.auth2.init().then(function () {
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
$.ajax({
type: 'POST',
url: '/account/logout/',
success: function () {
window.location = "/account";
}
});
});
});
});
};
then it works fine though it does not look that good. If someone can tell me what is wrong with my previous implementation and what that is not working.
Problem is with this line
gApiAuth.init().then(doGoogleLogout(gApiAuth));.
For success handler of the promise, you need to pass functional reference not call the function directly. Here doGoogleLogout(gApiAuth) will be called before the promise is resolved. Change this to gApiAuth.init().then(()=>doGoogleLogout(gApiAuth))
Read more about from this link
I have an existing function that returns an AJAX promise. I want to update this function to display a confirmation alert before running the AJAX call, but other parts of the code use this function and is already expecting a promise.
Here's what my original function looks like:
function doTheDeed() {
return $.ajax({
url: '/api/delete/123',
method: 'POST'
}).done(function () {
alert('The deed is done.');
});
}
doTheDeed().done(function {} { /*Do something else*/ });
Now I want to confirm with the user before running the AJAX call. How do maintain the API agreement of returning a promise, while waiting for the users confirmation or cancel?
function doTheDeed() {
bootbox.confirm('Are you sure?', function (result) {
if (result) {
// Too late to return a promise, promise should've been returned a long time ago
return $.ajax({
url: '/api/delete/123',
method: 'POST'
}).done(function () {
alert('The deed is done.');
});
} else {
//return what??
}
});
}
doTheDeed().done(function {} { /*Do something else*/ });
Do I need to conditionally return different promises based on the user's response?
You could use jQuery's Deferreds ?
function doTheDeed() {
var def = $.Deferred();
bootbox.confirm('Are you sure?', def.resolve);
return def.promise().then(function(result) {
return result ? $.post('/api/delete/123') : "no go";
});
}
doTheDeed().done(function (data) {
if (data == 'no go') {
// user declined
} else {
// item deleted
}
}).fail(function(err) {
// something failed
});
Building on Adeneo's answer, and adhering to the principle of promisifying at the lowest level, bootbox could be monkeypatched with a reusable promisification of bootbox.confirm(), without having to hack into bootbox itself.
If you do this then it will be appropriate :
to allow the challenge text and noGo message to be specified by the caller.
to send the noGo condition down the error path.
if(!bootbox.confirmAsync) {
bootbox.confirmAsync = function (challenge, noGoMessage) {
challenge = challenge || 'Are you sure?';
noGoMessage = noGoMessage || 'User declined';
return jQuery.Deferred(function (def) {
bootbox.confirm(challenge, function (confirmed) {
confirmed ? def.resolve() : def.reject(new Error(noGoMessage));
});
}).promise();
}
}
doTheDeed() would then comprise a totally conventional then chain starting with bootbox.confirmAsync(...), for example :
function doTheDeed () {
return bootbox.confirmAsync('Are you sure you want to delete?', 'User declined to delete')
.then(function (data) {
return $.post('/api/delete/123');
})
.then(null, function (err) {
// if user declined, then 'User declined to delete' will come back as err.message
console.log(err.message);
return err; // jQuery v<3.0
// throw err; // jQuery v>=3.0
});
}
I'm trying to call the function SetLoginButtonLabel in widget Login from inside the function SetLoginInfo -- SetLoginInfo is a call back from the widget LogInDB. When I try to call it just using this.SetLoginButtonLabel I get error SetLoginButtonLabel is undefined. I'm also trying hitch as shown below, but thats not working either. There are several different functions I'd like to call from SetLoginInfo -- How could I use hitch or some other method to make this work?
Thanks
---Widget Login
...
postCreate: function() {
var SetLab = lang.hitch(this, "SetLoginButtonLabel");
}
Login: function() //call the database
{
LoginDB.Login("http://xxx/John Smith", this.SetLoginINfo)
},
SetLoginInfo: function(LoginData) //call back from LoginDB
{
//I've tried:
this.SetLogingButtonLabel("status"); //get an undefined error
//and
SetLab("Logout");//this just seems to get lost
},
SetLoginButtonLabel: function(status)
{
//
}
.......
---Widget LoginDB
define(['dojo/store/Memory', 'dojo/_base/xhr', "dojo/data/ObjectStore", 'dojo/_base/json'],
//functions to get data and fill data stores
function (Memory, xhr, ObjectStore) {
var TicketStore;
return {
//login
Login: function (url, callback) {
xhr.get({//send data
url: url,
handleAs: "json",
load: function (result) {
var LoginData = result;
callback(LoginData);
},
error: function (err) { }
});
}
}
});
this made it work:
LoginDB.Login(s, lang.hitch(this, this.SetLoginInfo));
All of my calls within SetLoginInfo I put a this on the front:
this.SetLoginButtonLabel("Logged In");
I'm trying to save a model and on success, unrender it:
problem is that from within success i can't reference the this reference (which is the view) and I also cannot reference the variable isOk.status that this.model.save(...) returns.
the code:
save: function(e) {
e.preventDefault();
var isOk = this.model.save(null,
{
wait: true,
success: function(model, response){
console.log(response);
console.log(response.status);
},
error: function(model, response){
console.log("error");
console.log($.parseJSON(response.responseText));
$('#errorMessage').empty();
$('#errorMessage').append($.parseJSON(response.responseText).error);
$('#errorApproveModal').modal({
keyboard: true
});
}
});
console.log('logging isOk');
console.log(isOk);
//this one is working! It's on validate event
if(!isOk){
$('#errorMessage').empty();
$('#errorMessage').append("Error: there was an error");
$('#errorApproveModal').modal({
keyboard: true
});
return false
}
console.log(isOk);
**//both those checks are not working for some reason.**
//
if(isOk.status == 200 || isOk.statusText == "OK"){
console.log('in is ok');
this.remove();
}
return false;
}
Btw the view is:
App.Views.User = Backbone.View.extend({
model: App.Models.User
,
save: function...
});
Can someone please help?
Is there a better way to handle the success and error than this method?
Thanks!!
Roy
I'm not sure if this is the proper way to do it but I always just declare a variable referencing this from the view's function, then use that in success. Something like this:
save: function(e) {
// ADD THIS LINE
var me = this;
var isOk = this.model.save(null,
{
....
success: function(model, response){
// USE me IN HERE
me.render(); // e.g
},
....
}
You also can do this:
save: function(e) {
var isOk = this.model.save(null,
{
....
success: function(model, response,options){
// USE me IN HERE
this.options.me.render(); // e.g
},
//ADD me this
me : this
....
}
With the options,you can do all your parameters.
I'm trying to create a global handler that gets called before the ajax success callback. I do a lot of ajax calls with my app, and if it is an error I return a specific structure, so I need to something to run before success runs to check the response data to see if it contains an error code bit like 1/0
Sample response
{"code": "0", "message": "your code is broken"}
or
{"code": "1", "data": "return some data"}
I can't find a way to do this in jQuery out of the box, looked at prefilters, ajaxSetup and other available methods, but they don't quite pull it off, the bets I could come up with is hacking the ajax method itself a little bit:
var oFn = $.ajax;
$.ajax = function(options, a, b, c)
{
if(options.success)
{
var oFn2 = options.success;
options.success = function(response)
{
//check the response code and do some processing
ajaxPostProcess(response);
//if no error run the success function otherwise don't bother
if(response.code > 0) oFn2(response);
}
}
oFn(options, a, b, c);
};
I've been using this for a while and it works fine, but was wondering if there is a better way to do it, or something I missed in the jQuery docs.
You can build your own AJAX handler instead of using the default ajax:
var ns = {};
ns.ajax = function(options,callback){
var defaults = { //set the defaults
success: function(data){ //hijack the success handler
if(check(data)){ //checks
callback(data); //if pass, call the callback
}
}
};
$.extend(options,defaults); //merge passed options to defaults
return $.ajax(options); //send request
}
so your call, instead of $.ajax, you now use;
ns.ajax({options},function(data){
//do whatever you want with the success data
});
This solution transparently adds a custom success handler to every $.ajax() call using the duck punching technique
(function() {
var _oldAjax = $.ajax;
$.ajax = function(options) {
$.extend(options, {
success: function() {
// do your stuff
}
});
return _oldAjax(options);
};
})();
Here's a couple suggestions:
var MADE_UP_JSON_RESPONSE = {
code: 1,
message: 'my company still uses IE6'
};
function ajaxHandler(resp) {
if (resp.code == 0) ajaxSuccess(resp);
if (resp.code == 1) ajaxFail(resp);
}
function ajaxSuccess(data) {
console.log(data);
}
function ajaxFail(data) {
alert('fml...' + data.message);
}
$(function() {
//
// setup with ajaxSuccess() and call ajax as usual
//
$(document).ajaxSuccess(function() {
ajaxHandler(MADE_UP_JSON_RESPONSE);
});
$.post('/echo/json/');
// ----------------------------------------------------
// or
// ----------------------------------------------------
//
// declare the handler right in your ajax call
//
$.post('/echo/json/', function() {
ajaxHandler(MADE_UP_JSON_RESPONSE);
});
});
Working: http://jsfiddle.net/pF5cb/3/
Here is the most basic example:
$.ajaxSetup({
success: function(data){
//default code here
}
});
Feel free to look up the documentation on $.ajaxSetup()
this is your call to ajax method
function getData(newUrl, newData, callBack) {
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8",
url: newUrl,
data: newData,
dataType: "json",
ajaxSuccess: function () { alert('ajaxSuccess'); },
success: function (response) {
callBack(true, response);
if (callBack == null || callBack == undefined) {
callBack(false, null);
}
},
error: function () {
callBack(false, null);
}
});
}
and after that callback success or method success
$(document).ajaxStart(function () {
alert('ajax ajaxStart called');
});
$(document).ajaxSuccess(function () {
alert('ajax gvPerson ajaxSuccess called');
});