how to properly inject Facebook JavaScript SDK to AngularJS controllers?

All we need is an easy explanation of the problem, so here it is.

I’m new to AnuglarJS and already built a small web-app with it,
I would like to use the Facebook JavaScript SDK with it, but using best practices (dependency injecting to controllers, to maintain app structure and testability).

I found this https://groups.google.com/forum/#!msg/angular/bAVx58yJyLE/Kz56Rw-cQREJ
but its very confusing for someone new to this framework (modules, services and factories are not explained well IMHO).

so, what is the proper way to use the Facebook SDK inside an AngularJS app ?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

I have actually had to do this… I don’t have the code with me, and it’s probably proprietary anyhow… but it was essentially like this:

// create a simple factory:    
app.factory('facebook', ['$window', function($window) {

    //get FB from the global (window) variable.
    var FB = $window.FB;

    // gripe if it's not there.
    if(!FB) throw new Error('Facebook not loaded');

    //make sure FB is initialized.
    FB.init({
       appId : 'YOUR_APP_ID'
    });

    return {
        // a me function
        me: function(callback) {
            FB.api('/me', callback);
        }

        //TODO: Add any other functions you need here, login() for example.
    }
}]);

// then you can use it like so:
app.controller('SomeCtrl', function($scope, facebook) {

    //something to call on a click.
    $scope.testMe = function() {

       //call our service function.
       facebook.me(function(data) {
          $scope.facebookUser = data;

          //probably need to $apply() this when it returns.
          // since it's async.
          $scope.$apply();
       });
    };
});

If there are any errors in that let me know, and I’ll look up the working code I have and see what I’ve missed. But that should be about it.

Method 2

2015 EDIT !

This is an old answer. I’ll suggest you check out how the popular angular-modules on github do it or simply use them:

Old Answer

Because of problems with calls at the start of the app I use the following approach, which loads the app only after the SDK has been loaded:

window.fbAsyncInit = function () {
FB.init({
    appId: window.fbConfig.appID,
    channelUrl: '//' + window.location.hostname + window.location.pathname + 'channel.php',
    status: window.fbConfig.oInitOptions.bStatus || true,
    cookie: window.fbConfig.oInitOptions.bCookie || true,
    xfbml: window.fbConfig.oInitOptions.bXfbml || true
});


// Get Login Status once at init
window.FB.getLoginStatus(function (oResponse) {
    if (oResponse && oResponse.status) {
        window.fbConfig.sAuthStatus = oResponse.status;
    }

    // Bootstrap app here only after the sdk has been loaded
    angular.bootstrap(document.body, ['fbAngularApp']);
});
};

// Load the SDK Asynchronously
(function (d) {
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {
    return;
}
js = d.createElement('script');
js.id = id;
js.async = true;
js.src = '//connect.facebook.net/' + window.fbConfig.lng + '/all.js';
ref.parentNode.insertBefore(js, ref);
}(document));

Method 3

I have written this angularjs-facebook service.
First you init it on your app module config method to initialize your facebook app id and other settings.

Then you just enjoy calling the Facebook service from Controllers and calling Facebook methods asynchronous just as normal.

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

Method 4

The only way that works is including the the sdk in your index page in the old way.

Because I have implemented the same solution from @blesh or extended version from @elviejo, both of them has a problem if we have a function which is called when the controller is invoked, the chance that FB is not initialized is very high and this will make the call failed while calling a function from undefined 🙂

Hope this will help others avoiding headache with this.

Method 5

I was stumped on this for a while, I solved it with a $watch

//setup watch for FB API to be ready
//note that since you use $window, you need to inject it into your controller
//angular.module('myApp').controller('appController', function ($scope, $window, ...) {
$scope.FBListener = $scope.$watch(function () {
  return $window.FB;
}, function (newVal, oldVal) {
  // FB API loaded, make calls
  console.log("FB is ready");
  //functions that do FB API calls
  $scope.getFBEvents();
  $scope.getFBPosts();
});

when FB has been loaded, you can clear the $watch (which is probably best to do for performance) by calling $scope.FBListener();

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply