I'm using the following link to dynamic routes
<nuxt-link :key="$route.fullPath" :to="{ name: 'items-id', params: { parent: { id: item.parent.id, description: item.parent.description } }}">Click me</nuxt-link>
So navigating to /items/ correctly passes the specified params. But if i click another nuxt-link with different params, while being on the /items/ url then nothing happens. I imagine it's because the url doesn't really change.
What's the best way to "reload" the url with new params?
I've considered using path which would be different for each nuxt-link
<nuxt-link :key="$route.fullPath" :to="{ path: '/items/' + item, params: { parent: { id: item.parent.id, description: item.parent.description } }}">Click me</nuxt-link>
But this makes the URL ugly as it includes the object ref
Just watch() the params (probably the id) and reload data when they change:
watch: {
id() {
// reload your item here
},
...
},
Using watch should do it. Just update the variable you want to change according to the value for example if you want to watch for the id variable then set it to a component variable that you will want to be displayed.
watch: {
id (value) {
this.VARIABLE = value
}
}
Related
Coding Enviroment: Vue3, JavaScript
Router code:
{
path: '/group/:id',
component: Group,
children: [
{
path: 'homework_list',
component: HomeworkList,
},
{
path: 'member_list',
component: GroupMemberList
},
]
},
Vue code:
<router-link to="homework_list">Homework List</router-link>
First I can visit the link http://localhost:3333/group/1, when I click the router-link, I want to go a URL like http://localhost:3333/group/1/homework_list, but it just go to the URL http://localhost:3333/group/homework_list.
I know I can change the router-link like following code to implement the function. But the id is not static.Is it necessary to add the id value of current link to all route-link? It seems a bit troublesome.
<router-link to="1/homework_list">Homework List</router-link>
My English is not so good, if there is any inappropriate expression, please forgive me.
to property of router-link is just like any other property of your custom components and as such, it can be dynamic. For example, let's assume that you have groupId property in your data
<template>
<div>
<router-link :to="groupId + '/homework_list'">Homework list</router-link>
</div>
</template>
<script>
export default {
data () {
return {
groupId: 15
}
}
</script>
Note that there is a big difference between to="foo", and :to="foo". The first one is static (string foo) and second one is dynamic (referencing property named foo) - meaning that every time that property changes it will be propagated to the child components.
You can read about it further here
Hi I'm trying to use a Vue.js router-link to pass a parameter dynamically into a component. I'm getting a browser error that says that the parameter is not defined, even though the router URL is being displayed correctly, with the parameter. The component is also rendered, but the data does not seem to be accessible in the component as a property or data element.
Here is my table with router-link:
<sui-table-row v-for="(player, i) in allPlayers" :key="i">
<sui-table-cell>{{player.league}}{{i+1}}</sui-table-cell>
<sui-table-cell>{{ player.player1 }}&{{player.player2}}</sui-table-cell>
<sui-table-cell selectable v-for="(week, j) in allDates" :key="j">
<router-link :to="{ name: 'addWeek', params: {team1: player._id } }">
{{player.schedule[j]}}
</router-link>
</sui-table-cell>
</sui-table-row>
Routes.js
import AddWeek from '#/views/admin/addWeek.vue';
const routes = [{
path: '/ncl-schedule/addWeek/:team1',
name: 'addWeek',
component: AddWeek
}]
export default routes
Two issues I'm having here:
1: Chrome is throwing the following error:
[vue-router] missing param for named route "addWeek": Expected "team1" to be defined
This is odd because I get the team id passed as the param on the route, and it brings me to the AddWeek component as I'd expect.
http://localhost:8080/ncl-schedule/addWeek/5e6bc31785aa8e5ab4575d80
2: I can't get the data as a property or data element in the component, however.
The error indicates that player _id isn't ready when the component is first rendered, maybe it's async data. Try a v-if on your link:
<router-link v-if="player && player._id" :to="{ name: 'addWeek', params: {team1: player._id } }">
Params are accessed at this.$route.params in the target component. You can automatically convert those to props if you prefer, by defining your route with the props: true option:
const routes = [{
path: '/ncl-schedule/addWeek/:team1',
name: 'addWeek',
component: AddWeek,
props: true
}]
You need to also create the team1 prop in addWeek.
Click Schedule Link Here to View Example
With regard to the initial Chrome error, Dan was correct that the data was async and therefore not rendered upon initial load. This is resolved now in this solution.
I ultimately wanted multiple parameters to be passed in from the component. In order to accomplish this I used "query" opposed to "params", in the "router-link". The rest of the code block is included for clarification of the parameters being passed.
Parent Component:
<sui-table-row v-for="(players, i) in allPlayers" :key="i">
<sui-table-cell>{{players.league}}{{players.teamNumber}}</sui-table-cell>
<sui-table-cell>{{ players.player1 }}&{{players.player2}}</sui-table-cell>
<sui-table-cell selectable v-for="(week, j) in allDates" :key="j">
**<router-link :to="{ name: 'addWeek', query: {selectedTeam: players, week: week.weekId, match: players.schedule[j] } }">
{{players.schedule[j]}}
</router-link>**
</sui-table-cell>
</sui-table-row>
routes.js
const routes = [{
path: '/schedule/addWeek',
props(route) {
return route.query || {}
},
name: 'addWeek',
component: AddWeek
}]
Finally within the component I wanted to access the data I retrieved them from the route within the mounted hook as follows:
Consuming Component:
async mounted() {
// this is the team in the players field who's week's matches were chosen.
this.selectedTeam = this.$route.query.selectedTeam
// teams clicked on
this.teamsPlayed = this.$route.query.match
// this is the week the matches take place - intersection of selectedTeam, date
this.schedule.weekId = this.$route.query.week
}
If I’m on a page with the URL 'http://localhost:8080/item' and I’m clicking on the same link on this page, then the page does not reload.
I need to make that if I click on the same link, the page will reload.
My link:
<nuxt-link :to="/item">
Any insight will be welcome. Thanks!
Use key, something like:
<router-view :key="$route.params.yourCustomParam"/>
Also you can use something like:
<router-link :to="{ params: { yourCustomParam: Data.now } }" replace>link</router-link>
Remember to is passed router.push() and it accept an object also. Doing that, it is more declarative and controllable. I'm using this to decide if the page of component should be rerendered since they will based on id params obtained from URL entry, and my child component can still using nesting .
I recently tried to solve a similar issue and to overcome this I used Vuex with :key (ref).
Firstly, in your store you need a state property such as:
export const state = () => ({
componentUpdates: {
item: 0,
//can add more as needed
}
})
In general, you could use only one property across the app if you prefer it that way. Just remember that later on, the key value needs to be unique - that is in the case if you used this property for two or more components within one page, for example. In this case, you could do something like this :key="$store.getters.getComponentUpdates.item+'uniqueString'"
then a getter:
export const getters = {
getComponentUpdates(state) {
return state.updateComponent;
}
}
finally a mutatation:
export const mutations = {
updateComponent(state, payload) {
return state.componentUpdates[payload.update]++
}
}
Now we can utilise the reactive :key wherever needed.
But first in your nuxt-link lets add an event to trigger the mutation, note the usage of #click.native to trigger the click event:
<nuxt-link #click.native="$store.commit('updateComponent', { update: 'item'})" :to="/item">
Now in the item page, for example. Let's imagine there is a component that needs to be updated. In this case we would add :key to it:
<my-item :key="$store.getters.getComponentUpdates.item" />
That is it. As you can see this solution utilises the benefits of nuxt-link but also allows us to selectively update only parts of our page that need updates (we could update the entire page this way as well if needed).
In case if you needed to trigger the logic from mounted or initial load in general, then you could use computed property and :key to your div container, right inside the <template> of your page.
Add :key to the div:
<template>
<div :key="$store.getters.getComponentUpdates.item"></div>
</template>
Create computed property:
computed: {
updateItemPage() {
//run your initial instructions here as if you were doing it in mounted then return the getter
this.initialLoadMethod()
return this.$store.getters.getComponentUpdates.item
}
}
The final touch, which is not crucial but can be implemented in order to reset the state property:
export const mutations = {
updateComponent(state, payload) {
return state.componentUpdates[payload.update] >= 10
? state.componentUpdates[payload.update] = 0
: state.componentUpdates[payload.update]++
}
}
I have a single page VueJS app with a number of data variables I want to encode into the URL.
As an example if my route configuration is (I'm not sure if the syntax is correct):
routes: [
{
path: '/:foo/:bar/:oof/:rab',
component: App
}
And the Component is:
<script>
export default {
name: "App",
data: function() {
return {
foo: 1,
bar: 2,
oof: 3,
rab: 4
}
}
}
Then the URL would be http://www.example.com/#/1/2/3/4
And if foo is changed to 9999 the URL would automatically update: http://www.example.com/#/9999/2/3/4
It would also respond to the user changing the URL, or opening the app with a different URL by loading the URL values into the data.
I thought this would be relatively straightforward but after a Google I'm utterly confused by the correct way of going about this.
Any help/ examples/ solutions greatly appreciated.
Whatever you use to change the values would need to trigger a route push. For example
methods: {
changeFoo (newFoo) {
// you can set foo but it probably won't matter because you're navigating away
this.foo = newFoo
this.$router.push(`/${newFoo}/${this.bar}/${this.oof}/${this.rab}`)
}
See https://router.vuejs.org/guide/essentials/navigation.html
It might be easier if you name your route, eg
routes: [{
name: 'home',
path: '/:foo/:bar/:oof/:rab',
component: App
}]
then you could use something like
this.$router.push({name: 'home', params: this.$data})
It seems that there are two things you're trying to achieve, but I'm not sure from your example which comes first in your ideal order of operations:
Getting the values from your URL
This can be achieved through this.$route.params, which will be an object containing the values you're looking for.
Setting the URL based on your foo, bar, oof, rab variables
You can use this.$router.push() to do this: vue-router docs
I've got a VueJs front end that fetches some data from an API. The app uses vue-router.
The data fetched for one component is similar to the following:
{
name: ...,
email: ...,
order: {
data: {
line_items: [
{
quantity: ...
}
]
}
}
}
The component is instantiated with a data object called info:
data () {
return {
info: {}
}
}
In the beforeRouteEnter hook, the data is fetched by a vue-resource http.get and info is set to the body of the result like this:
vm.info = result.body
When the component renders, the following errors are produced:
TypeError: undefined is not an object (evaluating _vm.order.data.line_items')
In the template, the data is referenced in curly braces as per usual, however, if I just reference info in the template like this:
{{ info }}
it will output all of the data and not complain at all.
What is the correct way to assign a deeply nested data object?
If you are finding #saurabh answer is not working then you may need to check how you are assigning the new values to your object.
Firstly is the data being accidiently set as a string? hence {{ info }} working (or appearing to). May be worth using response.json() to set the data.
If thats not it then the error may be produced as the data you have set is not reactive. As you are assigning a nested object you may need to use different methods to make it reactive, i.e
Vue.set(vm.someObject, 'b', 2)
or
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
check out: https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
because your response is an object you may want to break out your data into corresponding params, i.e.
data () {
return {
info: {
name: '',
email: '',
order: {},
},
}
}
then you can assign name & email as you expected (info.email = ...).
For info.order you'd use Vue.set:
Vue.set(this.info, 'order', result.body.order)
The actual issue here is a life cycle one. The route guard beforeRouteEnter is called after the component is created so the error is thrown because the data isn’t there when the component tries to access it.
You have to use condition rendering here, which you can easily do with help of Vue directive v-if. It may give error if the data is not populated and you try to access it, so v-if will render that part of HTML only when data is present.
You need to do something like following:
<div v-if="info.order">
<span>
{{ info.order }}
</span>
</div>
In my scenario, I had to use one Vue.set that wrapped an Object.assign:
I'm trying to set state.workouts[state.workoutDate].isDone in a Vuex mutation
toggleWorkout(state, isDone) {
Vue.set(
state.workouts,
state.workoutDate,
Object.assign({}, state.workouts[state.workoutDate], { isDone: isDone })
);
},
Force update object setting a new object with same content
<button #click="my.object.nested.variable = 2; my = Object.assign({}, my);">
or
this.my.object.nested.variable = 2;
this.my = Object.assign({}, this.my);