Embed Vue component within Shopify store - javascript

Within a product page, I am trying to display a custom Vue component. For brevity, the component displays some information from a Firebase database based on the given product id.
I originally tried to make this a Shopify app so I could access their APIs. I implemented OAuth and can retrieve the required information. However, actually including the component within the store has been unsuccessful.
What is the best way of including Vue inside Shopify?
I have tried including the script files directly inside the template files, inside snippets, and included them within the global scripts tag. But nothing I have tried has been able to render even a simple component.
Inside product.liquid:
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.10/dist/vue.js"></script>
<div id="app">
{{ message }}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
</script>
Inside Vue developer tools the component appears inside the DOM but the "Hello Vue!" message does not appear as it should.
There are no other errors in the console. Which is most puzzling.
Any insight into the proper way of including Vue into Shopify would be greatly appreciated.

Liquid files will by default parse {{ }} tags. So you need to change your templating mechanism. Below is updated code which works in Shopify Liquid files -
<div id="app">
${ message }
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
delimiters: ['${', '}']
})
</script>
Basically, i have added delimeters which vue will check to find templates and they are different from Shopify Parsing which will result in shopify not parsing those holders. You can read up more about vue delimeters here - Link

Related

How to set vue-data after new vue and work for data-binding

e.g:
I need to add data-value after new vue and work for data-binding.
why i need to do that :
I know it's work if i declare first on new Vue object.
But there's a old project with a lot of layout-subject-page,if i need to add a vue global varible then i need to edit every page's vue data-value.
what i expected :
var app = new Vue({
el: '#app',
data: {}
})
app.$data.message = "test"
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h1>{{ message }}</h1>
</div>
It can't be done.
Vue runs internal setup on the initially declared data properties which won't happen if you try to declare them later.
From the docs:
Vue does not allow dynamically adding new root-level reactive properties to an already created instance.
You can add new object/array items using Vue.set if that helps you.

Declaring data in Vue with components

According to the docs, this is how you declare data in Vue:
data: {
name: 'Vue.js'
}
However, when I do that it doesn't work and an error shows in the console:
The "data" option should be a function that returns a per-instance value in component definitions.
I change it to the following and then it works fine:
data() {
return {
name: 'Vue.js',
}
}
Why do the Vue docs show the top bit of code when it doesn't work? Is there something wrong on my end?
Edit: This only happens when using components.
In a root Vue instance (which is constructed via new Vue({ . . . }), you can simply use data: { . . . } without any problems.
When you are planing to reuse Vue components using Vue.component(...) or using "template" tag, Use data attribute as a function.
Please review the corresponding section of the Vue.js documentation for more information regarding this problem
https://v2.vuejs.org/v2/guide/components.html#data-Must-Be-a-Function
You should declare data in Vue.js by doing
var app = new Vue({
el: '#app', //This is the container in which Vue will be in. The #app means the id of the container is app
data: {
}
});
It turns out you need to declare data in components different than when you set it on a Vue object.
Instead, a component’s data option must be a function, so that each instance can maintain an independent copy of the returned data object:
More: Vue docs

How can I make a third party Vue library have access to other third-party Vue plugins being used?

Let's say I'm using vuex, vue-i18n, and Syncfusion ej2-vue-grids in a project.
My app will have access to $store and $t, but if I make a grid and define a custom template for a column, the component that gets rendered in that field does not have access to vuex or vue-i18n.
I've been able to get around this for vuex by setting Vue.prototype.$store = store; when first setting up the Vue app. vue-i18n has several additional properties, though, and setting everything on the prototype feels like a hack.
I assume Syncfusion must be calling Vue.extend when creating the components for the grid column, so the component is losing all context from the app. Is this a bug on their side, or is there something I should be doing differently?
EDIT
Here is a plnkr with an example of the behavior I'm seeing.
https://plnkr.co/edit/XwVC6yNQaI2vQIUoWfSm?p=preview
When you first view it, the Freight column should be empty (because it can't access the store) and below the grid should be a line of !!!!!!!! (because it can access the store).
If you uncomment line 15 in index.js, both of line of !!!!!! below the grid and the contents of the Freight column should be visible.
We need to pass the store and vue-i18n reference to the template declaration.AS in below code snippet.
<pre>
<code>
tmpl() {
return {
template: {
store,
i18n,
data() {
return {
data: {}
}
},
computed: {
test() {
return this.$store.state.test;
}`enter code here`
},
template: `<div>
<div> Translated text child: {{ $t("message.hello") }}</div>
<span>{{ test }} {{ data.Freight }} {{ test }}</span> </div>`
}
}
}
</code>
</pre>
Plunker sample with updated column template using store: https://plnkr.co/edit/Sei9F1MEvNyLGseZEzM1?p=preview

How to dynamically compile a component added to a template in VueJS?

I am building a blog with VueJS 2. Most of my articles are stored as Markdown files, but I want to me able to cover some more advanced topics, using features that Markdown doesn't cover. I am considering making these special posts VueJS components that would be used in a template as <article-name>, or <special-article article-title="{{articleTitle}}">. Pretty simple.
I have the component loaded already, so all I need to do is compile the template string into a real template. I might be thinking too much with my AngularJS background rather than with Vue.
I can't find any solid direction for dynamically adding a component to a template in VueJS.
You can compile a template with Vue.compile. Just be aware it's not available in all builds. That's covered in the documentation.
Getting the data associated with it is a little more work.
console.clear()
const articles = [
{
title: "Testing",
articleTemplate: "<article-title></article-title>"
},
{
title: "Testing 2",
articleTemplate: "<special-article :article-title='title'></special-article>"
},
]
Vue.component("article-title",{
template: `<span>Article Title</span>`
})
Vue.component("special-article", {
props:["articleTitle"],
template: `
<div>
<h1>{{articleTitle}}</h1>
<p>Some article text</p>
</div>
`
})
new Vue({
el: "#app",
data:{
articles
},
computed:{
compiledArticles() {
return this.articles.map(a => {
// compile the template
let template = Vue.compile(a.articleTemplate)
// build a component definition object using the compile template.
// What the data function returns is up to you depending on where
// the data comes from.
return Object.assign({}, template, {data(){return a}})
})
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.min.js"></script>
<div id="app">
<component v-for="article in compiledArticles" :is="article"></component>
</div>
VueJS has a built-in component for this scenario:
<component is="article-component-name"></component>

Where to use the main variable of a new vue instance

I'm obviously missing the point somewhere here, but where does one use the main variable of a new vue instance?
I'm new to vue.js (obviously) and whilst reading various documentation I can't help notice that each new vue instance starts with something like var app = new Vue({ but then in the examples I've read this app variable doesn't get referenced again in the js or html. The code works fine without referencing it anywhere.
Could someone please kindly advise on where or why I would use the app variable?
Many thanks
It's completely not required to capture the result of new Vue() if you don't need or want to.
The reason it's done is primarily for testing (ala from the console) or for interaction with external libraries. Because all of the methods and data of the Vue are available on the variable it's possible to call those methods and use that data from outside Vue.
For example, let's say I have some logic on my page completely outside Vue that has some data I want to use inside my Vue.
const externalData = {message:"I'm some interesting data."}
const myVueApp = new Vue({
el: "#app",
data:{
message: null
}
})
myVueApp.message = externalData.message
Here the code is setting the message property of Vue from outside Vue.
This is useful primarily when you have existing code, and you are integrating Vue into that existing environment.
Another scenario is just plain testing. Open your console and run the snippet below. Change the context to the snippet's javascript:
And then type
app.message = "Hey, this is nifty!"
And the new message will be reflected in the Vue.
console.clear()
const app = new Vue({
el: "#testing",
data:{
message: "Change me from the console!"
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="testing">
{{message}}
</div>

Categories

Resources