i have this json object
blog:{
"_id": "62567252370e769a8a93a517",
"title": "my trip to zanziar"
}
i'm trying to show in my url
http://localhost:8082/blog/my-trip-to-zanziar
in my url
but i'm getting
http://localhost:8082/blog/my%20trip%20to%20zanziar
and its not displaying any data
this is how i go to the route
<router-link :to="`/blog/${blog._title}`">
</router-link>
this is my router
{
path: "/blog/:title",
},
this is how i diplay to get the details under the title
mounted() {
axios
.get(`http://localhost:4000/api/blogs/${this.$route.params.title}`, {})
.then(response => {
console.log(response);
this.blog = response.data.blog;
})
.catch(error => {
console.log(error);
});
}
please how i can go about this
use String.prototype.replaceAll() where appropriate to replace empty spaces with hyphens:
<router-link :to="`/blog/${blog?._title?.replaceAll(' ', '-')}`" />
You might also consider making the formatted string it's own computed property if you need to perform the replacement more than once in your component.
you should add one more property like a slug in the blog object.
this.blog = { ...blog, slug: blog.title.replaceAll(' ','-').toLowerCase()}
now, you can use the slug in the router link.
<router-link :to="`/blog/${blog.slug}`"> ... </router-link>
Related
In Home.vue I get data from db.json and store it into jobs: [] array.
export default {
name: 'Home',
data() {
return {
jobs: [],
}
},
components: {
},
mounted() {
fetch("http://localhost:3000/jobs")
.then(res => res.json())
.then(data => this.jobs = data)
.catch(err => console.log(err.message))
}
}
Also in Home.vue I show this data, but only in a short list with:
v-for="job in jobs.slice(0, 5)"
In AllJobs.vue I want to show the full data from db.json and in AddJob.vue I will make a form to be able to add data to db.json.
In App.vue I have the router-links:
<template>
<div class="container">
<div class="navigation">
<h1 class="title">{{ $route.name }}</h1>
<nav>
<router-link :to="{ name: 'Latest open positions' }">Home</router-link>
<router-link :to="{ name: 'All open positions' }">Jobs</router-link>
<router-link :to="{ name: 'Add a new job' }">Dashboard</router-link>
</nav>
</div>
<router-view/>
</div>
</template>
How I pass data from Home.vue into AllJobs.vue?
Should I get another fetch method into AllJobs.vue to get data?
Should I get data into App.vue and then pass it into files that I need?
What is the best approach?
When it comes to handling API requests and sharing data between components, what you need is some state management solution like pinia.
You can fetch and save your data in a store and then use it in any component:
jobs.js
export const useJobsStore = defineStore('jobs', {
state: () => ({ jobs: [] }),
actions: {
fetchJobs() {
fetch("http://localhost:3000/jobs")
.then(res => res.json())
.then(data => this.jobs = data)
.catch(err => console.log(err.message))
},
},
})
App.vue
import { mapActions } from 'pinia
import { useJobsStore } from './jobs.js'
export default {
methods: {
...mapActions(useJobsStore, ['fetchJobs'])
},
mounted() {
this.fetchJobs()
}
}
Home.vue and AllJobs.vue
import { mapState } from 'pinia'
import { useJobsStore } from './jobs.js'
export default {
computed: {
// this makes this.jobs available in script and template
...mapState(useJobsStore, ['jobs'])
}
}
One thing which is debatable is where to call fetchJobs action
In App.vue or main.js - this will fetch data as soon as you open the app, but can be unnecessary if the page you visit doesn't even use the data.
In each page that uses the data - solves the previous problem, but fetches the same data multiple times.
In each page that uses the data (with caching) - you can modify fetchJobs to make a request only if the data haven't been fetched already. This way the app will fetch the data as soon as you visit some page which uses it. And if you visit another page, it will use the cached value instead of making a request
There isn't a singe best approach, which one to pick depends on your needs
So, I'm creating a Pokemon application and I would like to display the pokemon names using the api : https://pokeapi.co/api/v2/pokemon/.
I'm doing a fetch request on the api and then display the pokemon names in my template. I have 0 problem when I try to display only 1 pokemon but I have this error when I try to display all my pokemons using v-for.
Do you have any idea why I meet this error ?
<template>
<p class="dark:text-white"> {{pokemons[0].name}} </p> //working
<div v-for="(pokemon, index) in pokemons" :key="'poke'+index"> //not working...
{{ pokemon.name }}
</div>
</template>
<script>
const apiURL = "https://pokeapi.co/api/v2/pokemon/"
export default {
data(){
return{
nextURL:"",
pokemons: [],
};
},
created(){
this.fetchPokemons();
},
methods:{
fetchPokemons(){
fetch(apiURL)
.then( (resp) => {
if(resp.status === 200){
return resp.json();
}
})
.then( (data) => {
console.log(data.results)
// data.results.forEach(pokemon => {
// this.pokemons.push(pokemon)
// });
// this.nextURL = data.next;
this.pokemons = data.results;
console.log(this.pokemons);
})
.catch( (error) => {
console.log(error);
})
}
}
}
</script>
<style>
</style>
I've just pasted your code into a Code Pen and removed the working/not working comments and the code runs and shows the names.
Maybe the problem is in the parent component where this component is mounted, or the assignment of the :key attribute
try :key="'poke'+index.toString()", but I'm pretty sure js handels string integer concats quiet well.
Which version of vuejs do you use?
Edit from comments:
The parent component with the name PokemonListVue imported the posted component as PokemonListVue which resulted in a naming conflict. Renaming either one of those solves the issue.
In the error message posted, in line 3 it says at formatComponentName this is a good hint.
I would like to know is there is a way to do something like this without backend. I am calling all data from json server and displaying on home page:
async created() {
try{
const products = await axios.get('http://localhost:3000/products')
this.products = products.data
} catch(err) {
console.log(err)
}
}
Now when i click any of these products i would like to redirect user to new page and would like to display data of that specific object from json server.
What i have built for now is when user click on any product he gets redirected to route /product, and everything is hardcoded there, no dynamic data.
I hope my question is clear, thank you everybody.
You should consider using Vuex for this.
Move your method from created() to vuex's action and then call it in the hook.
The Vuex store's code is gonna be something like this:
state: {
products: []
},
getters: {
getProductById: (state) => (id) => state.products.find(product.id === id)
},
mutations: {
SET_PRODUCTS(state, products) {
state.products = products
}
},
actions: {
// this one is to call from the hook
fetchProducts({ commit }) {
return axios.get('http://localhost:3000/products').then(res => {
commit('SET_PRODUCTS', res.data)
})
}
}
Then call something like this from the component you're redirecting from:
<router-link
:to="{
name: 'Product', // im assuming this is the /product route's name
params: {
id: product.id // product.id is the id of your specific object your clicked on
}"
>
{{ product.productName }}
</router-link>
In your <Product /> component, you get the specific object by id from your Vuex store by using the getProductById() getter.
In your template:
...
<!-- the id we've passed as a route params -->
<h1>{{ getProductById($route.params.id) }}</h1>
...
This is my script that calls axios and fetch data as posts
<script>
import axios from 'axios'
export default {
name: 'App',
mounted: function () {
axios.get('API URL')
.then(response => this.posts = response.data)
},
data() {
return {
posts: null
}
},
};
</script>
My code on view that tries to fetch data as posts from the script above
<template>
<div id="app">
<ul>
<li v-for="post in posts" v-text="post.createdAt"></li>
</ul>
<div>
</template>
SAMPLE data fetched from API URL look like this
POSTS OBJECT VARIABLES
I am able to fetch API DATA in console log as an array but when I call one object from array which is createdAT, v-text = "post.createdAt" does not print/fetch list of createdAt date list.
Just solved it following this document USING AXIOS TO CONSUME API here is the link for that https://v2.vuejs.org/v2/cookbook/using-axios-to-consume-apis.html .
Above code that I have posted works fine. Problem was on my API URL which was nested inside data[data[object]]. So the way I called data from that API
from this
mounted: function () {
axios.get('API URL')
.then(response => this.posts = response.data)
}
to this
mounted: function () {
axios.get('API URL')
.then(response => this.posts = response.data.data)
}
posts isn't reactive because the default value is null, make it an empty array, or use Vue.set instead:
Array:
posts: []
Vue.set:
.then(response => Vue.set(this, 'posts', response.data))
Edit
In response to the comments below:
You must import Vue from 'vue' to resolve the Vue is not defined error.
Regarding your v-for-key needing to be unique, you need to define a unique key on v-for elements. You can just use JSON.stringify(post):
<li v-for="post in posts" v-text="post.createdAt" :key="JSON.stringify(post)"></li>
i have a navbar and there is a text field in that the user can search for posts by tags. If the user enters 1-3 tags, the written tags will be stored in a tags array.
My router-link in the navbar component looks like this: (only relevant part)
<router-link :to="{name:'posts', props:{searchTags: tags}}">
<button type="button" v-if="this.tags.length > 0"
class="...">Search
</button>
</router-link>
in my routes.js is my posts route (important snippet of my routes.js)
routes: [
{
path: "/posts",
component: posts,
name: 'posts'
},
]
The navbar should send the tags array to the posts component. Unfortunately I can't do it.
The posts component, sends a post request to an API that gets the latest posts. But I want that when tags are passed, not the newest posts are fetched, only posts with certain tags. But first I have to get the tags somehow.
I tried to get them with "this.$props.searchTags" and other things. Unfortunately the result is always "undefined".
export default {
name: "posts",
props: {
searchTags: Array,
required: false
},
data: function () {
return {
apiUrl: '/getPosts',
....
tags: [this.searchTags],
}
},
methods: {
getPosts: function (url) {
this.$http.get(url).then(function (data) {
// blabla
});
},
getPostsByTags: function() {
//
},
},
created() {
if(this.$props.searchTags == null)
this.getPosts(this.apiUrl);
else
this.getPostsByTags(bla);
},
}
Router link to property accepts string or Location as a value. Location object does not have props property.
Instead, it is possible to use params to send data to route component:
<router-link
:to="{ name: 'posts', params: { searchTags: tags } }"
>
...
</router-link>
This way searchTags with value of assigned tags will be accessible via this.$route.params.searchTags inside destination component.
So created hook of example above should be updated to:
created () {
if (!this.$route.params.searchTags) {
this.getPosts(this.apiUrl);
} else {
this.getPostsByTags(bla);
}
},
Try to add props: true in your route definition
routes: [
{
path: "/posts",
component: posts,
name: 'posts',
props: true
},
]