FB is undefined even though I just used it

25,197

Solution 1

The whole point of that big script block starting with window.fbAsyncInit is that the Facebook SDK gets loaded asynchronously.

Even though you've got your calls against FB inside a jQuery document ready callback, that isn't sufficient to ensure the SDK is loaded when that code is executed.

Fortunately, window.fbAsyncInit exists for exactly that purpose: it won't be run until the SDK has loaded.

From Facebook's docs:

The function assigned to window.fbAsyncInit is run as soon as the SDK is loaded. Any code that you want to run after the SDK is loaded should be placed within this function and after the call to FB.init. For example, this is where you would test the logged in status of the user or subscribe to any Facebook events in which your application is interested.

Solution 2

I had this problem and solved it similarly to the solution that Amry provided so I'm posting it here in case someone else needs to use it.

I made the initial assumption that the FB initialization call made in the fbAsyncInit method would initialize immediately, so I too coded my use of the FB object in a $(document).ready() method. That is not the case. fbAsyncInit takes quite some time after the page loads to finish initializing. Here is my solution, when using jQuery on my site:

<script type="text/javascript">

  window.fbAsyncInit = function() {

    FB.init({
      appId      : 'your_app_id', // App ID
      channelUrl : 'your channel',
      status     : true, // check login status
      cookie     : true, // enable cookies to allow the server to access the session
      xfbml      : true  // parse XFBML
    });
    jQuery(document).trigger('FBSDKLoaded'); //This is the most important line to solving the issue
  };

  // 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/en_US/all.js#xfbml=1&appId=269187653191150";
     ref.parentNode.insertBefore(js, ref);
   }(document));

</script>

The last task is to simply switch your $(document).ready() code to a bind for your event. This goes where ever you are using the FB object.

(function($) {
    $(document).bind('FBSDKLoaded', function() {
        //Code using the FB object goes here.
    });

})(jQuery);

One thing I should also mention: Firefox is a lot more tolerant of this than Webkit browsers like Chrome. I couldn't figure out why NONE of my jQuery was working properly in Chrome... well, this was why.

I hope this helps someone.

Solution 3

FB was not yet defined at that point of time. You haven't used it yet, you had simply typed it earlier up. The FB.XFMBL.parse line will execute when the document is ready. Same goes to the //connect.facebook.net/en_US/all.js line. So it's not really reliable which code will execute first if it is executed from the same event.

What you can do is somehow have the code you want be executed from window.fbAsyncInit. From that point onwards, you can be sure that FB is ready to be used.

One way you can do if you don't want to mix the code you have in widget.js is by using jQuery's custom event. So instead of having $(function() { ... });, you will have something along this line:

$(window).bind('fbAsyncInit', function() {
  // Your code here
});

Then you will have window.fbAsyncInit call $(window).triggerHandler('fbAsyncInit') just after the FB.init() line.

Share:
25,197
Dave Long
Author by

Dave Long

Application Developer with Recruitics managing the Analytics platform, I've worked across frontend, backend and database platforms constructing and optimizing a platform that currently accepts 1,000,000 requests per week.

Updated on July 09, 2022

Comments

  • Dave Long
    Dave Long almost 2 years

    I am trying to add a Facebook Like button to a widget that I am creating. The code that I use to add the Facebook like button to my page is as follows:

    widget.html

    <body>
    <div id="fb-root"></div>
    <script>
        window.fbAsyncInit = function() {
            FB.init({
                appId  : '263071593731910',
                status : false, // check login status
                cookie : true, // enable cookies to allow the server to access the session
                xfbml  : true  // parse XFBML
            });
        };
        (function() {
            var e = document.createElement('script');
            e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
            e.async = true;
            document.getElementById('fb-root').appendChild(e);
        }());
    </script>
    <div id="fb-button"></div>
    <script type="text/javascript" src="widget.js"></script>
    

    widget.js

    $(function(){
    var fb = $(document.createElement("fb:like"));
    fb.attr({
        href: data.facebook,
        send: false,
        layout: 'button_count',
        width: 70,
        'show_faces': false
    });
    $("#fb-button").empty().append(fb);
    FB.XFBML.parse($("#fb-button").get(0));
    FB.Event.subscribe('edge.create',changeView);
    });
    

    *The changeView function does exist as well in the JavaScript.

    When I run the code, I get an error: Uncaught ReferenceError: FB is not defined even though the button is created. The error is pointing to the line containing FB.XFBML.parse code. Is there something I need to do differently in my JavaScript?