Edit: I can't get the params.id because nuxt-link pass it to detail page.
I'm trying to build a blog with NuxtJS.
This is the link for blog detail page.
<nuxt-link :to="{name: 'category-slug', params: { slug: slug, id: id, category: category } }">
It works well but after I refresh detail page (i.e: tech/hello-world), it returns Cannot read property 'author' of null
_slug.vue
<template>
<div>
<h1>slug {{ $route.params.id }}</h1>
{{ loadedPost.author }}
</div>
</template>
<script>
import Vuex from "vuex"
import axios from "axios"
export default {
asyncData(context) {
console.log(context.params.id)
return axios.get('https://howto-a9089.firebaseio.com/posts/' + context.params.id + '.json')
.then(res => {
return {
loadedPost: res.data
}
})
},
}
</script>
I think there's a problem with asyncdata. Why it happens?
As per the documentation, you should set a default value for loadedPost so you don't get errors like this while the asynchronous data is loading
export default {
data() {
return { loadedPost: {} }
},
asyncData({ params }) {
return axios.get(`https://howto-a9089.firebaseio.com/posts/${params.id}.json`)
.then(res => ({
loadedPost: res.data
}))
}
}
Without this, loadedPost is null when your template attempts to display loadedPost.author and that's why you get that error.
Thanks for answers. Here's the solution. _slug.vue only gets params.id when user clicks the below button.
<nuxt-link :to="{name: 'category-slug', params: { slug: slug, id: id, category: category } }">
When user enters directly this url or refresh the page, there will be no params.id. So I needed to GET data by "slug".
Thanks to Firebase:
return axios.get('https://howto-a9089.firebaseio.com/posts.json?orderBy="slug"&equalTo=' + '"' + params.slug + '"' + '&print=pretty')
Result: I got SEO friendly url now. :) (i.e url.com/tech/hello-world)
Related
De idea is not to program the name, but to pass the name as a property.
So i can have a base vue component and i tell what vue component to load in there dynamicly by giving name and location.
Which works perfect when i type the string (set the name) but not when i put the name in a string then it says module not found.
so if I import('./yyy.vue') it works but if. but if I import(var_that_is_the_name) it says not found. i think it has something to do with laravel mix or stringparsing.
<template>
<div class="xxx" ref="xxx">
<component :is="dynamicComponent"></component>
<div class="right">
right {{ this.DvueLocation }}
</div>
</div>
</template>
<script>
import { defineAsyncComponent } from '#vue/runtime-core'
export default {
name: 'xxx',
components: {
},
props: {
DvueLocation: {
type: String,
default: "./yyy.vue",
},
DvueName: {
type: String,
default: "yyy"
}
},
data: function () {
return {
isMounted: false,
}
},
computed: {
dynamicComponent() {
console.log(this.DvueLocation);
return defineAsyncComponent(() => import('./yyy.vue'))
return defineAsyncComponent(() => import(this.DvueLocation))
}
},
}
</script>
the yyy.vue is a simple component that prints yyy.
first line works, second with not cold not add // for it and save.
i tried putting "'" + around it en lots more
while its exactly the same if i type it.
both the string printed and on console of browser gives the right value
Something to do with string parsing.
return defineAsyncComponent(() => import('./' + this.DvueName))
This works for me now!
i'm new to vue and i have created a dynamic page that gets questions,user name, and categories from API ,every thing is showing fine but my problem is i want to make those dynamic (user name for example) is clickable so when ever i click on it it should take me to user's profile with same name, i have tried to do a clickable div but only the url route changes not the content of the page (it's not taking me to the profile page), also as u see in my code i created a function in methods that saved my clickable user in index and i'm trying to show this user saved in index in my profile page but i didn't figure out how to do it, any help please?
hom.vue
<p>Asked by: </p>
<div id="user" v-for="(user, index) in users"
:key="index">
<div #click="selectedUser(index)">{{ user }}</div>
</div>
export default {
props: {
question1: Object
},
data() {
return {
selectedIndex: null,
};
},
watch: {
question1: {
handler() {
this.selectedIndex = null;
},
},
},
computed: {
users() {
let users = [this.question1.user];
return answers;
},
},
methods: {//here i saved the user that i clicked on in index in order to show it to the profile page
selectedUser(index) {
this.selectedIndex = index;
this.$router.push('/Profile')
},
}
}
profile.vue
<template>
<div class="container" width=800px>
<b-row id="asked-info">
<p>Welcome to the profile of: </p>
<div id="user" v-for="(user, index) in users"
:key="index">
{{ user }}
</div>
</b-row>
</div>
</template>
<script>
export default {
props: {
question1: Object
},
computed: {
users() {
let users = [this.question1.user];
// here i'm not able to figure out how will the user i saved in index (the user i clicked on) will show here
return users;
},
},
}
</script>
</script>
You can pass the index via props to route components.
Your selectedUser function would be like:
selectedUser(index) {
this.$router.push({ path: `/Profile/${index}` })
},
In your Router instance:
routes: [
{
path: '/profile/:index',
component: Profile,
props: true //to specify that you are using props
},
//your other routes
]
Then in the profile.vue, you can access the index by this syntax: this.$route.params.index
But this is just how you pass the index to the profile.vue page, eventually you need to have access to the users array which you have in the hom.vue page, which means that you are sharing data between components (or pages). I strongly suggest you to use Vuex, the Vue state management, a centralized store for your app. You can check out their documentation here: https://vuex.vuejs.org/#what-is-a-state-management-pattern
I am new with Vue and I am using API to show data, here in my code when click is performed to category it saves that name of category and redirects user to another page called category.vue, my problem is after redirecting user I want now to show questions with that category name that been received only (as filter), is there a way to do it?
/* this is how i saved data to transfer to category page */
<div class="category" v-for="(categoryy,index) in category(question1)" :key="index">
<router-link :to="`/category/${category(question1)}`"> {{ categoryy }} </router-link>
</div>
category.vue
<template>
<div class="vw">
<p> related question of </p>
<p>{{ this.$route.params.cat }}</p> /* category name i sent appears here */
<ul class="container-question" v-for="(question1,index) in questions" :key="index"
>
/* THE PROBLEM : it shows all questions without filtering */
{{question1.question}}
</ul>
</div>
</template>
<script>
export default {
props:
{
question1: Object
},
data(){
return{
questions: []
}
},
computed:{
category(){
let category = this.$route.params.cat;
return category
}
},
mounted: function(){
fetch('https://opentdb.com/api.php?amount=10&category=9&difficulty=medium&type=multiple',{
method: 'get'
})
.then((response) => {
return response.json()
})
.then((jsonData) => {
this.questions = jsonData.results
})
}
}
</script>
You can first get all the categories with this route https://opentdb.com/api_category.php
As i suspect you already have done on the first vue page.
Then as you do, you pass the id of the category as a route param.
The only thing you seem to miss here is that you have hardcoded the category id 9 in your mounted fetch.
You would want to change this to:
fetch(`https://opentdb.com/api.php?amount=10&category=${this.category}&difficulty=medium&type=multiple`,{
method: 'get'
})
This way uses the computed property you created above from the router param from the previous page.
you have to pass the route param not in a computed property, but directly on the mounted hook,
export default {
mounted() {
fetch(
`https://opentdb.com/api.php?amount=10&category=${this.$route.params.cat}&difficulty=medium&type=multiple`,
{
method: "get",
}
)
.then((response) => response.json())
.then((jsonData) => (this.questions = jsonData.results));
},
};
Is there a way to make this happen by id through the URL? And how do I set it up that the information that populates on the second page is only by that id number? Having a major braindead moment
<div v-for="prize in prizes" :key="prize.name">
<div class="card_individual">
<div class="card-media-container">
<img class="card_image" src="../assets/c5Cor.jpg" alt="people"/></div>
<div class="card-detail-container">
<div class="card_title">Win a {{ prize.name }}</div>
</div>
<div class="modal-footer">
<router-link :to="{ name: 'PriceDetail'}"><button type="button" class="btn btn-primary">{{ cards.btn_text }}</button></router-link>
</div>
</div>
</div>
<script>
import axios from 'axios'
export default {
name: 'Prizes',
data () {
return {
prizes: [],
}
},
mounted () {
this.getPrizes()
},
methods: {
getPrizes () {
axios.get('http://localhost:3000/prizes').then(response => {
this.prizes = response.data.prizes
this.id = response.data.prizes.id
})
}
}
}
You'll need to pass the id as a prop so that the 2nd view can use a different API call to retrieve a prize (price?) by id. The detail view should look something like this:
props: {
prizeId: Number
},
data () {
return {
prize: {},
}
},
mounted () {
this.getPrizeById()
},
methods: {
getPrizeById() {
axios.get('http://localhost:3000/prizebyid/' + this.prizeId).then(response => {
this.prize = response.data.prize
})
}
}
You can pass that id prop in the router-link from the main list like this:
<router-link :to="{ name: 'PriceDetail', params: { prizeId: prize.id }}">
This passes the id as part of the route's path (known as a param). Just make sure that the route definition for the PriceDetail route expects params, and also turns them into props (using props: true), which you can do like this:
{ path: '/<your-path>/:prizeId', name: 'PriceDetail', props: true }
And you need to make sure that your backend is configured to serve up individual data when a route like http://localhost:3000/prizebyid/1000 is visited.
If you want to make it more slick, you can serve up all results when visiting http://localhost:3000/prizes, and individual results when serving http://localhost:3000/prizes/1000, using the prizes route for both. I just used prizebyid route in my example for clarity since it might be easier to configure in the backend at first.
I'm trying to make a blog with vuejs and I'm a bit stuck.
All my article data is in a Vuex Store like this :
export const store = new Vuex.Store({
state: {
articles: [{
title: "Article 1",
id: 1,
content:"Article 1 content"
}, {
title: "Article 2",
id: 2,
content:"Article 2 content"
}
}]
}
I have a grid of articles on my homepage :
<div class="item-article" v-for="article in articles">
<router-link :to="{path: '/article/'+article.id}"></router-link>
<div>{{ article.title }}</div>
</div>
When I click on a grid article, I want it to redirect to the articlePage.vue component with the data of the same id article.
So far, on my articlePage.vue component I am with this :
<div v-for="article in selectedArticle">
<h1>{{ article.title }}</h1>
<p>{{ article.content }}</p>
</div>
computed: {
selectedArticle(){
return this.$store.state.articles.filter(article => article.id == this.$route.params.id);
}
}
I want to use $route.params.id in order to catch the matching id in VueX, and access to the the right data. But it's not working. What am I doing wrong?
Thanks for your help! :)
First, define your routes and look how to create a dynamic route:
const routes = [
{
path: '/articles/:id',
name: 'articles',
component: articlePage,
props: true
}
]
In your Vue instace, pass routes and vuex store:
new Vue({
store,
router: routes,
el: '#app',
render: h => h(App)
})
In getters property in your Vuex Store, you need to create a method that filter/find article by id, something like that:
getArticlesById: (state) => (id) => state.articles.find(article => article.id === id)
And finally, in your mounted() method, call him:
this.article = this.$store.getters.getArticlesById(this.articleId)
this.articleId is the param sending by URL, remember define him in component props:
export default {
name: "articlePage",
props: ["category"],
...}
Name your routes and pass your articleId like this:
<router-link :to="{ name: 'article', params: { id: article.id }}">{{article.title}}</router-link>
Also, using Array.prototype.find might be a better idea than using Array.prototype.filter because the second one would give you a one-element array in your case.
You should use find instead of filter, and add return within the find callback function
selectedArticle() {
let article = this.$store.state.articles.find(article => {
return article.id == this.$route.params.id
});
return article;
}