17

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 ?

Gal Ben-Haim
  • 17,433
  • 22
  • 78
  • 131

5 Answers5

5

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.

Ben Lesh
  • 107,825
  • 47
  • 247
  • 232
  • should I init the SDK async in the html like Facebook suggest or the init is done in the factory and the html only includes the sdk ? – Gal Ben-Haim Dec 10 '12 at 19:27
  • the code seems to be working, but data bindings doesn't work with async calls, I tried using $q and $scope.$apply in the controller and got it to partially work. but I read that a controller is a bad place to put those. so how do I change the factory to work with those async API calls ? – Gal Ben-Haim Dec 10 '12 at 20:17
  • 3
    Just to expand on @blesh answer. Check this more developed example: http://jsfiddle.net/bradbirdsall/ggmRQ/6/ – elviejo79 Feb 13 '13 at 23:50
5

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));
hugo der hungrige
  • 12,382
  • 9
  • 57
  • 84
1

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

Ciul
  • 633
  • 6
  • 7
0

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.

Dzung Nguyen
  • 9,152
  • 14
  • 65
  • 104
0

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();

Max
  • 454
  • 4
  • 10