FB is undefined even though I just used it
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?
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.
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.
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.
精彩评论