Reputation: 8726
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
Reputation: 135792
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>
`
},
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>
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