How to pass props parameter with axios in Vuejs? - vue.js

I am passing a property in another component via props:
props: ['product']
This Product has some properties like: id, name etc.
Now, I want to get the category of this product with id via axios.
Is it possible? How?
My try:
mounted () {
axios
.get('/categoryofaproduct/', {
params: {
id: this.product.id
}
})
.then(response => {
console.log(response)
})
}

I think Props properties will not be accessable directly like this.
data() {
return {
id: null,
categoryName: null
}
}
In mounted you can copy the id like this and then it will work.
mounted () {
this.id = this.product.id
axios.get('/categoryofaproduct/'+this.id)
.then(response => {
this.categoryName = response.data
})
}

I would recommend to use back ticks to make it a string literal and interpolation to insert the values in. This just makes it more readable when you have multiple parameters in a URL
mounted () {
axios
.get(`/categoryofaproduct/${this.product.id}`
)
.then(response => {
console.log(response)
})
}
Then accept that parameter on your route
{
// create route with id as a parameter
path: "/categoryofaproduct/:id",
name: "category-of-a-product",
component: () => import("./views/categoryofaproduct.vue"),
},
To get access to that param create a computed field that returns it
computed: {
paramsId() {
return this.$route.params.id
},
}

Related

"filter is not a function" TypeError on computed property, simple filter with arrow function

In the below code snippet, if i remove .filter(beer => beer.isFavourite) the computed property works with no error, essentially becoming the same value as allBrewDogBeers. When i add filter, i get "TypeError: this.allBrewDogBeers.filter is not a function". I think maybe this is to do with the context, but i don't really understand what i'm missing, because i've written a filter as simple as this before, but maybe Vue is confusing me.
I just want to have a computed property which is a subset of allBrewDogBeers, I v-bind this computed property to a favourite component in my template.
computed: {
favouriteBeers: function() {
return this.allBrewDogBeers.filter(beer => beer.isFavourite);
}
},
full script:
<script>
import { eventBus } from './main.js'
import BeerList from './components/BeerList.vue'
import BeerDetail from './components/BeerDetail.vue'
import FavouriteBeers from './components/FavouriteBeers.vue'
export default {
name: "App",
components: {
'beer-list': BeerList,
'beer-detail': BeerDetail,
'favourite-beers': FavouriteBeers
},
data() {
return {
allBrewDogBeers: [],
selectedBeer: null
};
},
computed: {
favouriteBeers: function() {
return this.allBrewDogBeers.filter(beer => beer.isFavourite);
}
},
methods:{
addFavourBeer: function(beer) {
const index = this.allBrewDogBeers.indexOf(beer);
this.allBrewDogBeers[index].isFavourite = true;
},
removeFavourBeer: function(beer) {
const index = this.allBrewDogBeers.indexOf(beer);
this.allBrewDogBeers[index].isFavourite = false;
}
},
mounted(){
fetch("https://api.punkapi.com/v2/beers")
.then(response => this.allBrewDogBeers = response.json())
.then(data => this.allBrewDogBeers = data);
eventBus.$on('beer-selected', (beer) => {this.selectedBeer = beer});
eventBus.$on('beer-favourite-add', beer => this.addFavourBeer(beer));
eventBus.$on('beer-favourite-remove', beer => this.removeFavourBeer(beer));
}
};
</script>
You've got a problem here:
.then(response => this.allBrewDogBeers = response.json())
That's assigning a promise to this.allBrewDogBeers, which isn't what you want.
Change it to:
.then(response => response.json())
The other then will handle the assignment.

How to get value of Vuex getter inside of Vue local data object

Hey this seemed to be pretty simple, but I just can't figure out how to get my loggedInUser object to work outside the template. I read through a bunch of other answers and I know I have to do something to store the getter in a local data object.
I have a temporary 'id' object set up because that's what I ultimately want to set to loggedInUser.id in order to attach to my Axios request.
Here's the page I want to make changes on:
<script>
import { mapGetters } from 'vuex'
// import vuex from 'vuex'
export default {
data: () => ({
results: "",
id: "15",
}),
computed: {
...mapGetters(['loggedInUser'])
},
// var id = {{loggedInUser}};
methods: {
getData() {
this.$axios.get('http://127.0.0.1:8000/api/v1/actors/',
{params: {user: this.id} }
)
.then(response => {this.results = response.data});
}
}
}
</script>
and here's my index.js for store:
export const getters = {
isAuthenticated(state) {
return state.auth.loggedIn
},
loggedInUser(state) {
return state.auth.user
}
}
The mapGetters helper simply maps store getters to local computed
properties
This:
computed: {
...mapGetters(['loggedInUser'])
},
Is equivalent to this:
computed: {
loggedInUser() {
return this.$store.getters.loggedInUser
},
},
Replace this.id with this.loggedInUser.id in your axios request, and get rid of the temporary id data property.
getData() {
this.$axios.get('http://127.0.0.1:8000/api/v1/actors/', {
params: {
user: this.loggedInUser.id
}
})
.then(response => {
this.results = response.data
});
}
We are assuming getData only gets called when the user is authenticated. If that's not the case, have in mind this.loggedInUser may be null or undefined and accessing this.loggedInUser.id will throw an error.

Clone / Copy state is returning empty state

I am having an issue using lodash's cloneDeep to clone the user object passed in from the store. When I attempt to render the data in the template {{ user }} shows the data retrieved from the store and {{ userCopy }} shows the empty store. I am not sure why this is happening, I am new to Vue.
store/staff.js
import StaffService from '~/services/StaffService.js'
export const state = () => ({
user: {
offers: '',
legal: ''
}
})
export const mutations = {
SET_USER(state, user) {
state.user = user
},
}
export const actions = {
fetchUser({ commit, getters }, id) {
const user = getters.getUserById(id)
if (user) {
commit('SET_USER', user)
} else {
StaffService.getUser(id)
.then((response) => {
commit('SET_USER', response.data)
})
.catch((error) => {
console.log('There was an error:', error.response)
})
}
},
}
export const getters = {
getUserById: (state) => (id) => {
return state.staff.find((user) => user.id === id)
}
}
pages/settings/_id.vue
<template>
<div>
{{ user }} // will display the whole object
{{ userCopy }} // will only display empty store object
</div>
</template>
<script>
import _ from 'lodash'
data() {
return {
userCopy: _.cloneDeep(this.$store.state.staff.user)
}
},
computed: {
...mapState({ user: (state) => state.staff.user })
},
created() {
this.$store.dispatch('staff/fetchUser', this.$route.params.id)
},
</script>
My guess would be that a Vue instance's data is initialized before state becomes available. While computed props are populated/updated as their data source change.
If the component doesn't need to change the value of user during runtime, I'd suggest turning it into a computed property.
If your component does change the value during runtime (such as when it's v-model'd to an input), there are two approaches you can do.
Method 1: Using mounted hook
This is done by placing user in data property and then assigning a value when the instance is mounted, like so:
mounted () {
this.$data.userCopy = _.cloneDeep(this.$store.state.staff.user)
}
Method 2: Using computed with getter and setter functions.
Normally, you shouldn't change a computed value. But it can be done using a setter function. With this, when Vue detects an attempt to change a computed prop it will execute set() with the old and new values as arguments. This function would change the value at its source, allowing get()'s returned value to reflect this. For example:
computed: {
userCopy: {
get () {
return _.cloneDeep(this.$store.state.staff.user)
},
set (newValue) {
this.$store.commit('updateStaff', newValue) // Replace this line with your equivalent state mutator.
}
}
}

passing data to route's component beforeEnter

I have the following VueRouter route
{
path: '/playlists/:id',
name: 'videos',
component: Video,
props: {
videos: [],
},
beforeEnter(to, from, next) {
Vue.axios
.get('/playlistitems?playlistId='.concat(to.params.id))
.then((response) => {
to.params.videos = response.data
next((vm) => {
console.log(vm)
vm.videos = response.data
})
})
.catch((err) => console.log('error', err))
},
}
When the route is entered into everything executes as expected but I'm not sure how to pass the response.data to the route's component Videos
Question 1
Can you set the Vue component's props property from the Router?
Question 2
The route is a dynamic route. If the route and component is already loaded and the dynamic parameter changes....does beforeEnter still fire? If not where should I put my data fetching logic? Do I watch for route changes inside the Vue component?
1)
This might not be the most elegant approach, but here's a way to achieve that:
let videos = [];
export default new Router({ ... });
{
path: '/playlists/:id',
name: 'videos',
component: Video,
props: route => ({ videos }),
beforeEnter (to, from, next) {
Vue.axios.get('/playlistitems?playlistId='.concat(to.params.id))
.then((response) => {
// Now the data will be available when the props will be initialized
videos = response.data
next()
})
.catch((err) => console.log('error', err))
}
}
// Videos.vue
props: {
videos: Array
},
2)
IMHO, it would be easier if you could encapsulate the logic in the component.
What do I mean by that is that you could fetch your data in the created hook and set it to a variable that you defined in your data function.
data() {
return {
videos: []
}
},
created () {
Vue.axios.get('/playlistitems?playlistId='.concat(this.$route.params.id))
.then((response) => {
this.videos = response.data;
})
.catch((err) => console.log('error', err))
},
Another approach, which may be suitable or not, depending on what you're working on, would be to have a parent component that fetches multiple playlists which could be stored in vuex.
Thus, you would have another component that handles playlists/:id.
Within this last mentioned component, in your created hook, you would have something like this:
created () {
this.$store.commit('playlist/SET_CURRENT_PLAYLIST_ID', this.$route.params.id);
this.videos = this.$store.getters['playlits/getVideosByPlaylistId'];
},

Vue component doesn't update on route URL parameter change

So I have a component which executes code once it's mounted like this:
mounted(){
axios.get('/markers/' + this.username)
.then(response => {
this.markers = response.data.markers
}).catch((error) => console.log(error));
}
And I get the username like this:
username: this.$route.params.username
however, if I change the URL parameter, the username doesn't update so my AXIOS call doesn't update my markers. Why is this happening?
The reason is simple, even thought the URL is changing the component is not, VueJS is basically reusing the component and therefore not calling the mounted() method again.
Usually you can just setup a watcher and refactor a bit your code
methods: {
fetchData(userName) {
axios.get('/markers/' + this.username)
.then(response => {
this.markers = response.data.markers
}).catch((error) => console.log(error));
}
},
watch: {
'$route.params': {
handler(newValue) {
const { userName } = newValue
this.fetchData(userName)
},
immediate: true,
}
}
EDIT: Added the immediate true option and removed the mounted() hook