Network Error when trigger nuxt-link beginner - vuejs2

Network Error when trigger nuxt-link after refresh same page its work fine
Here is Template
<div class="col-lg-3" v-for="(video, index) in videos" :key="index">
<nuxt-link :to="/video/ + video.id">
<img :src="video.image" width="100%">
<div class="card">
<div class="card-body">
<h1 class="title">{{ video.title }}</h1>
</div>
</div>
</nuxt-link>
</div>
scripts
export default {
layout: 'default',
asyncData({ req, params }) {
// We can return a Promise instead of calling the callback
return axios.get('http://localhost:8000/getVideos')
.then((res) => {
return { videos: res.data.data }
})
}
}
Here is Next Page Link
<script>
import axios from 'axios'
export default{
layout: 'default',
asyncData({ req, params }) {
// We can return a Promise instead of calling the callback
return axios.get(`http://localhost:8000/video/${params.id}`)
.then((res) => {
return { video: res.data.video , relatedVideos: res.data.relatedVideos }
})
},
}
</script>
and This is the Error what is and facing
after refresh page it works fine

after install > https://github.com/barryvdh/laravel-cors package in my laravel backend everything working fine

Related

Nuxt-content not working with asyncData in a component

I'm trying to fetch content from my content/blog folder but I can't make it work in the components/menu.vue page since it's a component ?
This is working in the page/index.vue but not in components/menu.vue. Why?
I'm new to all this and maybe I'm doing something wrong here, maybe I'm not able to fetch content from a component... I don't know.
<template>
<div class="container">
<div class="articles">
<div class="article" v-for="article of articles" :key="article">
<nuxt-link :to="{ name: 'slug', params: { slug: article.slug } }">
<div class="article-inner">
<img :src="require(`~/assets/${article.img}`)" alt="" />
<div class="detail">
<h3>{{ article.title }}</h3>
<p>{{ article.description }}</p>
</div>
</div>
</nuxt-link>
</div>
</div>
</div>
</template>
<script>
export default {
async asyncData ({ $content, params }) {
const articles = await $content('blog', params.slug)
.only(['title', 'description', 'img', 'slug'])
.sortBy('createdAt', 'asc')
.fetch()
console.log('bongo')
return {
articles
}
},
data () {
return {
num: this.$route.name
}
},
computed: {
currentRouteName () {
return this.$route.name
}
}
}
</script>
As written here: https://nuxtjs.org/docs/features/data-fetching#async-data
asyncData is only available for pages and you don't have access to this inside the hook.
So yes you can use asyncData only in a page.
An alternative would be to use a non-blocking fetch() hook as shown here: https://nuxtjs.org/docs/features/data-fetching#accessing-the-fetch-state

vuejs problem change route get userChoice in localstorage but push on the profile route before getting new userChoice?

the problem is that on click I increments the new userChoice according to the user chosen but it pushes on the profile route before retrieving the new userChoice click.
what to do here is my template I will put everything in the same function change use the push at the end but it does not work either then I do 2 functions but it does not work either what is the solution ??
<template>
<section
class="stopPadMarg container-fluid d-md-flex justify-content-between"
>
<div class="py-5 stopPadMarg bg-primary col-md-1">
<img
src="../assets/image/icon.png"
width="60px"
class="rounded-circle"
alt="logo"
/>
</div>
<div class="largeur80">
<form class="justify-content-center form-inline py-3 my-2 my-lg-0">
<input
v-model="searchKey"
id="search"
class="form-control mr-sm-2"
type="search"
placeholder="Search"
aria-label="Search"
/>
</form>
<div>
<h3
class="backPrimaire opacity mx-1 text-primary bordurePost bordureRond"
>
<b-icon-chevron-double-down
class="mr-5 my-1 pt-1 text-secondary"
animation="cylon-vertical"
font-scale="1"
></b-icon-chevron-double-down>
Vos collegues
<b-icon-chevron-double-down
class="ml-5 my-1 pt-1 text-secondary"
animation="cylon-vertical"
font-scale="1"
></b-icon-chevron-double-down>
</h3>
</div>
<div class="hauteur">
<div class="mt-5 d-flex flex-wrap">
<div
v-for="(user, id) in filteredList"
v-bind:key="id"
class="col-md-3 d-flex flex-column align-items-center align-content-center"
>
<div #click="changeUser(user)" class="cursor">
<img
#click="changeRoute"
v-if="user.image_url !== null || ''"
:src="user.image_url"
width="100px"
height="100px"
class=" justify-content-left bordureProfil
rounded-circle"
/>
<img
v-else
src="../assets/image/icon.png"
width="100px"
class=" justify-content-left bordureProfil rounded-circle"
/>
</div>
<div>
<h5 class="mt-2">
{{ user.nom.toUpperCase() }}
</h5>
<h6 class="mb-3">{{ user.prenom.toLowerCase() }}</h6>
</div>
</div>
</div>
</div>
</div>
<div class="py-5 stopPadMarg bg-primary col-md-1">
<img
src="../assets/image/icon.png"
width="60px"
class="rounded-circle"
alt="logo"
/>
</div>
</section>
</template>
<script>
import axios from "axios";
export default {
components: {},
data() {
return {
searchKey: "",
postes: [],
users: [],
user_id: localStorage.getItem("userId"),
userChoice: localStorage.getItem("userChoice"),
};
},
async created() {
this.postes = [];
this.users = [];
await axios
.get("http://localhost:3000/postes")
.then(
(response) => ((this.postes = response.data), console.log(response))
)
.catch((error) => console.log(error));
await axios
.get("http://localhost:3000/users")
.then(
(response) => ((this.users = response.data), console.log(this.users))
)
.catch((error) => console.log(error));
await axios
.get("http://localhost:3000/users")
.then(
(response) => (
(this.userDef = response.data.find((user) => {
return user.id;
})),
console.log(this.userDef)
)
)
.catch((error) => console.log(error));
await axios
.get(`http://localhost:3000/user/${this.user_id}`)
.then(
(response) => (
(this.userConnect = response.data), console.log(this.userConnect.id)
)
)
.catch((error) => console.log(error));
await axios
.get("http://localhost:3000/commentaires")
.then(
(response) => (
(this.comments = response.data), console.log(this.comments)
)
)
.catch((error) => console.log(error));
},
computed: {
filteredList() {
return this.users.filter((user) => {
return user.nom.toLowerCase().includes(this.searchKey.toLowerCase());
});
},
},
methods: {
async changeUser(user) {
await localStorage.removeItem("userChoice");
await localStorage.setItem("userChoice", user.id);
this.$router.push(`/profil/${this.userChoice}`);
},
async changeRoute() {
await this.$router.push(`/profil/${this.userChoice}`);
},
},
};
</script>
<style></style>
and the picture here
if I press a second time on the same profile it gives it to me if I return to the colleagues page but not if I change profile there is an empty page
here picture of the routes path
in fact the route does not change profile and remains on 58 here c the profile of that which is connected and if we change number on the route it launches a page page so this is the problem with the path of the route that the we see in the browser cache
Having looked at your code it's obvious why you'd get an empty page when changing routes. Let me explain:
Your routes say this:
Register a route /profil/${userChoice} (which is a value read from localStorage).
This route definition is only read once, at page intialisation. So, when your page loads only /profil/58 will be defined, /profil/59 wont.
What you are probably looking for is route parameters:
https://router.vuejs.org/guide/essentials/dynamic-matching.html
You'd want the number part of this url to be dynamic and respond to changes.
So, instead of reading the value from localStorage, you would write:
{
path: '/profil/:user_id',
name: 'ProfilUser',
...
}
Now when your Profil components is initialized instead of accessing localStorage you read the provided value as follows:
created() {
var userChoice = this.$route.params.user_id;
}
(note it is also possible to get this param as a prop, consult the vue-router docs on how to do this)
Another thing you need to keep in mind is that you need to respond when this parameter changes. Your component will not be refreshed/remounted.
To respond to parameter changes you can do the following:
watch: {
'$route.params.user_id'() {
this.reloadAllStuff();
}
}
I would recommend to not use localStorage for this use case, let the URL parameter be the main source of truth.
Further reading:
https://qvault.io/2020/07/07/how-to-rerender-a-vue-route-when-path-parameters-change/

Get URL query parameters in Vue 3 on Component

i am new to Vue JS, i must say i really love this platform. I started using it just 3 days back. I am just trying to get the URL query parameter and i am using vue-router as well. Here is how i have it:
http://localhost:8001/login?id=1
Here is how my controller look like.
<template>
<section class="contact-info-area">
<div class="container">
<div class="row">
<div class="col-lg-12">
<section class="write-massage-area">
<div class="mb-5"></div>
<div class="row justify-content-center">
<div class="col-lg-5">
<div class="write-massage-content">
<div class="write-massage-title text-center">
<h3 class="title">Login {{ $route.query.id }}</h3> <!-- THIS IS WORKING -->
</div>
<div class="write-massage-input">
<form #submit.prevent="onSubmitForm">
<div class="row">
<div class="col-lg-12">
<div class="input-box mt-10">
<input type="text" placeholder="Email" v-model="form['email']">
<ErrorMessage :validationStatus="v$.form.email"></ErrorMessage>
</div>
</div>
<div class="col-lg-12">
<div class="input-box mt-10">
<input type="text" placeholder="Password" v-model="form['password']">
</div>
</div>
<div class="col-lg-12">
<div class="input-box mt-10 text-center">
<button type="submit" class="main-btn main-btn-2">Login</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="mb-5"></div>
</section>
</div>
</div>
</div>
</section>
</template>
<script>
import { ref } from 'vue'
import useVuelidate from '#vuelidate/core'
import { required, minLength, email } from '#vuelidate/validators'
import ErrorMessage from '../components/ErrorMessage'
export default {
name: "login",
components: {
ErrorMessage
},
created(){
},
setup(){
const form = ref({})
const rules = {
form: {
email: {
required,
email
},
password: {
required,
minLength : minLength(5)
}
}
}
const v$ = useVuelidate(rules, { form })
function onSubmitForm(){
console.log(this.$route.query.id) **<!-- THIS IS NOT WORKING -->**
v$.value.$touch()
console.log(form.value)
}
return { form, onSubmitForm, v$}
}
}
</script>
here on the above code. On button submit i am going to a function called onSubmitForm, there i am using console.log(this.$route.query.id) but this is giving a below error :
Uncaught TypeError: Cannot read property 'query' of undefined
at Proxy.onSubmitForm (Login.vue?a55b:84)
Why this is happening? I am seeing that in the vue document as well, they mentioned in the same way. What i am missing in this?
Thank you!
You can call useRoute to access the query params...
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.query)
</script>
If you use parameters and your endpoint looks something like this:
{
path: '/inspect_detail/:id',
name: 'inspect_detail',
component: function() {
return import ( '../views/Inspect_detail.vue')
},
params: true
},
and you are routing like this:
<router-link :to="{ name: 'inspect_detail', params: { id: akey }}">...</router-link>
then you can pickup the values like this:
<script>
import { useRoute } from 'vue-router';
export default {
setup(){
const route = useRoute()
console.log( route.params );
}
}
</script>
Bit late but if you want query params to work on page refresh you have to wait for the router to get ready as its asynchronous. The router wont be ready if its a page refresh. The router will be ready if its navigation from another page in that case the query params will be available from the begining.
<script setup>
import { onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()
//just to demonstrate
console.log(route.query)
// If it is a page refresh it will print null.
// The router wont be ready if its a page refresh. In that case the query wont be available.
// The router will be ready if its navigation from another page in that case the query params will be available
onMounted(() => {
getUrlQueryParams()
});
getUrlQueryParams = async () => {
//router is async so we wait for it to be ready
await router.isReady()
//once its ready we can access the query params
console.log(route.query)
});
</script>
I hadn't done frontend in a couple of months and had to refresh on Vue 3 and route query properties, and this question came up first.
Now the memory jog has kicked in, I believe the correct way is to pass the props from the router to the component as shown in the examples here https://router.vuejs.org/guide/essentials/passing-props.html
Essentially, call your route
{
path: "/login",
name: "Login",
props: route => ({ id: route.query.id }),
component: () => import(/* webpackChunkName: "login" */ "../views/Login.vue"),
},
to be able to access the id field.
Alternately, you can sent the whole lot with props: route => ({ query: route.query })
Pick it up as a prop in your view/component
export default {
name: "login",
components: {
ErrorMessage
},
created(){
},
props: {
id: {
type: String,
default: "",
}
}
setup(props){
const form = ref({})
const rules = {
form: {
email: {
required,
email
},
password: {
required,
minLength : minLength(5)
}
}
}
const v$ = useVuelidate(rules, { form })
function onSubmitForm(){
console.log(props.id)
v$.value.$touch()
console.log(form.value)
}
return { form, onSubmitForm, v$}
}
}

Rendering component on runtime after Http request in VueJS

I'm trying to conditionally render a component in VueJS after an Http request right away when the application starts. If the response is ok I would like to render component 1, otherwise component 2. I would also like to render the component onClick
App.vue
<template>
<div id="app">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="navbar-collapse" id="navbarsExample05">
<ul class="navbar-nav pl-md-5 ml-auto">
<li v-for="tab in tabs" v-bind:key="tab" v-bind:class="['nav-item nav-link', { active: currentTab === tab }]"
v-on:click="currentTab = tab">
{{ tab }}
</li>
</ul>
</div>
</nav>
<component v-bind:is="currentTabComponent" class="tab"></component>
</div>
</template>
<script>
import Comp1 from '../components/comp1'
import Comp2 from '../components/comp2'
export default {
name: 'App',
components: {
Comp1,
Comp2
},
data: function() {
return {
currentTab: 'Comp2',
tabs: ['Comp1', 'Comp2']
};
},
computed:{
currentTabComponent: function () {
function check(){
fetch('someHttpUrl')
.then(response => response.json())
.then(data => {
resolve('Comp1')
});
.catch(err => {
resolve('Comp2')
})
}
var result = check();
result.then(async function (data) {
return data
})
}
}
}
</script>
When I click on the tab, the right component is loaded. But not when the application starts.
Is there any Vue method to render asynchronous a component?
There is no need to have currentTabComponent computed method.
You can just make your HTTP call and update currentTab when it is done.
Something like this:
mounted() {
fetch('someHttpUrl')
.then(response => response.json())
.then(data => {
this.currentTab = 'Comp1'
});
.catch(err => {
this.currentTab = 'Comp2'
})
}
I also removed the method named check as it seemed redundant.

Click event on div to get innerText value and $emit with event-bus to another component not working

I have a list of divs that include product information which i get from an API call. In another component/view i want to display a single product information when the divs are clicked on.
So what i'm trying to do is retrieve the product id by accessing the event object when clicking on the divs then store that id in a variable (not data property) and then $emit it with the event-bus and then listen for it in my other component and use that id to make the API call to get the information for that single product. I'm not sure if this is the best way of doing what i want to do, but its the only way that comes to mind right now.
However so far i have gotten a few different errors and my component that displays the single product does not render.
This is the component that displays the list of products/divs
<template>
<div>
<div class="pagination">
<button :disabled="disabled" #click.prevent="prev()">
<i class="material-icons">arrow_back</i>
</button>
<span class="page-number">{{ currentPage }}</span>
<button #click.prevent="next()">
<i class="material-icons">arrow_forward</i>
</button>
</div>
<div class="products">
<div
class="product"
#click="getSingleBeer($event)"
v-for="product in products"
:key="product.id"
>
<h2 class="name">{{ product.name }}</h2>
<div class="image">
<img :src="product.image_url" />
</div>
<h3 class="tagline">{{ product.tagline }}</h3>
<h3 class="first-brewed">{{ product.first_brewed }}</h3>
<h3 class="abv">{{ product.abv }}%</h3>
<p class="id">{{ product.id }}</p>
</div>
</div>
</div>
</template>
<script>
import axios from "axios";
import { eventBus } from "../main";
export default {
name: "Products",
data() {
return {
products: [],
currentPage: 1,
searchVal: ""
};
},
created() {
this.getBeers();
eventBus.$on("keyword", val => {
this.searchVal = val;
this.getBeersForSearch();
});
},
computed: {
apiUrl() {
return `https://api.punkapi.com/v2/beers?page=${this.currentPage}&per_page=16`;
},
apiUrlForSearch() {
return `https://api.punkapi.com/v2/beers?page=${this.currentPage}&per_page=12&beer_name=${this.searchVal}`;
},
disabled() {
return this.currentPage <= 1;
},
isFirstPage() {
return this.currentPage === 1;
}
},
methods: {
async getBeers() {
try {
const response = await axios.get(this.apiUrl);
this.products = response.data;
console.log(response);
} catch (error) {
console.log(error);
}
},
async getBeersForSearch() {
try {
this.currentPage = 1;
const response = await axios.get(this.apiUrlForSearch);
this.products = response.data;
console.log(response);
} catch (error) {
console.log(error);
}
},
getSingleBeer($event) {
const id = parseInt($event.target.lastChild.innerText);
eventBus.$emit("beer-id", id);
this.$router.push({ name: "Beer" });
}
}
};
</script>
And this is the component/view that is going to display info for the single selected product.
<template>
<div class="beer-container">
<div class="description">
<h2>{{ beer.description }}</h2>
</div>
<div class="img-name">
<h1>{{ beer.name }}</h1>
<img :src="beer.image_url" alt />
</div>
<div class="ingredients"></div>
<div class="brewer-tips">
<h2>{{ beer.brewers_tips }}</h2>
</div>
</div>
</template>
<script>
import { eventBus } from "../main";
import axios from "axios";
export default {
name: "Beer",
data() {
return {
beerId: null,
beer: []
};
},
created() {
eventBus.$on("beer-id", id => {
this.beerId = id;
this.getBeer();
console.log(this.beer);
});
},
methods: {
async getBeer() {
try {
const response = await axios.get(this.apiUrl);
this.beer = response.data[0];
console.log(response.data[0]);
} catch (error) {
console.log(error + "Eroorrrrrr");
}
}
},
computed: {
apiUrl() {
return `https://api.punkapi.com/v2/beers/${this.beerId}`;
}
}
};
</script>
Some of the errors i had so far:
1-the api call is made 2-3 simultaneously when i observe console logs instead of just once.
GET https://api.punkapi.com/v2/beers/null 400
Error: Request failed with status code 400Eroorrrrrr
GET https://api.punkapi.com/v2/beers/null 400
Error: Request failed with status code 400Eroorrrrrr
GET https://api.punkapi.com/v2/beers/null 400
Error: Request failed with status code 400Eroorrrrrr
2-The first time i click on the div it directs to the new route/component but i dont receive any errors and nothing seems to happen behind the scenes.
3- I have also been getting this error:
[Vue warn]: Error in v-on handler: "TypeError: Cannot read property 'innerText' of null"
And
TypeError: Cannot read property 'innerText' of null
My router.js
import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";
import Beer from "./views/Beer.vue";
Vue.use(Router);
export default new Router({
mode: "history",
base: process.env.BASE_URL,
routes: [
{
path: "/",
name: "home",
component: Home
},
{
path: "/beer",
name: "Beer",
component: Beer
}
]
});
UPDATE: I'm able to pass the data to the next component but when i click on the product divs the first time nothing happens, i only get directed to the next route/component but data does not get passed. And when i go back and click again,(without refreshing the page) the data gets passed but nothing renders on the component.
I believe you can simplify that a lot by changing your #click to be:
#click="getSingleBeer(product.id)"
Which should pass the id for you, so you can just do:
getSingleBeer(beerId) {
eventBus.$emit("beer-id", beerId);
this.$router.push({ name: "Beer" });
}