How to embed multiple videos on Facebook (using React)

Reading from Facebook docs seems to be very easy to embed videos on Facebook. However, the <div id="fb-root"></div> should be immediately before the div script and fb-video class (from what I observed). Therefore, if I want to embed a video, I should do something like:

 <div className="card-video-wrapper"> <div id="fb-root"></div> <script>(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/es_ES/sdk.js#xfbml=1&version=v2.8"; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk'));</script> <div className="fb-video" data-href="my-video-url" data-show-text="false" data-autoplay="true"></div> </div> 

First, I want <div id="fb-root"></div> and the script to go right after the open tag, but this way the video is hiding at the top of the page.

The problem occurs when I want to embed several videos on Facebook, for example:

 <div className="card-video-wrapper"> <div id="fb-root"></div> <script>(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/es_ES/sdk.js#xfbml=1&version=v2.8"; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk'));</script> <div className="fb-video" data-href="my-video-url-1" data-show-text="false" data-autoplay="true"></div> </div> <div className="card-video-wrapper"> <div id="fb-root"></div> <script>(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/es_ES/sdk.js#xfbml=1&version=v2.8"; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk'));</script> <div className="fb-video" data-href="my-video-url-2" data-show-text="false" data-autoplay="true"></div> </div> 

In this case, the second is not displayed.

The <div id="fb-root"></div> is probably placed once, but, as I said, the video is hidden. Consider an example:

 <body> <div id="fb-root"></div> <script>(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/es_ES/sdk.js#xfbml=1&version=v2.8"; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk'));</script> ... <div className="card-video-wrapper"> <div className="fb-video" data-href="my-video-url-1" data-show-text="false" data-autoplay="true"></div> </div> <div className="card-video-wrapper"> <div className="fb-video" data-href="my-video-url-2" data-show-text="false" data-autoplay="true"></div> </div> ... </body> 

Checking using the navigator console I see that these styles apply to the children of the fb-root layer:

 position: absolute; top: -10000px; height: 0px; width: 0px; 

How can I embed multiple videos on Facebook?

Edit:

You might think that this should be related to CSS. However, even deleting all CSS rules, I see the same problem, videos are not displayed (even one video) when <div id="fb-root"></div> and script are placed after the source tag.

On the other hand, I tested it with a simple page (as @hackerrdave suggested) and it works. Now I am wondering what could be the problem. This is a React application that uses some components of Framework7 (I'm not sure if this may be relevant).

+7
javascript facebook reactjs
source share
4 answers

The use of Responsive matters because the first DOM rendering does not contain any fb-video element.

The problem is that the fb-video element is displayed when the component receives the elements for rendering. Then, when the SDK loads, there is no video to render. If I load the SDK after receiving the items, the videos will be shown.

Edit:

Thanks to @CBroe for the tip. The best solution is to use FB.XFBML.parse(); in componentDidMount and / or componentDidUpdate . That way I can put the <div id="fb-root"></div> and script tags after the body tag.

 componentDidMount() { FB.XFBML.parse(); } componentDidUpdate() { FB.XFBML.parse(); } 
+3
source share

This is a workaround because I could not find the problem for sure, but I still answer because it leads to something workable. You have been warned.

I found that a gap has been added to the Facebook SDK that somehow interferes. By creating your own iframe with exactly the same src and some other attributes, the video will display correctly. If Facebook has a callback somewhere that indicates when this will be done, we can use this to do just that. However, I could not find such a callback, so I decided to use MutationObserver .

The solution meat is in the onFacebookLoaded function below. Although I have not used React, I am sure this should work too. Obviously, you can change which attributes you are interested in - there is allowfullscreen among others that may make a difference.

The rest of the code below waits until Facebook uploads the video and stops listening to the changes after that. It is written in such a way that any number of videos on a page should work.

 var onFacebookLoaded = function() { // replace .fb-video div with iframe var oldFrame = this.querySelector('iframe'), newFrame = document.createElement('iframe'), attrsWeWant = new Set(); attrsWeWant.add('src').add('scrolling').add('title') .add('width').add('height').add('frameborder'); if (oldFrame.hasAttributes()) { var attrs = oldFrame.attributes; for (let i = attrs.length - 1; i >= 0; --i) { if (attrsWeWant.has(attrs[i].name)) { newFrame.setAttribute(attrs[i].name, attrs[i].value); } } } this.parentNode.replaceChild(newFrame, this); }, target = document.querySelectorAll('.fb-video'), count = target.length, observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.target.fbLoadedSeen !== true) { onFacebookLoaded.call(mutation.target); mutation.target.fbLoadedSeen = true; count--; } }); // cleanup when all videos have loaded if (count === 0) { observer.disconnect(); } }); // connect to updates for (let i = 0; i < target.length; ++i) { observer.observe(target.item(i), {attributes: true}); } 
 <div id="fb-root"></div> <script> (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 = "https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.8"; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk')); </script> <h1>Video 1</h1> <div class="fb-video" data-href="https://www.facebook.com/facebook/videos/10153231379946729/" data-width="300" data-height="300" data-allowfullscreen="true"></div> <h1>Video 2</h1> <div class="fb-video" data-href="https://www.facebook.com/facebook/videos/10153231379946729/" data-width="500" data-height="400" data-allowfullscreen="true"></div> 
+1
source share

[from another OP answer] The problem is that the fb-video element is displayed when the component receives elements for rendering. Then, when the SDK loads, there is no video to render. If I load the SDK after receiving the items, the videos will be shown.

Yes, the SDK goes through the document and looks for items to parse during initialization.

But there is a method specifically designed for rendering content that was added to the document after initializing the SDK: FB.XFBML.parse

It can be called without any arguments to view the entire document again or pass the DOM element so that it only looks at a specific DOM subtree.

+1
source share

According to the FB docs, you should only host the SDK and fb-root div:

 <!-- Load Facebook SDK for JavaScript --> <div id="fb-root"></div> <script>(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#xfbml=1&version=v2.6"; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk'));</script> 

Then for each video that you want to display, you can put the built-in video player div:

 <!-- Your embedded video player code --> <div class="fb-video" data-href="https://www.facebook.com/facebook/videos/10153231379946729/" data-width="500" data-show-text="false"></div> <div class="fb-video" data-href="https://www.facebook.com/facebook/videos/10153231379946729/" data-width="500" data-show-text="false"></div> 
0
source share

All Articles