Move static parts of Vue code from methods() to <template> - vue.js

Within my code there is some static data like const YAMAP_KEY and let src in the <script> section. I'd like to move those to the <template> section leaving the rest of the <script> section as is it now. How do I do it?
<template>
<div class='some-container container'>
<div id='yaMap'></div>
</div>
</template>
<script>
export default {
data: () => ({
}),
methods: {
loadYamap() {
return new Promise((resolve, reject) => {
const YAMAP_KEY = 'abcdef';
const YamapNode = document.createElement('script');
let src = 'https://api-maps.yandex.ru/2.1?lang=ru_RU&coordorder=longlat&apikey=' + YAMAP_KEY;
YamapNode.src = src;
YamapNode.onload = () => resolve();
YamapNode.onerror = (err) => {
console.log('map didn't load');
reject(err);
};
this.$el.appendChild(YamapNode);
});
}
},
mounted() {
this.loadYamap()
.then(() => {
ymaps.ready(() => {
var Yamap = new ymaps.Map('yaMap', {
center: [55.76, 37.64],
zoom: 10
})
})
})
.catch(ex => console.log('map load exception:', ex));
}
}
</script>
UP.
I've tried adding consts to the <template> section.
<template>
<div class='some-container container'>
<div id='yaMap'></div>
<script ref='myref'>
console.log('script in template');
const YAMAP_KEY = '8972y3uihfiuew';
let src = 'https://api-maps.yandex.ru/2.1?lang=ru_RU&coordorder=longlat';
<script>
</div>
</template>
Then accessing them in the <script> section.
<script>
export default {
data: () => ({
}),
methods: {
loadYamap() {
this.$refs.myref.onload = () => console.log('script in template loaded');
...

Add a tag inside and declare var for those constants and access them in your javascript code.
<div id="container">
<input type="text" id="container" placeholder="enter text" v-model="value">
<p>{{ value }}</p>
<script>var a = 'manu';</script>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.11.10/vue.min.js"></script>
<script>
new Vue({
el: '#container',
data: {
value: '',
},
created: function() {
console.log('Value', a);
}
});
</script>
Example: https://codepen.io/mnbhardwaj888/pen/PooPyjV

Related

Vue blog change rendered post when clicked on a link from "latest posts" sidebar

I've got a problem with my hobby project, I created a BlogPost.vue in which I render the previously clicked post from a Blog.vue page.
In this BlogPost, I render the clicked post's title, content etc, and on the sidebar, I show a small area in which I render 3 of the latest posts from this same category - the posts from Blog.vue.
When I click on the sidebar's links, any of the 3, the browser does change the slug, and the page does re-render itself, except it re-renders the same post that was clicked. If I refresh the page in the browser (or Ctrl+R or F5 etc), then it does render the correct content clicked from this sidebar.
I have no clue why it does that, I can only suppose that I should be watching the route change then somehow refresh what it renders, but no idea as to how.
Blog.vue, this works great, renders the single post clicked
<script setup lang="ts">
import axios from "axios";
import { ref } from "vue";
import { onMounted } from "vue";
import moment from "moment";
const postsUrl = "http://localhost/wordpress/wp-json/wp/v2/posts";
const posts = ref([] as any);
const isLoading = ref(false);
const errorCaught = ref(false);
var queryOptions = {
_embed: true,
};
const getPosts = () => {
isLoading.value = true;
axios
.get(postsUrl, { params: queryOptions })
.then((response) => {
posts.value = response.data;
console.log(posts.value);
isLoading.value = false;
})
.then(() => {
console.log(isLoading.value);
})
.catch((error) => {
if (error) {
isLoading.value = false;
errorCaught.value = true;
}
});
};
onMounted(async () => {
getPosts();
});
</script>
<template>
<transition name="fadeLoading">
<div v-if="isLoading" class="posts-loading">
<div class="circle"></div>
</div>
</transition>
<transition name="fadeLoading">
<div class="errorCaught" v-if="errorCaught">
There was an error loading news
</div>
</transition>
<div class="blog-container">
<div class="wrapper">
<transition-group name="fadeBlog">
<ul v-if="!isLoading" class="blog-posts-ul" v-for="post in posts">
<div class="posts-card">
<a
><router-link
:to="/blog/ + post.slug"
key="post.id"
class="posts-permalink"
>
</router-link
></a>
<img
v-if="post.featured_media != 0"
class="posts-featuredimage"
:src="post._embedded['wp:featuredmedia'][0].source_url"
:alt="post.title.rendered"
/>
<img v-else src="#/assets/logos/favicon-big.png" />
<div class="posts-date">
<p>
{{ moment(post.date).fromNow() + " " + "ago" }}
</p>
</div>
<div class="posts-text">
<h1 class="posts-title">{{ post.title.rendered }}</h1>
<p v-html="post.excerpt.rendered" class="posts-excerpt"></p>
</div>
</div>
</ul>
</transition-group>
</div>
</div>
</template>
BlogPost.vue, renders the previously clicked one, but does not show the sidebar's clicked content
<script setup lang="ts">
import { ref, watch, onMounted } from "vue";
import { useRoute } from "vue-router";
import axios from "axios";
import moment from "moment";
const route = useRoute();
const postsUrl = "http://localhost/wordpress/wp-json/wp/v2/posts";
const queryOptions = {
slug: route.params.blogSlug,
_embed: true,
};
const post = ref([] as any);
const isLoading = ref(false);
const latestPostsAPI = "http://localhost/wordpress/wp-json/wp/v2/posts";
const latestPosts = ref([] as any);
const errorCaughtLatest = ref(false);
var queryOptionsLatest = {
_embed: true,
per_page:3,
};
const getLatest = () => {
axios
.get(latestPostsAPI, { params: queryOptionsLatest })
.then((response) => {
latestPosts.value = response.data;
console.log(latestPosts.value);
})
.catch((error) => {
if (error) {
errorCaughtLatest.value = true;
}
});
};
const getPost = () => {
isLoading.value = true;
axios
.get(postsUrl, { params: queryOptions })
.then((response) => {
post.value = response.data;
console.log("Pages retrieved!");
})
.catch((error) => {
console.log(error);
})
.then(() => {
isLoading.value = false;
});
};
getLatest();
getPost();
</script>
<template>
<div v-if="!isLoading" class="post-wrapper">
<div class="wrapper">
<div class="post-title">{{ post[0].title.rendered }}</div>
<div class="post-date">
{{ moment(post[0].date).format("MMMM Do YYYY, h:mm, dddd") }}
</div>
<!-- THIS INCLUDES HTML TAGS -->
<div class="post-content" v-html="post[0].content.rendered"></div>
</div>
</div>
<div class="side-container">
<div class="side-wrapper">
<ul v-if="!isLoading" class="blog-posts-ul" v-for="latest in latestPosts">
<div class="posts-card">
<a
><router-link
:to="/blog/ + latest.slug"
key="latest.id"
class="posts-permalink"
>
</router-link
></a>
<img
v-if="latest.featured_media != 0"
class="posts-featuredimage"
:src="latest._embedded['wp:featuredmedia'][0].source_url"
:alt="latest.title.rendered"
/>
<img v-else src="#/assets/logos/favicon-big.png" />
<div class="posts-text">
<div class="posts-title">{{ latest.title.rendered }}</div>
<div class="posts-date">
<p>{{ moment(latest.date).fromNow() + " " + "ago" }}</p>
</div>
<div class="posts-author">
{{ latest._embedded.author[0].name }}
</div>
</div>
</div>
</ul>
</div>
</div>
</template>
Thanks for your time
In my original post as you can see, I'm using axios to get my post with the params queryOptions:
I declare my queryOptions with a const:
const queryOptions = {
slug: route.params.blogSlug,
_embed: true,
};
THEN, I call the getPost method, which uses this constant:
const getPost = () => {
isLoading.value = true;
axios
.get(postsUrl, { params: queryOptions } })
.then((response) => {
post.value = response.data;
console.log("getPost!");
})
.catch((error) => {
console.log(error);
})
.then(() => {
isLoading.value = false;
});
};
And the problem is right there: that queryOptions, IS a constant, gets defined at the onMounted lifecycle, or even before I'm not 100% sure, but it does NOT get re-defined WHEN I click on any link on this BlogPost.vue component.
SO, the solving is the following:
Change the getPost method so it does NOT use a pre-defined constant, rather just simply type in the params, like the following:
const getPost = () => {
isLoading.value = true;
axios
.get(postsUrl, { params: { slug: route.params.blogSlug, _embed: true } })
.then((response) => {
post.value = response.data;
console.log("getPost!");
})
.catch((error) => {
console.log(error);
})
.then(() => {
isLoading.value = false;
});
};
If I do it this way, every time the getPost method runs, which it WILL since I'm watching the blogSlug change with
watch(() => route.params.blogSlug, getPost);
the getPost function will always call the latest route.params.blogSlug, which gets changed before the watcher runs the getPost as I click on the sidebar link.

Vuex store Getter loadings faster than store State

I have a nuxtJS vue2 components as follows:
<template>
<div class="product-fullpage">
<div class="product-card">
<img :src="productById(this.$route.params.id).imageURL">
<div class="product-headings">
<div class="product-info" v-animate-on-scroll>
<h1>{{ productById(this.$route.params.id).name }}</h1>
<h2>£{{ productById(this.$route.params.id).price }}</h2>
</div>
<div class="product-cart" v-animate-on-scroll>
<div class="quantity-info">
<label for="quantity">Quantity:</label>
<input v-model.number="productInfo.quantity" name="quantity" type="number" min="0" max="99"/>
</div>
<button #click="addToCart" :disabled="noQuantity">Add To Cart ></button>
</div>
</div>
</div>
</div>
</template>
I'm using a getter that does the following:
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['productById'])
},
}
</script>
Here's the getter
export const getters = {
productById: (state) => (id) => {
return state.products.find(product => product.id === id)
},
}
my state is set to pull from firebase
export const actions = {
async setProducts({commit}) {
let colRef = collection(db, 'products')
const querySnapshot = await getDocs(colRef)
querySnapshot.forEach((doc) => {
const imageDownloadURL = getDownloadURL(ref(storage, `${doc.data().imageRef}`))
.then( url => {
// console.log(url)
let article = ({
id: doc.id,
name: doc.data().name,
price: doc.data().price,
description: doc.data().description,
imageURL: url
})
commit('setProducts', article)
})
})
},
}
the mutation to set the state:
export const mutations = {
setProducts(state, article) {
let matchProduct = state.products.find(product => product.id == article.id)
if(!matchProduct) {
state.products.push(article)
}
},
}
and this is my state:
export const state = () => ({
products: [],
})
i thought that if i load everything beforehand in default.vue under 'layouts' that i can then have the store.state.products set.
<template>
<div class="container">
<!-- <nuxt /> -->
<nuxt v-if="!loading"/>
<div class="overlay" v-else>
Loading...
</div>
</div>
</template>
<script>
export default {
created() {
this.loading = true
this.$store.dispatch('setCart')
this.$store.dispatch('setProducts')
.finally(() => (this.loading=false))
},
data() {
return {
loading: false,
}
},
}
</script>
sorry if this is turning out to be a long post - but basically on initial load, I get my imageURL, name and price. but then on reload it comes out empty. i believe the getter is occurring before the store is loaded. how do i set it so that i can state.products.find(product => product.id == article.id) for my getter after state is loaded?

Why Vue doesn't refresh list using props?

On my App, on mounted() method, I call an API, which give to me a JSON with a list of items; than, I update the prop I've set in my target Homepage component:
Homepage.pages = resJSON.data.pages;
Here's the App code:
<template>
<div id="app">
<Homepage title="PWA Test"/>
</div>
</template>
<script>
import Homepage from './components/Homepage.vue'
export default {
name: 'App',
components: {
Homepage
},
mounted() {
let endpoint = "http://localhost:5000/api/graphql?query={pages(orderBy:{contentItemId:asc}){contentItemId,createdUtc,author,displayText,description%20}}";
fetch(endpoint, {
method:'GET',
headers: {
'Accept':'application/json',
'Content-Type':'application/json'
}
})
.then((response) => {
// check for HTTP failure
if (!response.ok) {
throw new Error("HTTP status " + response.status);
}
// read and parse the JSON
return response.json();
})
.then((res) => {
Homepage.pages = res.data.pages;
})
.catch((error) => {
console.log(error);
});
}
}
</script>
<style>
</style>
Here's the Homepage component:
<template>
<div id="homepage">
<h1>{{ title }}</h1>
<ul>
<li v-for="page in pages" :key="page.description">#{{ page.description }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Homepage',
props: {
title: String,
pages: []
}
}
</script>
<style scoped>
</style>
But the ul doesn't update after receiving the JSON and updating the props pages. Where's my error?
you need to get the response.json(); in a data property of the App and then pass it down to the Homepage component. So your code should you look like this,
App code:
<template>
<div id="app">
//binding page into data property
<Homepage title="PWA Test" :pages="pages"/>
</div>
</template>
<script>
import Homepage from './components/Homepage.vue'
export default {
name: 'App',
data: function () {
return {
//data propety
pages : []
}
},
components: {
Homepage
},
mounted() {
let endpoint = "http://localhost:5000/api/graphql?query={pages(orderBy:{contentItemId:asc}){contentItemId,createdUtc,author,displayText,description%20}}";
fetch(endpoint, {
method:'GET',
headers: {
'Accept':'application/json',
'Content-Type':'application/json'
}
})
.then((response) => {
if (!response.ok) {
throw new Error("HTTP status " + response.status);
}
// assign the result to the data property
this.page = response.json();
})
.then((res) => {
Homepage.pages = res.data.pages;
})
.catch((error) => {
console.log(error);
});
}
}
</script>
Do you pass the props in a template after this.pages = res.data.pages?
<Homepage :pages="pages" />
I think there are some mistakes that you have done in your code, if you want change update prop value then you have to initialized your props values in script.
<template>
<div id="homepage">
<h1>{{ title }}</h1>
<ul>
<li v-for="page in currentPages" :key="page.description">#{{ page.description }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Homepage',
props: {
title: String,
pages: []
}
data: function () {
return {
currentPages: this.pages
}
}
}
</script>
I hope this will help you to solve your issue- thanks!

Vue.js Component emit

I have some problem about component $emit
This is my child component:
<template>
<div class="input-group mb-3 input-group-sm">
<input v-model="newCoupon" type="text" class="form-control" placeholder="code">
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" #click="addCoupon">comfirm</button>
</div>
</div>
</template>
<script>
export default {
props: ["couponcode"],
data() {
return {
newCoupon: this.couponcode
};
},
methods: {
addCoupon() {
this.$emit("add", this.newCoupon);
}
}
};
</script>
This is parent component
<template>
<div>
<cartData :couponcode="coupon_code" #add="addCoupon"></cartData>
</div>
</template>
<script>
import cartData from "../cartData";
export default {
components: {
cartData
},
data() {
return {
coupon_code: ""
}
},
methods:{
addCoupon() {
const api = `${process.env.API_PATH}/api/${
process.env.CUSTOM_PATH
}/coupon`;
const vm = this;
const coupon = {
code: vm.coupon_code
};
this.$http.post(api, { data: coupon }).then(response => {
console.log(response.data);
});
},
}
}
</script>
When I click the 'confirm' button,the console.log display 'can't find the coupon' 。 If I don't use the component,it will work 。
What is the problem? It's about emit?
addCoupon() {
this.$emit("add", this.newCoupon); // You emitted a param
}
// then you should use it in the listener
addCoupon(coupon) { // take the param
const api = `${process.env.API_PATH}/api/${
process.env.CUSTOM_PATH
}/coupon`;
const coupon = {
code: coupon // use it
};
this.$http.post(api, { data: coupon }).then(response => {
console.log(response.data);
});
},

Can't find out why vuex getters ById doensim get a company by id

i am still new to VUEX and i am following this tutorial vuex store
The only thing i am doing differently is i am using sequelize instead of mLab like he does.
This is what my getters look like
export const companyGetters = {
allCompanies: (state, getters) => {
return state.companies
},
companyById: (state, getters) => id => {
if (getters.allCompanies.length > 0) {
return getters.allCompanies.filter(c => c._id === id)[0]
} else {
return state.company
}
}
Exactly like what he did.
My action looks like this
companyById ({commit}, payload) {
commit(COMPANY_BY_ID)
axios.get(`${API_BASE}/companies/${payload}`).then(response => {
console.log(payload, response.data)
commit(COMPANY_BY_ID_SUCCESS, response.data)
})
}
Next in my details i have
<template>
<div>
<company-details :company="company" ></company-details>
</div>
</template>
<script>
import CompanyDetails from '../components/company/CompanyDetails'
export default {
created () {
if (!this.company.companyName) {
this.$store.dispatch('companyById', this.$route.params['id'])
}
},
computed: {
company () {
return this.$store.getters.companyById(this.$route.params['id'])
}
},
components: {
'company-details': CompanyDetails
}
}
</script>
and then finally my companyDetails looks like this
<template>
<v-ons-col style="width: 350px; float:left;">
<v-ons-card>
<h1>{{company}}</h1>
</v-ons-card>
</v-ons-col>
</template>
<script>
export default {
props: ['company']
}
</script>
here is the mutations
export const companyMutations = {
[ALL_COMPANYS] (state) {
state.showLoader = true
},
[ALL_COMPANYS_SUCCESS] (state, payload) {
state.showLoader = false
state.companies = payload
},
[COMPANY_BY_ID] (state) {
state.showLoader = true
},
[COMPANY_BY_ID_SUCCESS] (state, payload) {
state.showLoader = false
state.company = payload
}
and here is my actions
allCompanies ({commit}) {
commit(ALL_COMPANYS)
axios.get(`${API_BASE}/companies`).then(response => {
commit(ALL_COMPANYS_SUCCESS, response.data)
})
},
companyById ({commit}, payload) {
commit(COMPANY_BY_ID)
axios.get(`${API_BASE}/companies/${payload}`).then(response => {
console.log(payload, response.data)
commit(COMPANY_BY_ID_SUCCESS, response.data)
})
My CompanyList looks like this
<template>
<div>
<div class="companies">
<div class="container">
<template v-for="company in companies" >
<company :company="company" :key="company.id"></company>
</template>
</div>
</div>
</div>
</template>
<script>
import Company from './Company.vue'
export default {
name: 'companies',
created () {
if (this.companies.length === 0) {
this.$store.dispatch('allCompanies')
}
},
computed: {
companies () {
return this.$store.getters.allCompanies
}
},
components: {
'company': Company
}
}
</script>
Imported Company looks like this
<template>
<v-ons-col style="width: 350px; float:left;">
<router-link :to="'/details/'+company.id" class="company-link">
<v-ons-card>
<img :src="company.imageURL" style="width:100% ;margin: 0 auto;display: block;">
<div class="title">
<b>{{company.companyName}}</b>
</div>
<div class="description">
{{company.description}}
</div>
<div class="content">
<!-- <template v-for="company in companies">
{{company}}
</template> -->
</div>
</v-ons-card>
</router-link>
</v-ons-col>
</template>
<script>
export default {
name: 'company',
props: ['company']
}
</script>
So when i click on one of these "companies" its suppose to get it by id and show the details however in the getters this return getters.allCompanies.filter(c => c._id === id)[0] returns undefined, when i refresh the page then it gets the correct company and displays it, what is going on please help. If you need more info please ask