I have had problems where I am getting a null value from my store... sometimes, and only on some values. If anyone could point me in the right direction and explain why it is wrong... I would be really grateful. So here is the deal my store.getters.getApiKey is sometimes "" and sometimes not.
So... in the component vue below, it is not null on the first reference
{{this.$store.getters.getApiKey}}
and then within the mounted section, store.getters.getHostUrl is set, but store.getters.getApiKey keeps returning "".
Here are the details:
the Component.vue
<template>
<div class="countryCodes">
<p>ApiKey : {{this.$store.getters.getApiKey}}</p>
<p>CountryCode Data is {{ page }}</p>
<div class="CountryCodes">
<tr v-for="ccdata in content_list" v-bind:key="ccdata.guid">
<td>{{ ccdata.guid }}</td>
<td>{{ ccdata.name }}</td>
<td>{{ ccdata.code }}</td>
</tr>
</div>
</div>
</template>
import axios from "axios";
import store from "#/store";
export default {
name: 'CountryCodes',
data () {
return {
page: "",
content_list: []
}
},
mounted () {
axios({ method: "GET", "url": store.getters.getHostUrl + "
"/api/"+store.getters.getApiKey+"/countryCodes" }).then(result => {
this.page = result.data.page;
this.content_list = result.data.contents;
}, error => {
console.error(error);
});
},
methods: {
}
}
</script>
Then my store (store.js) looks like this...
import Vuex from "vuex";
import Vue from 'vue';
Vue.use(Vuex)
export default new Vuex.Store({
state: {
apiKey: "",
hostUrl:""
},
mutations: {
SET_APIKEY(state, value) { state.apiKey = value; },
SET_HOST_URL(state, value) {state.hostUrl = value; }
},
getters: {
getApiKey(state) { return state.apiKey; },
getHostUrl(state) { return state.hostUrl; }
}
})
finally in my main.js I commit the data to the store... :
import Vue from 'vue'
import App from './App.vue'
import router from './router/index.js'
import store from './store.js'
new Vue({
el: '#app',
render: h => h(App),
router,
store,
mounted: function() {
console.log(this.$route.query)
store.commit('SET_APIKEY', this.$route.query.api)
store.commit("SET_HOST_URL", location.origin.toString())
}
})
I have the same problem when trying to build a http service, where the store is null for the apikey. What magic am I missing?
Usually the mounted hook of child component is called before the mounted of parent component.
From Vue Parent and Child lifecycle hooks
If you try to console.log on both mounted hook you will see the order of execution (but I'm still not sure why your store.getters.getHostUrl is set).
So you need a watcher to run your code after your store has value.
Example code:
...
computed: { // or use another getters
url () {
if (!store.getters.getHostUrl || !store.getters.getApiKey) return
return `${store.getters.getHostUrl}/api/${store.getters.getApiKey}/countryCodes`
}
},
watch: {
url (value) {
...
}
}
...
CodeSandbox
So.... there were two ways of solving this..... thank you to both comments.
Switch my mounted in the main.js to created- the diagram above explains why... as well as the nice article.
add "await store.getters.getApiKey"
Related
HelloWorld.vue
import axios from "axios";
export const router = () => axios.get("https://fakestoreapi.com/products");
<template>
<div>
<div v-for="item in items" :key="item.id">
<b> id: {{ item.id }}</b>
<router-link
:to="`/${item.id}`"
>
{{ item.title }}
</router-link>
</div><!-- end v-for -->
<router-view></router-view>
</div>
</template>
<script>
import { router } from "./router";
export default {
name: "HelloWorld",
components: {},
data() {
return {
items: [],
};
},
mounted() {
router().then((r) => {
this.items = r.data;
});
},
};
</script>
User.vue
import axios from "axios";
export const routerid = (itemId) =>
axios.get("https://fakestoreapi.com/products/" + itemId);
<template>
<div>
<div v-if="item">
<h1>Price: {{ item.price }}</h1>
</div>
<tabs />
</div>
</template>
<script>
import { routerid } from "./routerid";
import tabs from "./tabs";
export default {
name: "User",
components: {
tabs,
},
data() {
return {
item: null,
};
},
mounted() {
this.loadData();
},
computed: {
routeId() {
return this.$route.params.id;
},
},
watch: {
routeId() {
console.log("Reload (route change)");
this.loadData();
}, //reload when route id changes
},
methods: {
loadData() {
console.log("Reloading, ID", this.routeId);
if (!this.routeId) return; // no ID, leave early
routerid(this.$route.params.id).then((item) => {
this.item = item.data;
});
},
},
};
</script>
tabs.vue
import axios from "axios";
export const tabsandcontent = async (itemId) =>
await axios.get("https://fakestoreapi.com/products?limit=" + itemId);
<template>
<div>
<div v-if="item">
<h1>description: {{ item.description }}</h1>
</div>
</div>
</template>
<script>
import { tabsandcontent } from "./tabsandcontent";
export default {
name: "User",
components: {},
data() {
return {
item: null,
};
},
mounted() {
this.loadData();
},
computed: {
tabsandcontent() {
return this.$route.params.id;
},
},
watch: {
tabsandcontent() {
console.log("Reload (route change)");
this.loadData();
}, //reload when route id changes
},
methods: {
loadData() {
console.log("Reloading, ID", this.tabsandcontent);
if (!this.tabsandcontent) return; // no ID, leave early
tabsandcontent(this.$route.params.id).then((item) => {
this.item = item.data;
});
},
},
};
</script>
main.js
import Vue from "vue";
import App from "./App.vue";
import VueRouter from "vue-router";
import HelloWorld from "./components/HelloWorld";
import User from "./components/User";
Vue.use(VueRouter);
const router = new VueRouter({
routes: [
{
path: "/HelloWorld",
name: "HelloWorld",
component: HelloWorld,
children: [{ path: ":id", name: "User", component: User }]
}
]
});
Vue.config.productionTip = false;
new Vue({
router,
render: (h) => h(App)
}).$mount("#app");
code:- https://codesandbox.io/s/combined-logic-api-forked-41lh0f?file=/src/main.js
can you please answer this, In main.js routing I changed from path: "/" to path: "/HelloWorld" then all of sudden output not reflecting... because in my project path:'/' indicates login page??? In this scenario what changes, i need to make, to make logic work
also where is the relation between path:'/' and api call??
You have same name for the variables in tabs component (In watch and computed). And In tabsandcontent.js, you have missed to fetch description for the specific item as performed in routerId.js.
Have a look at modified version which is working as you expected.
https://codesandbox.io/embed/combined-logic-api-forked-ji5oh4?fontsize=14&hidenavigation=1&theme=dark
First thing first, I want you to know that I don't understand what are you asking for. But I'm going to try to answer.
Your first question:
In main.js routing I changed from path: "/" to path: "/HelloWorld" then all of sudden output not reflecting.
Yes, you will not see your HelloWorld.vue component. You can see your page however if you type <your-url>/HelloWorld. Usually the / path is used for something like "Home" page.
However, I've tried checking out your codesandbox. And take a look at your HelloWorld.vue component.
I think you are confused because when you changed the path from / to /HelloWorld apart from the HelloWorld.vue not showing up. It somehow broken the link which causes the API in tabs.vue not functioning.
If that's the case, you just have to simply add HelloWorld/${item.id} in tabs.vue,
<template>
<div>
<div v-for="item in items" :key="item.id">
<b> id: {{ item.id }}</b>
<router-link
:to="`HelloWorld/${item.id}`" // --> Notice this line
>
{{ item.title }}
</router-link>
</div><!-- end v-for -->
<router-view></router-view>
</div>
</template>
This however, isn't a common thing to do routing. You should add your App URLs to main.js. Which also isn't common, but I'm assuming this is just a little reproduction code you made for StackOverflow.
Here are my CodeSandbox edits.
https://codesandbox.io/s/combined-logic-api-forked-jttt8p
I will update the answer again later, I'm still not on my personal laptop.
Hi Guys i'm trying to create a look something like Bootstrap Nav Tabs but with Vuejs and Vue Router i also want to change the url in browser
here is my code for VueRouter
it is working fine but the Parent component(UserProfile) get re-render every time i switch between UserProfilePosts or UserDetails because i know my code going to be larger and this is not a good user experience,Thanks
{
path:'/:id',
component:UserProfile,
children: [
{ path: '', component: UserProfilePosts },
{ path: 'details', component: UserDetails },
],
meta:{
requiresAuth:true
}
}
Main Component(UserProfile):
<template>
<div class="container-fluid">
<h1>UserProfile</h1>
<router-link to="/username">Post's</router-link>
<router-link to="/username/details">Details</router-link>
<router-view></router-view>
</div>
<script>
export default{
created(){
console.log('created');
}
}</script>
You can try using Vuex with vex-persist. Vue refresh and reload the html each time it is asked. I am new to vue and this was how I implemented it, though it may not be the best solution.
VueX is the one central source of truth that your components can look for information. It will be easier passing down as prop and all the components just head to the 'store' for information
This stores the information as a local / session storage. For more information check out : https://github.com/championswimmer/vuex-persistuex-persist
import Vue from 'vue'
import Vuex from 'vuex'
import VuexPersistence from 'vuex-persist'
const vuexLocal = new VuexPersistence({
storage: window.sessionStorage
})
Vue.use(Vuex)
export default new Vuex.Store({
plugins: [vuexLocal.plugin],
state: {
database: []
},
mutations: {
pushToDatabase: (state, val) => {
state.database.push (val}
}
},
getters: {
getData: state => {
return state.database
}
}
})
I'm using Vuex stores in a "feature-scope structure" for the first time and have been having difficulties tracing why I am getting a [vuex] unknown getter: $_kp/kp - (Vue/Vuex isn't throwing much of a bone with this other than just the quoted error).
UPDATE: I turned on store.subscribeAction() to see if that give up any more info. Here is the printed log (I'm not seeing any this useful but hopefully it helps you).
Action Type: $_kp/getKpIndex
Action Payload: undefined
Current State: {ob: Observer} $_kp: Object kp: "2" //<- That is what I'm trying to get - "2"!
UPDATE-2: I'm using Vues Inspector now as well and it shows the following:
| State
| - $_kp: object
| - kp: "3"
| Mutation
| - payload: "3"
| - type: "$_kp/KP_DATA_UPDATED"
Any help with this is greatly appreciated and I hope this can be useful for who sets their stores in this manner.
SomeElement.vue:
<script>
import {mapGetters} from 'vuex';
import store from '../_store';
export default {
name : 'KpIndexElement',
parent: 'AVWX',
computed: {
...mapGetters({
kp: '$_kp/kp', //<-- HERE?
}),
},
created() {
const STORE_KEY = '$_kp';
if (!(STORE_KEY in this.$store._modules.root._children)) {//<= I think there is an issue with this too
this.$store.registerModule(STORE_KEY, store);
}
},
mounted() {
this.$store.dispatch('$_kp/getKpIndex');
},
}
</script>
<template>
<p><strong>Kp: </strong>{{ kp }}</p>
</template>
The Store index.js
import actions from './actions';
import getters from './getters';
import mutations from './mutations';
var state = {
kp: '',
};
export default {
namespaced: true,
state,
actions,
getters,
mutations,
};
actions.js:
import api from '../_api/server';
const getKpIndex = (context) => {
api.fetchKpData
.then((response) => {
console.log('fetch response: ' + response)
context.commit('KP_DATA_UPDATED', response);
})
.catch((error) => {
console.error(error);
})
}
export default {
getKpIndex,
}
mutations.js
const KP_DATA_UPDATED = (state, kp) => {
state.kp = kp;
}
export default {
KP_DATA_UPDATED,
}
...and finally the getters.js
const kp = state => state.kp;
export {
kp,
};
Syntax for mapGetters when using namespaces is as follows :
...mapGetters('namespace', [
'getter1',
'getter2',
... // Other getters
])
In your case :
...mapGetters('$_kp', [
'kp'
])
The first argument is the namespace, the second the payload containing the getters you want to use.
Also, as noted in the comments by #Ijubadr, I'm not sure mapGetters is evaluated after you registered your store module. To work around that, you might have to drop the use of mapGetters and declare your STORE_KEY as a data, then define a computed getter using STORE_KEY in its definition (I renamed it storeKey in the example below since this is no longer a constant):
computed: mapState('$_kp',{
kpIndex: 'kp'
}),
created() {
this.storeKey = '$_kp';
if (!(this.storeKey in this.$store._modules.root._children)) {
this.$store.registerModule(this.storeKey, store);
}
},
mounted() {
this.$store.dispatch('$_kp/getKpIndex');
}
This was the question got me stuck for a little bit. Unfortunately, I coudn't find answer here (asking also didn't help). So after doing some research and asking here and there, it seems that I got the solution to this issue.
If you have a question that you already know the answer to, and you
would like to document that knowledge in public so that others
(including yourself) can find it later.
Of course, my answer may not be the ideal one, moreover I know it is not, that's the key point why I'm posting - to improve it.
Note, I'm not using actions in example. The idea is the same.
Let's begin with stating the problem:
Imagine we have App.vue which dynamically generates its local component named Hello.
<template>
<div id="app">
<div>
<hello v-for="i in jobs" :key="i" :id="i"></hello>
<button #click="addJob">New</button>
</div>
</div>
</template>
<script>
import Hello from './components/Hello'
export default {
components: {
Hello
}...
store.js
export const store = new Vuex.Store({
state: {
jobs: []
}
})
We are using v-for directive to generate components by iterating through an array jobs. Our store as of now consists of only state with an empty array.
Button New should do 2 things:
1) create new component Hello, in other words add element to jobs (let it be numbers), which are going to be assigned as key and id of <hello>, and passed to local component as props.
2) generate local stores - modules - to keep any data scoped to newly created components.
Hello.vue
<template>
<div>
<input type="number" :value="count">
<button #click="updateCountPlus">+1</button>
</div>
</template>
export default {
props: ['id']
}
Simple component - input with a button adding 1.
Our goal is to design something like this:
For the first operation of NEW button - generating components - we add mutation to our store.js
mutations: {
addJob (state) {
state.jobs.push(state.jobs.length + 1)
...
}
Second, creating local modules. Here we're going to use reusableModule to generated multiple instances of a module. That module we keep in separate file for convinience. Also, note use of function for declaring module state.
const state = () => {
return {
count: 0
}
}
const getters = {
count: (state) => state.count
}
const mutations = {
updateCountPlus (state) {
state.count++
}
}
export default {
state,
getters,
mutations
}
To use reusableModule we import it and apply dynamic module registration.
store.js
import module from './reusableModule'
const {state: stateModule, getters, mutations} = module
export const store = new Vuex.Store({
state: {
jobs: []
},
mutations: {
addJob (state) {
state.jobs.push(state.jobs.length + 1)
store.registerModule(`module${state.jobs.length}`, {
state: stateModule,
getters,
mutations,
namespaced: true // making our module reusable
})
}
}
})
After, we're going to link Hello.vue with its storage. We may need state, getters, mutations, actions from vuex. To access storage we need to create our getters. Same with mutations.
Home.vue
<script>
export default {
props: ['id'],
computed: {
count () {
return this.$store.getters[`module${this.id}/count`]
}
},
methods: {
updateCountPlus () {
this.$store.commit(`module${this.id}/updateCountPlus`)
}
}
}
</script>
Imagine we have lots of getters, mutations and actions. Why not use {mapGetters} or {mapMutations}? When we have several modules and we know the path to module needed, we can do it. Unfortunately, we do not have access to module name.
The code is run when the component's module is executed (when your app
is booting), not when the component is created. So these helpers can
only be used if you know the module name ahead of time.
There is little help here. We can separate our getters and mutations and then import them as an object and keep it clean.
<script>
import computed from '../store/moduleGetters'
import methods from '../store/moduleMutations'
export default {
props: ['id'],
computed,
methods
}
</script>
Returning to App component. We have to commit our mutation and also let's create some getter for App. To show how can we access data located into modules.
store.js
export const store = new Vuex.Store({
state: {
jobs: []
},
getters: {
jobs: state => state.jobs,
sumAll (state, getters) {
let s = 0
for (let i = 1; i <= state.jobs.length; i++) {
s += getters[`module${i}/count`]
}
return s
}
}
...
Finishing code in App component
<script>
import Hello from './components/Hello'
import {mapMutations, mapGetters} from 'vuex'
export default {
components: {
Hello
},
computed: {
...mapGetters([
'jobs',
'sumAll'
])
},
methods: {
...mapMutations([
'addJob'
])
}
}
</script>
Hi and thank you for posting your question and your solution.
I started learning Vuex couple days ago and came across a similar problem. I've checked your solution and came up with mine which doesn't require registering new modules. I find it to be quite an overkill and to be honest I don't understand why you do it. There is always a possibility I've misunderstood the problem.
I've created a copy of your markup with a few differences for clarity and demonstration purposes.
I've got:
JobList.vue - main custom component
Job.vue - job-list child custom component
jobs.js - vuex store module file
JobList.vue (which is responsible for wrapping the job(s) list items)
<template>
<div>
<job v-for="(job, index) in jobs" :data="job" :key="job.id"></job>
<h3>Create New Job</h3>
<form #submit.prevent="addJob">
<input type="text" v-model="newJobName" required>
<button type="submit">Add Job</button>
</form>
</div>
</template>
<script>
import store from '../store/index'
import job from './job';
export default {
components: { job },
data() {
return {
newJobName: ''
};
},
computed: {
jobs() {
return store.state.jobs.jobs;
}
},
methods: {
addJob() {
store.dispatch('newJob', this.newJobName);
}
}
}
</script>
The Job
<template>
<div>
<h5>Id: {{ data.id }}</h5>
<h4>{{ data.name }}</h4>
<p>{{ data.active}}</p>
<button type="button" #click="toggleJobState">Toggle</button>
<hr>
</div>
</template>
<script>
import store from '../store/index'
export default {
props: ['data'],
methods: {
toggleJobState() {
store.dispatch('toggleJobState', this.data.id);
}
}
}
</script>
And finally the jobs.js Vuex module file:
export default {
state: {
jobs: [
{
id: 1,
name: 'light',
active: false
},
{
id: 2,
name: 'medium',
active: false
},
{
id: 3,
name: 'heavy',
active: false
}
]
},
actions: { //methods
newJob(context, jobName) {
context.state.jobs.push({
id: context.getters.newJobId,
name: jobName,
active: false
});
},
toggleJobState(context, id) {
context.state.jobs.forEach((job) => {
if(job.id === id) { job.active = !job.active; }
})
}
},
getters: { //computed properties
newJobId(state) { return state.jobs.length + 1; }
}
}
It's possible to add new jobs to the store and as the "active" property suggest, you can control every single individual job without the need for a new custom vuex module.
I'm currently making use of the WordPress REST API, and vue-router to transition between pages on a small single page site. However, when I make an AJAX call to the server using the REST API, the data loads, but only after the page has already rendered.
The vue-router documentation provides insight in regards to how to load data before and after navigating to each route, but I'd like to know how to load all route and page data on the initial page load, circumventing the need to load data each time a route is activated.
Note, I'm loading my data into the acf property, and then accessing it within a .vue file component using this.$parent.acfs.
main.js Router Code:
const router = new VueRouter({
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About },
{ path: '/tickets', component: Tickets },
{ path: '/sponsors', component: Sponsors },
],
hashbang: false
});
exports.router = router;
const app = new Vue({
router,
data: {
acfs: ''
},
created() {
$.ajax({
url: 'http://localhost/placeholder/wp-json/acf/v2/page/2',
type: 'GET',
success: function(response) {
console.log(response);
this.acfs = response.acf;
// this.backgroundImage = response.acf.background_image.url
}.bind(this)
})
}
}).$mount('#app')
Home.vue Component Code:
export default {
name: 'about',
data () {
return {
acf: this.$parent.acfs,
}
},
}
Any ideas?
My approach is to delay construction of the store and main Vue until my AJAX call has returned.
store.js
import Vue from 'vue';
import Vuex from 'vuex';
import actions from './actions';
import getters from './getters';
import mutations from './mutations';
Vue.use(Vuex);
function builder(data) {
return new Vuex.Store({
state: {
exams: data,
},
actions,
getters,
mutations,
});
}
export default builder;
main.js
import Vue from 'vue';
import VueResource from 'vue-resource';
import App from './App';
import router from './router';
import store from './store';
Vue.config.productionTip = false;
Vue.use(VueResource);
Vue.http.options.root = 'https://miguelmartinez.com/api/';
Vue.http.get('data')
.then(response => response.json())
.then((data) => {
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store: store(data),
template: '<App/>',
components: { App },
});
});
I have used this approach with other frameworks such as Angular and ExtJS.
You can use navigation guards.
On a specific component, it would look like this:
export default {
beforeRouteEnter (to, from, next) {
// my ajax call
}
};
You can also add a navigation guard to all components:
router.beforeEach((to, from, next) => {
// my ajax call
});
One thing to remember is that navigation guards are async, so you need to call the next() callback when the data loading is finished. A real example from my app (where the guard function resides in a separate file):
export default function(to, from, next) {
Promise.all([
IngredientTypes.init(),
Units.init(),
MashTypes.init()
]).then(() => {
next();
});
};
In your case, you'd need to call next() in the success callback, of course.
I've comprised my own version based on all the great responses to this post.. and several years having passed by as well giving me more tools.
In main.js, I use async/await to call a prefetch service to load any data that must be there on startup. I find this increases readability. After I get the data comms, I then dispatch it to the appropriate vuex store module in the beforeCreate() hook.
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import { prefetchAppData } from '#/services/prefetch.service';
(async () => {
let comms = await prefetchAppData();
new Vue({
router,
store,
beforeCreate() {
store.dispatch('communityModule/initialize', comms);
},
mounted() {},
render: h => h(App)
}).$mount('#app');
})();
I feel compelled to warn those be careful what you prefetch. Try to do this sparingly as it does delay initial app loading which is not ideal for a good user experience.
Here's my sample prefetch.service.js which does the data load. This of course could be more sophisticated.
import api from '#api/community.api';
export async function prefetchAppData() {
return await api.getCommunities();
}
A simple vue store. This store maintains a list of 'communities' that the app requires to be loaded before application start.
community.store.js (note im using vuex modules)
export const communityModule = {
namespaced: true,
state: {
communities: []
},
getters: {
communities(state) {
return state.communities;
},
},
mutations: {
SET_COMMUNITIES(state, communities) {
state.communities = communities;
}
},
actions: {
// instead of loading data here, it is passed in
initialize({ commit }, comms) {
commit('SET_COMMUNITIES', comms);
}
}
};
Alright, I finally figured this thing out. All I'm doing is calling a synchronous ajax request within my main.js file where my root vue instance is instantiated, and assigning a data property the requested data as so:
main.js
let acfData;
$.ajax({
async: false,
url: 'http://localhost/placeholder/wp-json/acf/v2/page/2',
type: 'GET',
success: function(response) {
console.log(response.acf);
acfData = response.acf;
}.bind(this)
})
const router = new VueRouter({
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About },
{ path: '/tickets', component: Tickets },
{ path: '/sponsors', component: Sponsors },
],
hashbang: false
});
exports.router = router;
const app = new Vue({
router,
data: {
acfs: acfData
},
created() {
}
}).$mount('#app')
From here, I can use the pulled data within each individual .vue file / component like so:
export default {
name: 'app',
data () {
return {
acf: this.$parent.acfs,
}
},
Finally, I render the data within the same .vue template with the following:
<template>
<transition
name="home"
v-on:enter="enter"
v-on:leave="leave"
v-bind:css="false"
mode="out-in"
>
<div class="full-height-container background-image home" v-bind:style="{backgroundImage: 'url(' + this.acf.home_background_image.url + ')'}">
<div class="content-container">
<h1 class="white bold home-title">{{ acf.home_title }}</h1>
<h2 class="white home-subtitle">{{ acf.home_subtitle }}</h2>
<div class="button-block">
<button class="white home-button-1">{{ acf.link_title_1 }}</button>
<button class="white home-button-2">{{ acf.link_title_2 }}</button>
</div>
</div>
</div>
</transition>
</template>
The most important piece of information to take away, is that all of the ACF data is only being called ONCE at the very beginning, compared to every time a route is visited using something like beforeRouteEnter (to, from, next). As a result, I'm able to get silky smooth page transitions as desired.
Hope this helps whoever comes across the same problem.
Check this section in docs of Vue Router
https://router.vuejs.org/guide/advanced/data-fetching.html
So first of you have to write method that would fetch data from your endpoint, and then use watcher to watch route.
export default {
watch: {
'$route': 'fetchItems'
},
methods: {
fetchItems() {
// fetch logic
}
}
}
Since you are working with WP Rest API, feel free to check my repo on Github https://github.com/bedakb/vuewp/blob/master/public/app/themes/vuewp/app/views/PostView.vue#L39