Passing props to nested route - vue.js

I have the following routes in my VueJS app:
const routes = [
{
path: '/',
component: PlacesList
},
{
name: 'place',
path: '/places/:name',
component: CurrentWeather,
children: [
{
name: 'alerts',
path: 'alerts',
component: ForecastAlerts
},
{
name: 'forecast',
path: 'forecast',
component: ForecastTimeline
}
]
}
];
ForecastTimeline receives props passed from CurrentWeather:
export default {
name: 'ForecastTimeline',
props: ['forecastData'],
components: {
ForecastDay
}
}
When I navigate to /places/:name/forecast from /places/:name everything works well. However, when I try to reach /places/:name/forecast directly I get a Cannot read property 'summary' of undefined error. This occurs because forecastData is fetched asynchronously within the CurrentWeather component. What is the proper way to handle asynchronous properties passed to a nested route?

Have you tried not displaying the subroutes components while fetching the data ?
Something like :
export default {
name: 'CurrentWeather',
data(){
return {
loading: true
}
},
created(){
this.fetchForecastData().then(() => {
this.loading = false;
});
},
methods: {
fetchForecastData() {
return fetch('http://..');
}
}
}
In CurrentWeather template :
<router-view v-if="!loading"></router-view>

Related

TypeError: a.then is not a function while compiling in production

I'm trying to compile my vue app in production with npm run build (which is vite build).
After that I try to serve my app on my server with the /dist folder and everything seems to be working perfectly, I'm able to send fetch request, click on various links etc.
Unfortunately, after logging in and when I should be redirected, I'm getting the error
TypeError: a.then is not a function while compiling in production
and
Uncaught (in promise) TypeError: a.then is not a function"
Everything just works perfectly fine while I'm in dev mode, it's just not working in production.
It seems to be linked to the router
This is the code for my Router :
const state = reactive({
token: localStorage.getItem("token"),
userAdmin: false,
userRestaurateur: false,
userDeliverer: false
});
if (state.token) {
const user = JSON.parse(atob(state.token.split('.')[1]))
state.userAdmin = Object.values(user.roles).includes('ROLE_ADMIN');
state.userRestaurateur = Object.values(user.roles).includes('ROLE_RESTAURANT');
state.userDeliverer = Object.values(user.roles).includes('ROLE_DELIVERER');
}
const router = createRouter({
history: createWebHistory('/'),
routes: [
{
path: '/',
name: 'home',
component: function () {
if (state.token && state.userAdmin) {
return Users
} else if (state.token && state.userRestaurateur) {
return HomeRestaurateur
}else if (state.token && state.userDeliverer) {
return Commands
}else {
return Home
}
}
},
{
path: "/login",
name: "login",
component: Login,
},
{
path: "/forgot-password",
name: "forgot_password",
component: ForgotPassword,
},
{
path: "/reset-password/:token",
name: "reset_password_token",
component: ResetPassword,
},
{
path: "/register",
name: "register",
component: Register,
},
{
path: "/profile",
name: "editProfile",
component: editProfile,
},
{
path: "/Restaurant/:id/Menu",
name: "Meals",
component: Meals,
},
{
path: "/admin/users",
name: "admin_users",
component: function () {
if (state.userAdmin) {
return Users
} else {
return Error403
}
}
},
{
path: "/admin/restaurants",
name: "admin_restaurants",
component: function () {
if (state.userAdmin) {
return Restaurants
} else {
return Error403
}
}
},
{
path: "/admin/restaurants_request",
name: "admin_restaurants_request",
component: function () {
if (state.userAdmin) {
return RestaurantsRequest
} else {
return Error403
}
}
},
{
path: "/restaurants/new",
name: "create_restaurants",
component: CreateRestaurant,
},
{
path: "/admin/reports",
name: "admin_reports",
component: function () {
if (state.userAdmin) {
return Reports
} else {
return Error403
}
}
},
{
path: "/orders",
name: "orders",
component: Commands,
},
{
path: "/:pathMatch(.*)*",
name: "not_found",
component: Error404,
}
],
});
I tried checking if other methods were working correctly, tried to change server, nothing just seems to work.

Vue I18n multi language

I'm doing multi-language support with vue js, everything works fine, but when I change the language, the data in the data
menuItem name does not change.
Vuei18n
<template v-slot:MenuItem>
<MenuItems v-for="(Item,Index) in menuItem"
:key="Index"
:items="Item"
:depth="Index"
>
<router-link :to="Item.path">{{Item.name}}</router-link>
</MenuItems>
</template>
export default {
name: "Nav",
data() {
return {
menuItem: [
{
name: this.$t('navbar.home'),
path: '',
},
{
name: this.$t('navbar.gallery'),
path: 'gallery',
},
{
name: this.$t('navbar.contact'),
path: 'contact',
},
],
}
}
}
data() is only called once when creating the component, and it's not intended to be reactive.
(So basically when your component is being created, it gets the your current translation as initial values)
To make a property reactive on $t(), you should use computed var instead:
export default {
name: "Nav",
data() {
// exclude from here
return {};
},
computed: {
menuItem() {
return [
{
name: this.$t("navbar.home"),
path: "",
},
{
name: this.$t("navbar.gallery"),
path: "gallery",
},
{
name: this.$t("navbar.contact"),
path: "contact",
},
];
},
},
};

Push route to parent component inside a function (Vue)

I feel like I'm missing something very obvious but I can't figure it out. Please help!
I have the following routes defined:
const routes = [
{
path: '/',
name: 'Login',
component: () => import('../views/Login.vue'),
meta: {
authRedirect: true
}
},
{
path: '/companies',
name: 'Companies',
component: () => import('../views/Companies.vue'),
meta: {
requiresAuth: true
}
},
{
path: '/companies/:id',
name: 'Company',
component: () => import('../views/Company.vue'),
meta: {
requiresAuth: true
}
},
{
path: '*',
name: '404',
component: () => import('../views/404.vue')
}
]
Then I have the following in my component:
export default {
name: 'Company',
data() {
return {
company: {}
}
},
methods: {
getCompanyDetails: function() {
let self = this
axios.get('/api/companies/' + this.$route.params.id).then(function(response) {
self.company = response.data
}).catch(function() {
self.$router.push('companies')
})
}
},
created() {
this.getCompanyDetails()
}
}
Essentially everything is working if the API returns data, but inside the catch function I'm trying to push the route back to /companies. But it's redirecting to /companies/companies. How do I redirect it to the correct route?
Did you tried $router.push('/companies') (with a / in the path) ?
Also, you can use $router.push({ name: 'Companies' }) if you want to make it more clear, it will match the name defined in your routes.

vue.js pass data to route using beforeRouteUpdate

vue.js I am trying to pass data from route to app.vue ,
I am relying on beforeRouteUpdate
what I am trying to do is
routes: [
{
path: '/dashboard',
name: 'dashboard',
component: function () { return import( './views/dashboard.vue') },
beforeRouteUpdate: (to, from, next) => { document.title = 'dashboard'; next(); }
},
{
path: '/home',
name: 'home',
component: function () { return import( './views/home.vue') },
beforeRouteUpdate: (to, from, next) => { document.title = 'home'; next(); }
},
document.title is working put it's not dynmaic in the app.vue ,
what i mean is when i choose anther route document.title does not change in the app.vue
in app.vue
data(){
return {
getselected : document.title,
}
},
mounted() {
console.log('getselected - '+ this.getselected );
},
As far as I know, the function beforeRouteUpdate is a component hook. Then, you can't use this inside your router. But you can pass a param to your route, via query.
Your router:
routes: [
{
path: '/dashboard',
name: 'dashboard',
query: {title: 'dashboard'},
component: function () { return import( './views/dashboard.vue') },
},
{
path: '/home',
name: 'home',
query: {title: 'home'},
component: function () { return import( './views/home.vue') },
},
]
Your component:
data(){
return {
documentTitle: '',
}
},
mounted() {
this.documentTitle = this.$route.query.title;
},
In other way, you can use your path name inside your component. You even don't need to declare query in your router.
data(){
return {
documentTitle: '',
}
},
mounted() {
this.documentTitle = this.$route.path.name;
},

Missing param for named route: Expected "x" to be defined

Whether I do this
Vue.router.push({ path: '/beats/catalog/1' })
or this
Vue.router.push({ name: 'BeatsCatalog', params: { page: 1 } })
I get the same result:
[vue-router] missing param for named route "BeatsCatalog": Expected "page" to be defined.
Router:
{
path: '/beats',
components: {
navbar: Navbar,
default: { template: `<router-view/>` }
},
children: [{
name: 'BeatsCatalog',
path: 'catalog/:page',
components: {
default: () => import('#/views/BeatsCatalog')
},
props: { default: true }
},
{
path: 'upload',
name: 'BeatsUpload',
components: {
default: () => import('#/views/BeatsUpload')
}
},
],
meta: { requiresAuth: true }
}
What's causing the issue? I see nothing wrong with my setup, I'm doing everything like in the documentation.
Thanks.
#Giacoma,
In your data property on the component BeatsCatalog the page is undefined when initally loaded. Hence you get the error.
So to solve this wrap your router-link in v-if.
Reference for the same error with better explaination is here:
https://github.com/vuejs/vue-router/issues/986