Search code examples
javascripthtmlangularfacebookngxs

Facebook Like Button has width 0 in Angular App


TL;DR

I inserted the exact code that the Meta Developers Page for a Facebook Like Button generated into this CodePen but the Button does not show (width & height are both 0px)

enter image description here

The Goal

In our Angular 12 Application, we want to include three things under a video:

  • Facebook Like Button
  • Facebook Share Button
  • Pinterest Pin Button

I created components for each of them and they trigger writing a script Tag to the DOM to fetch the JS Libraries (we use NGXS for asynchronous actions).

facebook-share-button.component.ts

const SCRIPT_ID = 'facebook-share-button';

@Component(...)
export class FacebookShareButtonComponent implements AfterViewInit, OnDestroy {
  @Select((state) => state.router.state.fullUrl) fullUrl$: Observable<string>;

  constructor(private store: Store) {}

  ngAfterViewInit() {
    this.store.dispatch(
      new CoreActions.LoadScript(
        SCRIPT_ID,
        'https://connect.facebook.net/de_DE/sdk.js#xfbml=1&version=v12.0',
        { async: true }
      )
    );
  }

  ngOnDestroy() {
    this.store.dispatch(new CoreActions.RemoveScript(SCRIPT_ID));
  }
}

facebook-share-button.component.html

<div class="facebook-share-button">
  <div id="fb-root"></div>
  <div
    class="fb-share-button"
    [attr.data-href]="fullUrl$ | async"
    data-layout="button"
    data-size="large"
  ></div>
</div>

The Problem

The Facebook Share Button and Pinterest Pin Button work just fine, only the Facebook Like Button does not show. It has width and height of 0px

enter image description here

enter image description here

Full code

facebook-like-button.component.ts

import { AfterViewInit, Component, OnDestroy } from '@angular/core';
import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs';
import { CoreActions } from 'src/app/core/core.actions';

const SCRIPT_ID = 'facebook-like-button';

@Component({
  selector: 'app-facebook-like-button',
  templateUrl: './facebook-like-button.component.html',
  styleUrls: ['./facebook-like-button.component.styl'],
})
export class FacebookLikeButtonComponent implements AfterViewInit, OnDestroy {
  @Select((state) => state.router.state.fullUrl) fullUrl$: Observable<string>;

  constructor(private store: Store) {}

  ngAfterViewInit() {
    this.store.dispatch(
      new CoreActions.LoadScript(
        SCRIPT_ID,
        'https://connect.facebook.net/de_DE/sdk.js#xfbml=1&version=v12.0',
        { anonymous: true, nonce: '4j5id3DJ' }
      )
    );
  }

  ngOnDestroy() {
    this.store.dispatch(new CoreActions.RemoveScript(SCRIPT_ID));
  }
}

facebook-like-button.component.html

<div class="facebook-like-button">
  <div id="fb-root"></div>
  <div
    class="fb-like"
    [attr.data-href]="fullUrl$ | async"
    data-width="77"
    data-layout="standard"
    data-action="like"
    data-size="large"
    data-share="false"
  ></div>
</div>

Things I tried

  1. Removing the facebook-share-button Component (maybe the two scripts are interfering)
  2. Placing the code in ngOnInit() (instead of ngAfterViewInit())
  3. Setting a static data-href Attribute (i.e. removing the async-Pipe)
  4. Removing <div id="fb-root"></div> in facebook-share-button.component.html or facebook-like-button.component.html or both
  5. Moving <div id="fb-root"></div> to app.component.html
  6. Playing around with the options of .fb-like and removing them one by one
  7. Setting async, defer and crossorigin to different values in the script tag
  8. Other browsers and deactivating AdBlockers
  9. Manually include the script tags
  10. Search on Stackoverflow for people with simlar problems
  11. And a combination of all of the above

but nothing worked.

In the end, I included the exact code that developers.facebook.net provided into app.component.html and it still did not work. I tried entering it in a Codepen (see above) and still there was no Button!

I feel kinda stupid. Am I doing something fundamentally wrong here...? 🤨 Can you help?


Solution

  • The Codepen you shared work for me on Google Chrome BUT only on Chrome.

    On Safari and Firefox I get Content Security Policy issues.

    Content-Security-Policy

    The issue is due to Content Security Policy (a.k.a CSP):

    Instead of blindly trusting everything that a server delivers, CSP defines the Content-Security-Policy HTTP header, which allows you to create an allowlist of sources of trusted content, and instructs the browser to only execute or render resources from those sources. Even if an attacker can find a hole through which to inject script, the script won't match the allowlist, and therefore won't be executed.

    So you need to allow the facebook paths (used to serves scripts) on your website.

    The Facebook required list is long and grows over the years, from this page you should add something like:

    script-src
      https://connect.facebook.net
      https://graph.facebook.com
      https://js.facebook.com;
    style-src
      'unsafe-inline';
    frame-src
      *.facebook.com
      connect.facebook.net;
    child-src
      *.facebook.com
      connect.facebook.net;
    img-src
      data:
      *.facebook.com
      *.facebook.net
      *.fbcdn.net;
    font-src
      data:;
    connect-src
      *.facebook.com
      connect.facebook.net;
    form-action
      *.facebook.com
      connect.facebook.net;
    

    These values above need to be added to you site default values, which should look like:

    Content-Security-Policy: default-src 'self'; img-src *; child-src: *
    

    More documentation on the CSP from Mozilla Docs.

    Useful links:

    Setting CSP via HTML tag <meta>

    You can set the CSP via the HTML <meta>, example:

    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
    

    Be aware that if you set multiple <meta http-equiv=... in your website <head> only the last one will be used others will be ignored.

    Ad Blockers, another potential issue

    if you have an ad blocker like EFF Privacy Badger or uBlock (uBlock Origin) you will need to disable theses extensions or unblock the site, then reload the codepen.

    Users with ad blockers won't see you buttons since the JS call they made will be block, on Google Chrome you will see net::ERR_BLOCKED_BY_CLIENT.

    enter image description here