user1012181
user1012181

Reputation: 8726

Error on creating a facebook like box component on vue

I'm trying to create a facebook like box component on vue.js. Ths SFC looks like this:

<template>
  <div>
    <div v-html="fbSdk"></div>
    <div v-if="facebookPage" class="fb-page" 
      :data-href="facebookPage" 
      data-hide-cover="false"
      data-show-facepile="true"></div>
    </div>
  </div>
</template>

<script>
  export default{
    data: {
      fbSdk: `
      <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";
        fjs.parentNode.insertBefore(js, fjs);
        }(document, 'script', 'facebook-jssdk'));
      </script>
      `
    },
    computed: {
      facebookPage(){
        return (this.$store.getters.postLogin) ? this.$store.getters.postLogin.payload.facebook_page : null;
      },
    }
  }
</script>

I know we cannot assign a script tag in the data object like I did (or am I wrong). I'm getting a compilation error as follows:

ERROR in ./~/babel-loader/lib!./~/vue-loader/lib/selector.js?type=script&index=0!./src/components/facebook-sdk/facebook-like.vue
Module build failed: SyntaxError: Unterminated template (15:12)

  13 | export default{
  14 |   data: {
> 15 |     fbSdk: `
     |             ^
  16 |     <div id="fb-root"></div>
  17 |     <script>
  18 |       (function(d, s, id) {

 @ ./src/components/facebook-sdk/facebook-like.vue 4:2-113
 @ ./~/babel-loader/lib!./~/vue-loader/lib/selector.js?type=script&index=0!./src/views/thankyou.vue
 @ ./src/views/thankyou.vue
 @ ./src/routes/index.js
 @ ./src/main.js
 @ multi ./build/dev-client ./src/main.js

Is there a better way to do this?

Upvotes: 0

Views: 1017

Answers (1)

acdcjunior
acdcjunior

Reputation: 135792

The template string problem

The presence if </script> inside the template string closes the tag (and the string), thus the "unterminated" error.

Fix: Escape the </script> by using <\/script>:

data: {
        fbSdk: `
  <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";
    fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));
  <\/script>
  `
    },

An alternative solution

Instead of adding the script, execute the code inside mounted() lifecycle hook.

First move the <div id="fb-root"></div> to the template. Second, have that logic go to the mounted, but make sure you add an if, so the <script> is not appended multiple times.

<template>
    <div>
        <div id="fb-root"></div>
        <div v-if="facebookPage" class="fb-page"
             :data-href="facebookPage"
             data-hide-cover="false"
             data-show-facepile="true"></div>
    </div>
    </div>
</template>

<script>
    export default{
        data: {},
        mounted() {
            if (!document.getElementById('facebook-jssdk')) {
                (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";
                    fjs.parentNode.insertBefore(js, fjs);
                }(document, 'script', 'facebook-jssdk'));
            }
        },
        computed: {
            facebookPage(){
                return (this.$store.getters.postLogin) ? this.$store.getters.postLogin.payload.facebook_page : null;
            },
        }
    }
</script>

A hack

Another alternative, is to use a sort of a vue hack to use <script> tag in the template. Basically you create a <vue-hack-script> component that will be rendered as <script> tag.

Example below:

<template>
  <div>
    <div id="fb-root"></div>
    <vue-hack-script v-once>
      (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";
          fjs.parentNode.insertBefore(js, fjs);
      }(document, 'script', 'facebook-jssdk'));
    </vue-hack-script>
    
    <div v-if="facebookPage" class="fb-page"
         :data-href="facebookPage"
         data-hide-cover="false"
         data-show-facepile="true">
    </div>
  </div>
</template>

<script>
  export default {
    data: {},
    computed: {
      facebookPage() {
        return (this.$store.getters.postLogin) ? this.$store.getters.postLogin.payload.facebook_page : null;
      },
    },
    components: {
      'v-hack-script': { render: function (h) { return h('script', this.$slots.default) } }
    }
  }
</script>

Upvotes: 2

Related Questions