How to set meta og:image after axios request (VueJs)? - vuejs2

I have a vue component which immediately after download sends axios request.
Also i use vue-social-sharing and i need og:image meta, but my image returns after axios respond.
<template>
<div class="container">
<div v-if="collageSrc" class="col-md-12 collage">
<img class="img-responsive" :src="this.collageSrc"/>
<social-sharing>
<div>
<network network="facebook">
<i name="fa fa-facebook"></i> Facebook
</network>
<network network="twitter">
<i class="fa fa-twitter"></i> Twitter
</network>
</div>
</social-sharing>
</div>
<div class="col-md-12 collage" v-else>
<h1>Your image is preparing...</h1>
</div>
</div>
</template>
<script>
export default {
name: 'collage',
props:['id'],
data: function(){
return {
collageWaiter: this.getCollageSrc(),
collageSrc: '',
url : '',
}
},
metaInfo: {
title : 'Compliment Genarator Collage',
meta: [
{charset : 'utf-8'},
{
'vmid' : 'og:image',
'property' : 'og:image',
//'content' : this.collageSrc
}
]
},
methods:{
getCollageSrc(){
const self = this;
axios.get('/api/generate?id='+this.id)
.then(function(result){
self.collageSrc = result.data;
self.url = "http://compgen.ru/collage/" + self.id;
});
}
}
}
</script>
as you can see, prop 'collageSrc' becomes available after axios request. How can i dynamic include this prop to meta og:image ?

Define metaInfo as function, not as object:
metaInfo() {
return {
meta: [
{ vmid: 'og:image', property: 'og:image', content: this.collageSrc }
]
}
}
https://vue-meta.nuxtjs.org/faq/component-props.html

Related

How to pass clicked card button id to the backend URL path in vue.js?

I developed one page which is responsible for Displaying Books and the response is coming from backend , now i want to update my book card by clicking on ADD TO BAG button for that i write one handleCart() method for updating it updates based on book id , How to pass particular clickedCard Book id to the url path ,please help me to fix this .
DisplayBooks.vue
<template>
<div class="carddisplay-section">
<div v-for="book in books" :key="book.id" class="card book">
<div class="image-section">
<div class="image-container">
<img v-bind:src="book.file" />
</div>
</div>
<div class="title-section">
{{book.name}}
</div>
<div class="author-section">
by {{book.author}}
</div>
<div class="price-section">
Rs. {{book.price}}<label class="default">(2000)</label>
<button v-if="flag" class="btn-grp" type="submit" #click="handlesubmit();Togglebtn();">close</button>
</div>
<div class="buttons">
<div class="button-groups">
<button type="submit" #click="handleCart();" class="AddBag">Add to Bag</button>
<!-- v-if="state==true" -->
<button class="wishlist">wishlist</button>
</div>
<div class="AddedBag">
<button class="big-btn">Added to Bag</button>
</div>
</div>
</div>
</div>
</template>
<script>
import service from '../service/User'
export default {
data() {
return {
isActive:true,
result: 0,
authorPrefix: 'by',
pricePrefix: 'Rs.',
defaultStrikePrice: '(2000)',
buttonValue: 'close',
flag: true,
state: true,
clickedCard: '',
books: [{
id: 0,
file: 'https://images-na.ssl-images-amazon.com/images/I/41MdP5Tn0wL._SX258_BO1,204,203,200_.jpg',
name: 'Dont Make me think',
author: 'Sai',
price: '1500'
}, ]
}
},
methods: {
toggleClass: function(event){
this.isActive = !this.isActive;
return event;
},
toggle(id) {
this.clickedCard = id;
console.log(this.clickedCard);
},
flip() {
this.state = !this.state;
},
Togglebtn() {
this.flag = !this.flag;
},
handlesubmit() {
service.userDisplayBooks().then(response => {
this.books.push(...response.data);
})
},
handleCart(){
let userData={
id:this.clickedCard,
}
service.userUpdateCart(userData).then(response=>{
alert("item added to cart");
return response;
})
}
}
}
</script>
User.js
userUpdateCart(data){
return axios.updateData(`/addtocart/${data.id}`,data);
},
axios.js
updateData(url,data){
return axios.put(url,data).then(response=>{
localStorage.getItem('token', response.data.token);
return response;
})
}
it's not taking book id
Pass the book ID as an argument to the handleCart method.
#click="handleCart(book.id)"
handleCart(bookId){
let userData={
id: bookId,
}
service.userUpdateCart(userData).then(response=>{
alert("item added to cart");
return response;
})
}
The toggle method is also never being called.

why beforeRouteUpdate is not updating route

I am showing the products page use vueJS and API.
I am showing categories on the left side and products on the right side
but while clicking on category products should be shown and the same component should be a load but the same component is not loading
Please check why beforeRouteUpdate is not working
below is my code
<template>
<div style="padding: 25px">
<div class="container">
<div class="row">
<div class="col-md-3">
<div class="row">
<h3>Categories</h3>
<div class="col-md-12" align="left">
<router-link type="button" align="left" class="card-link" :to="'/'">
All Products</router-link>
</div>
<div class="col-md-12" v-for="category in categories" :key="category.id">
<CategoryCard :category="category" />
</div>
</div>
</div>
<div class="col-md-9">
<h1 class="index-msg">
{{ msg }}
</h1>
<div v-if="isShowId">
<span>props id:{{id}}</span>
<br />
<span>route.params id: {{uid}}</span>
</div>
<div class="row">
<div class="col-md-4" v-for="product in products" :key="product.id">
<ProductCard :product="product" />
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import {
mapActions,
mapGetters
} from "vuex";
import CategoryCard from "../../components/products/CategoryCard";
import ProductCard from "../../components/products/ProductCard";
export default {
name: "Products",
props: ["id"],
computed: {
...mapGetters("product", ["products"]),
...mapGetters("category", ["categories"]),
},
components: {
ProductCard,
CategoryCard,
},
data() {
return {
msg: "Products Page",
uid: "",
isShowId: false,
};
},
methods: {
...mapActions("product", ["getProducts", "addCart", "removeCart"]),
...mapActions("category", ["getCategories"]),
},
mounted() {
let id = this.$route.params.id;
if (id) {
this.isShowId = true;
this.uid = id;
} else {
this.isShowId = false;
this.uid = "";
}
this.getProducts(id);
this.getCategories();
},
beforeRouteUpdate (to, from, next) {
next();
},
beforeRouteLeave (to, from, next) {
console.log(`Leave to =`, to);
console.log(`Leave from =`, from);
next();
},
};
</script>
Try to check what's the 'pathPre' variable here. This will help you finding where to route now.
beforeRouteUpdate: function (to, from, next) {
let pathPre = from.path.split("/");
console.log(pathPre)
next();
},
And if you want to just reload the route on the same url then use
this.$router.go();
Edited
Load with variable as slug
Try to use slug with route
{
path: '/routeA/:slug',
name: 'routeName',
component: routeA,
props:true,
}
and push to url with slug and route name
this.$router.push({
name: "routeName",
params: { slug: passSlugVariable },
});
and catch this prop in data as variable
data: function () {
return {
slug: this.$route.params.slug,
};
}
watch: {
'$route'(to, from) {
let to_path = to.path;
let from_path = from.path;
console.log(`to =`, to_path);
console.log(`from =`, from_path);
if (to_path !== from_path) {
this.$router.push(to_path)
this.$router.go();
} else {
this.$router.go();
}
},
},
This is working as I am refreshing the page every time using this.$router.go(); , I know this is wrong method , please tell me correct solution

Issue with nuxt/auth

For auth I do use nuxt-auth, when the login is successful, I want to redirect to the main page using this.$router.push('/'), then I get a response like blank page with the following message
2021
,
// for login
<template>
<div class="limiter">
<div
class="container-login100"
:style="{
backgroundImage: 'url(' + require(`#/assets/login/images/bg-01.jpg`) + ')',
}"
>
<div class="wrap-login100 p-l-110 p-r-110 p-t-62 p-b-33">
<form class="login100-form validate-form flex-sb flex-w">
<span class="login100-form-title p-b-53"> Login Admin </span>
<a href="facebook.com" class="btn-face m-b-20">
<i class="fa fa-facebook-official"></i>
Facebook
</a>
<a href="google.com" class="btn-google m-b-20">
<img :src="require(`#/assets/login/images/icons/icon-google.png`)" alt="GOOGLE" />
Google
</a>
<div class="p-t-31 p-b-9">
<span class="txt1"> Email </span>
</div>
<div class="wrap-input100 validate-input" data-validate="Email is required">
<input v-model="auth.email" class="input100" type="email" name="email" />
<span class="focus-input100"></span>
</div>
<div class="p-t-13 p-b-9">
<span class="txt1"> Password </span>
Forgot?
</div>
<div class="wrap-input100 validate-input" data-validate="Password is required">
<input v-model="auth.password" class="input100" type="password" name="pass" />
<span class="focus-input100"></span>
</div>
<div class="container-login100-form-btn m-t-17">
Login
</div>
<div class="w-full text-center p-t-55">
<span class="txt2"> Not a member? </span>
Register now
</div>
</form>
</div>
</div>
</div>
</template>
<script>
export default {
auth: false,
data() {
return {
auth: {
email: null,
password: null,
},
}
},
mounted() {
if (this.$auth.loggedIn) {
this.$router.push('/')
}
},
methods: {
async submit() {
try {
const response = await this.$auth.loginWith('local', { data: this.auth })
this.$router.push('/')
} catch (err) {
console.log(err)
}
},
},
}
</script>
store vuex index.js
export const getters = {
isAuthenticated(state) {
return state.auth.loggedIn
},
loggedInUser(state) {
return state.auth.user
}}
}
layout default.vue
<template>
<div class="wrapper">
<Sidebar v-if="isAuthenticated" />
<div :class="isAuthenticated ? 'main-panel' : ''">
<Navbar v-if="isAuthenticated" />
<Nuxt />
<Footer v-if="isAuthenticated" />
</div>
</div>
</template>
<script>
import Sidebar from '#/components/layout/Sidebar.vue'
import Navbar from '#/components/layout/Navbar.vue'
import Footer from '#/components/layout/Footer.vue'
import { mapGetters } from 'vuex'
export default {
components: { Sidebar, Navbar, Footer },
computed: {
...mapGetters(['isAuthenticated', 'loggedInUser']),
},
}
</script>
// auth nuxt config
auth : {
strategies: {
local: {
token: {
property: 'token',
required: true,
type: 'Bearer'
},
user: {
property: 'user',
autoFetch: true
},
endpoints: {
login: { url: '/sign/login', method: 'post' },
logout: { url: '/sign/logout', method: 'post' },
user: { url: '/sign/user-login', method: 'get' }
}
}
}
}
base index ('/')
<template>
<div class="container">
<div>
<Logo />
<h1 class="title">Learn Nuxt</h1>
<div class="links">
<a href="https://nuxtjs.org/" target="_blank" rel="noopener noreferrer" class="button--green">
Documentation
</a>
<a
href="https://github.com/nuxt/nuxt.js"
target="_blank"
rel="noopener noreferrer"
class="button--grey"
>
GitHub
</a>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['isAuthenticated', 'loggedInUser']),
},
}
</script>
In your vuex store, the state parameter in your getter only has access to local state. You can't access the auth state the way you tried.
In a vuex module, a getter gets 4 arguments, namely local state, local getters, root state and root getters. So if you would rewrite your getters like this it would probably work:
export const getters = {
isAuthenticated(state, getters, rootState) {
return rootState.auth.loggedIn
},
loggedInUser(state, getters, rootState) {
return rootState.auth.user
}}
}
But I still think it is a bit redundant doing it like that. I would replace isAuthenticated with this.$auth.loggedIn in your default layout. The nuxt-auth module globally injects the $auth instance, meaning that you can access it anywhere using this.$auth.
I had same problem after authorizing user and redirect user to the home page.
After many tries and doing many works, the right config of auth in nuxt.config.js seemed like this:
auth: {
strategies: {
local: {
scheme: 'refresh',
token: {
property: 'access_token',
tokenType: false,
maxAge: 60 * 60
},
refreshToken: {
property: 'refresh_token',
data: '',
maxAge: 60 * 60
},
endpoints: {
login: {
url: 'url/of/token',
method: 'urlMethod'
},
refresh: {
url: 'url/of/refreshToken',
method: 'urlMethod'
},
logout: false,
user: false
}
}
},
cookie: false,
redirect: {
login: '/login/page',
logout: '/login/page',
callback: false,
home: '/home/page'
}
},
Note that I didn't have any refreshToken property, but I should set it as empty string in config to be able to work with nuxt/auth!
Hope I could help

Nuxt Failed to execute ‘appendChild’ on ‘Node’ when trying to get window size

The problem is that the project must be transferred to Nuxt and some of the code does not work. Namely, the size of the screen must perform actions with the text. Since Nuxt is an SSR, the code cannot be executed on the server side because it does not know the size of the window.
Can I somehow fulfill this idea so that everything works?
I have a project with nuxt and i18n
[nuxt] Error while initializing app DOMException: Failed to execute 'appendChild' on 'Node': This node type does not support this method.
at Object.Je [as appendChild]
this my component vue
This code is an example of what causes an error.
<template>
<section>
<div>
<h2 class="subtitle" v-html="filterHeadSlogan"></h2>
</div>
</section>
</template>
<script>
export default {
name: 'testapp',
data() {
return {
filterHeadSlogan: '',
windowWidth: 0
}
},
methods: {
getWindowWidth(event) {
this.windowWidth = document.documentElement.clientWidth
var str = "<i>HELLO WORLD</i>"
if (this.windowWidth >= 960) {
this.filterHeadSlogan = str
} else {
this.filterHeadSlogan = str.replace(/<\/?[^>]+(>|$)/g, '')
}
}
},
mounted() {
this.$nextTick(function () {
window.addEventListener('resize', this.getWindowWidth);
//Init
this.getWindowWidth()
})
}
}
</script>
An error occurred because there was no data in the variable. The village appeared, but there was no data and there was a conflict. I created asyncData
async asyncData(){
return {
headSlogan: ""
}
},
Full code
<template>
<div class="westartslogan">
<div class="head-slogan">
<h2 v-html="headSlogan"></h2>
</div>
<h3>{{$t('page.home.wellcom_block_subtitle_left')}}</h3>
<ul>
<li><i class="icon"></i>
<div v-html="$t('page.home.wellcom_block_option_1_left')"></div></li>
<li><i class="icon"></i>
<div v-html="$t('page.home.wellcom_block_option_2_left')"></div></li>
<li><i class="icon"></i>
<div v-html="$t('page.home.wellcom_block_option_3_left')"></div></li>
<li><i class="icon"></i>
<div v-html="$t('page.home.wellcom_block_option_4_left')"></div></li>
<li><i class="icon"></i>
<div v-html="$t('page.home.wellcom_block_option_5_left')"></div></li>
</ul>
<div class="startcalc-btn button-container">
<nuxt-link :to="getLocalizedRoute({ name: 'calculator' })" class="uk-button uk-button-default">{{
$t('page.home.wellcom_button_calculator') }}
</nuxt-link >
</div>
<div class="ourproject-btn uk-hidden#s">
<div class="button-container">
<nuxt-link :to="getLocalizedRoute({ name: 'portfolio' })" class="uk-button uk-button-default">
{{ $t('page.home.wellcom_button_portfolio') }}
</nuxt-link>
</div>
</div>
</div>
</template>
<script>
export default {
async asyncData(){
return {
headSlogan: ""
}
},
name: 'we_can',
data () {
return {
filterHeadSlogan: '',
headSlogan: this.$i18n.t('page.home.wellcom_block_title_left'),
windowWidth: 0
}
},
methods: {
getWindowWidth (event) {
this.windowWidth = document.documentElement.clientWidth
if (this.windowWidth >= 960) {
this.headSlogan = this.headSlogan
} else {
var str = this.headSlogan
this.headSlogan = str.replace(/<\/?[^>]+(>|$)/g, '')
}
}
},
mounted() {
this.$nextTick(function () {
window.addEventListener('resize', this.getWindowWidth);
//Init
this.getWindowWidth()
})
}
}
</script>
<style scoped>
</style>
I was dealing with the same problem.
Do these steps:
Run your project (yarn start).
Open http://localhost:3000/ in Chrome.
In Chrome devtools clear site data in application tab.
Hard reload the page.

Returning promise from api and putting into global data

Sorry if this is obvious but new to vue and my js not so great.....
I'm trying to get some data from an api and then put that data into a global object so it can be passed down to some child components.
I can't seem to $set the data into the global projects object, it either returns undefined or returns a promise.
parent --
<template>
<div id="app">
<section class="intro">
<h1>WELCOME</h1>
</section>
<transition name="fade"> <router-view class="view" :computedProjects=computedProject ></router-view></transition>
</div>
</template>
<script>
import projectsList from './components/projectsList'
var client = contentful.createClient({
// This is the space ID. A space is like a project folder in Contentful terms
space: '',
// This is the access token for this space. Normally you get both ID and the token in the Contentful web app
accessToken: '',
})
var PRODUCT_CONTENT_TYPE_ID = 'project'
export default {
name: 'app',
components: {
projectsList
},
data: function() {
return {
users:'',
projects:'',
}
},
methods: {},
created : function () {
client.getEntries().then((response) => {
console.log(response)
this.projects = response
console.log(this.projects)
return response
});
},
computed: {
computedProject: function() {
if (!this.projects) return null;
return this.projects;
}
}
}
}
child ---
<template>
<section class="project-list">
<swiper :options="swiperOption">
<swiper-slide v-for="project in projects" v-bind:ref="'project' + project.name" :key="project.name" data-swiper-parallax="-100">
<div class="project-cover wrapper">
{{project.name}}
<router-link :to="{ name: 'project', params: { id: project.name }}">
<div class="cover-img" :style="{ 'background-image': 'url(../static/img/projects/'+project.name+'/'+'project-details-header.jpg)' }"> </div>
<div class="project-copy"></div>
<div href="#" class="tilter tilter--4">
<figure class="tilter__figure">
<img class="tilter__image" :src="'+project.fields.coverImage.fields.file.url+'" alt="" />
<div class="tilter__deco tilter__deco--shine"></div>
<div class="tilter__deco tilter__deco--overlay" v-bind:style="{ backgroundImage: project.gradient }"></div>
<figcaption class="tilter__caption">
<h1 class="projectName tilter__title title">{{project.name}}</h1>
<h2 class="tilter__description">{{project.tagline}}</h2>
</figcaption>
<svg class="tilter__deco tilter__deco--lines" viewBox="0 0 300 415">
<path d="M20.5,20.5h260v375h-260V20.5z" />
</svg>
</figure>
</div>
</router-link>
</div>
</swiper-slide>
<div class="swiper-pagination" slot="pagination"></div>
</swiper>
</section>
</template>
<script>
export default {
data: function () {
return {
swiperOption: {
autoplay:false,
setWrapperSize :true,
observeParents:true,
keyboardControl : true,
centeredSlides :true,
freeMode:false,
freeModeSticky:true,
pagination: '.swiper-pagination',
paginationType: 'progress',
watchSlidesProgress : true,
watchSlidesVisibility : true,
speed:650,
grabCursor:true,
parallax:true
},
}
},
props :['computedProject'],
created : function () {
console.log(this.projects)
},
any help will be appreciated.
You can just assign the vue data variable in the callback of getEntries like following:
created : function () {
var self = this
client.getEntries().then((response) => {
console.log(response)
self.projects = response
})
console.log(this.projects)
},