2

I'am trying to call a Facebook API with AngularJS.

The problem is that all calls from FB API is Asynchronous, so I need to know when my query on facebook is avaliable to use in agularjs.

For this, I call this method in my controller:

Facebook.getLoginStatus();

which Facebook is my service, defined as:

app.factory('Facebook', function() {

    getLoginStatus: function() {

        FB.getLoginStatus(function(stsResp) {
            console.log(stsResp);
            if(stsResp.authResponse) {
                // User is already logged in
                return true;
            } else {
                // User is not logged in.
                return false;
            }
        });
    }

}

What I want in this case is to check if user is logged. If true, I'll show some options, otherwise, I'll show the Login button.

I've already try to use $q.defer() functions, promises, factorys to watch response data, everything. But anything works as I want. I've checked some development examples based on Egghead.io examples, but I think that I'm not fully understand asynchronous calls in angularjs.

Thanks in advance.

Deividi Cavarzan
  • 10,034
  • 13
  • 66
  • 80

4 Answers4

8

Here's a full basic working example of wrapping the Facebook API in an Angular service:

http://plnkr.co/edit/0GRLdWPJOzGFY14irxLT?p=preview

See also my answer to this question (which has some partial examples of Angular-FB integration):

AngularJS : Where to use promises?

Community
  • 1
  • 1
karlgold
  • 7,970
  • 2
  • 29
  • 22
  • Thanks for your reply, It was very, very helpful my friend. Just one thing: Did you know how can I maintain a transient variable that will indicate some kind a loading status? I see that you use on Pluncker the first_name, but I'll never get this variable if the Button to connect to facebook wans't shown. I don't want to force the login to FB. Thanks in advance. – Deividi Cavarzan Apr 20 '13 at 20:37
  • I am not sure if I understand the question, but check out the updated Plunker. I added a 'connected' flag that is initially set to false, and is then set to true when someone logs in. Please accept the reply if it answers the question, thanks. – karlgold Apr 20 '13 at 21:22
  • Yes, this is what I mean. Did you put on same pluncker? I didn't see any update on code. – Deividi Cavarzan Apr 20 '13 at 21:26
  • Try the link one more time, sorry maybe I needed to save the changes. You should see that the two HTML elements are conditionalized on 'user.connected' now, and this flag is initialized and updated in the application code. – karlgold Apr 20 '13 at 21:34
4

if you want to have all fb code in a slightly more angularish style, consider doing something like encapsulating the FB classes in a provider. FB is one rare example where the provider pattern is actually nice to use (to setup your app ID on the config section).

here's an example of an angular facebook provider with basic login functionality and generic method for making graph api calls:

app.provider('facebook', function() {
  var fbReady = false
  this.appID = 'Default';

  function fbInit(appID) {
    (function(d, s, id) {
      var js, fjs = d.getElementsByTagName(s)[0];
      if (d.getElementById(id)) return;
      js = d.createElement(s); js.id = id;
      js.src = "//connect.facebook.net/en_US/sdk.js";
      fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));  
    window.fbAsyncInit = function() {
     FB.init({
      appId      : appID,
      cookie     : true,  
      xfbml      : true,  
      version    : 'v2.0' 
    });
     fbReady = true;
   }   
 }

 this.setAppID = function(appID) {
  this.appID = appID;
};

this.$get = function() {
  var appID = this.appID;
  var self = this;
  fbInit(appID);

  return {
    graph : function(path, cb) {
      FB.api(path, function(response) {
        cb(response);
      });
    },
    getAuth: function() {
      return self.auth;
    },
    getLoginStatus: function(cb) {
      if (!fbReady) {
        setTimeout(function() { 
          self.$get()['getLoginStatus'](cb);
        } , 100);
        console.log('fb not ready');
        return;
      }
      FB.getLoginStatus(function(response) {
        cb(response);
      });
    },
    login: function(cb) {
      if (!fbReady) {
        self.$get()['login'](cb);
        console.log('fb not ready');
        return;
      }
      FB.login(function(response) {
        if (response.authResponse) {
          self.auth = response.authResponse;
          cb(self.auth);
        } else {
          console.log('Facebook login failed', response);
        }
      }, {"scope" : "manage_notifications"});

    },
    logout: function() {
      FB.logout(function(response) {
        if (response) {
          self.auth = null;
        } else {
          console.log('Facebook logout failed.', response);
        }

      });
    }
  }
}
});

later when you want to use it, simply set your app's ID in the config section:

app.config(function(facebookProvider){
 facebookProvider.setAppID('<your_app_id>');
})

inject it to a controller:

.controller('MainCtrl', function ($scope, facebook) {

and then perform some calls in a controller/run section:

facebook.graph('/me/notifications', onNotificationsGotten);
orcaman
  • 6,263
  • 8
  • 54
  • 69
3

I wrote this module angularjs-facebook as a provider, such that on config you configure your app id and then you can use facebook asynchronous calls. There are also methods to listen on controllers.

https://github.com/ciul/angularjs-facebook

Ciul
  • 633
  • 6
  • 7
1

Heres a good example of making asynchronous http requests with the iTunes API. It should help you figure out how to do it with the Facebook API as well.

Asynchronous HTTP requests in Angular JS