VueJs route match params only from list (Validate params value) - vue.js

The route should be resolved only for the given params list (Validate params)
e.g. valid names ["Sam", "Alice"]
//route
{
path: "/customers/:names"
}
// expectation
path = /customers/Sam => matched
path = /customers/Alice => matched
path = /customers/XYZ => Not matched
path = /customers/ABC => Not matched
How this can be achieved ??

You can use router guards to validate the route.
Use either Global guards or In-component guards. Choose as per your requirements.
// define route with valid names
{
path: "/customers/:name",
meta: {
validNames: ["Sam", "Alice"]
}
}
// Global Gaurd
router.beforeEach((to, from, next) => {
if (to.meta?.validNames) {
if (!to.meta.validNames.includes(to.params.name)) {
return ‘/error’
}
// else valid name
}
next()
})
Answering from mobile. Excuse me if there’s any typos

Supposing the following router configuration
/src/router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import CustomersName from "../views/CustomersName.vue";
Vue.use(VueRouter);
const routes = [
{
path: "/customers/:name",
name: "customers-name",
component: CustomersName,
},
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes,
});
export default router;
And the following view
/src/views/CustomersName.vue
<template>
<div>
<p>Current route's customer name: {{ $route.params.name }}</p>
<p>
Do we have either Sam or Alice currently?
{{ ["Sam", "Alice"].includes($route.params.name) }}
</p>
<router-link
class="block"
:to="{ name: 'customers-name', params: { name: 'Sam' } }"
>
visit Sam
</router-link>
<router-link
class="block"
:to="{ name: 'customers-name', params: { name: 'Bob' } }"
>
visit Bob
</router-link>
<router-link
class="block"
:to="{ name: 'customers-name', params: { name: 'Alice' } }"
>
visit Alice
</router-link>
<router-link
class="block"
:to="{ name: 'customers-name', params: { name: 'alice' } }"
>
visit small alice
</router-link>
</div>
</template>
<style scoped>
.block {
display: block;
}
</style>
We will have the following result
Here is a video on how it actually looks
PS: here is a working github repo (if needed).

Related

Optional route params lost when access child route components Vue 2

I got a problem with optional route params, that route param (id) is lost when I access the child component
this is my route config on the router
{
path: "route/:id?",
component: () => import("*****"),
props: true,
children: [
{
path: "/",
redirect: { name: "*****" }
},
{
path: "information",
component: () => import("****")
},
]
},
this is my route expected companies/1/description etc
is there something wrong with my code?
this is how I push the router
it shows success like that companies/1/information but if i go through to another child route.. this param is lost like companies/direction
If I understand it correctly you expect the <router-link> placed inside your Company component to somehow "inherit" route params from the current route automatically.
Unfortunately this is not how it works with optional params - it would work with non-optional params but optional params must be passed explicitly...
:to="{ name: link.routeName, params: { id: $route.params.id } }"
const companies = Vue.component('companies', {
template: `
<div id="app">
<router-link to="/companies/1">Company 1</router-link>
<router-link to="/companies/2">Company 2</router-link>
<router-view></router-view>
</div>
`
})
const company = Vue.component('company', {
props: ['id'],
template: `
<div id="app">
<h4> {{ id }} </h4>
<h4> {{ $route.fullPath }} </h4>
<router-link :to="{ name: 'adminBusinessProfileInformation', params: { id: $route.params.id } }">Information</router-link>
<router-link :to="{ name: 'adminBusinessProfileDescription', params: { id: $route.params.id } }">Description</router-link>
<router-view></router-view>
</div>
`
})
const child = Vue.component('child', {
template: `
<div>
Child component
</div>
`
})
const router = new VueRouter({
mode: 'history',
routes: [{
path: '/',
redirect: 'companies'
},
{
name: 'companies',
path: '/companies',
component: companies
},
{
path: '/companies/:id',
component: company,
props: true,
children: [{
path: "/",
redirect: {
name: "adminBusinessProfileInformation"
}
},
{
path: "information",
component: child,
name: "adminBusinessProfileInformation"
},
{
path: "description",
component: child,
name: "adminBusinessProfileDescription"
}
]
}
]
})
new Vue({
el: '#app',
router,
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<router-link to="/companies/1">Company 1</router-link>
<router-link to="/companies/2">Company 2</router-link>
<router-view></router-view>
</div>

how to use router-link custom navigation instead of `to` prop

<router-link to="/" tag="a" :title="title">
<span class="icon icon-home i-large" />
<span class="class-2">Name</span>
</router-link>
This is what I have...
As you can see , I am using to prop. But I don't want to use it. Whenever someone clicks on this, i want to execute a function and use programatic navigation.
How is this possible? the structure and htmls that I have shouldn't change and it still should work as expected.
Something like this you mean?
<a #click="functionThatExecutesMyCode">
<span class="icon icon-home i-large" />
<span class="class-2">Name</span>
</a>
functionThatExecutesMyCode() {
this.$router.push({ to: 'newRoute'})
}
Else you should use the navigation guards: https://router.vuejs.org/guide/advanced/navigation-guards.html
I don't think it's possible to change :to props to add a function, because it is predefined as only accept a string in its docs. https://router.vuejs.org/api/#to
However, I suggest another way to implement what you want, you can add the logic in beforeEach hook. For example
router.beforeEach( (to, from, next) => {
// implement your logic here, for example if no internet, go to error page
if (!navigator.onLine && to.name !== "NetworkError") {
next({ name: "NetworkError" });
return false;
}
next();
}
For more info, look at their docs: https://router.vuejs.org/api/#router-beforeeach
It depends on what you exactly want.
There are easier solutions, like:
const Root = {
template: '<div>Root</div>'
}
const Route1 = {
template: '<div>Route1</div>'
}
const routes = [{
path: '/',
name: 'root',
component: Root
},
{
path: '/1',
name: 'route1',
component: Route1
}
]
const router = new VueRouter({
routes // short for `routes: routes`
})
new Vue({
el: "#app",
router,
data: {
selected: 'root',
options: ['root', 'route1']
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<select v-model="selected">
<option v-for="(option, i) in options">
{{ option }}
</option>
</select>
<router-view></router-view>
<router-link :to="{ name: selected }">{{ selected }}</router-link>
</div>
In this solution I used a named route, and the "name" can be changed by the select input.
The next solution is to incorporate a function:
const Root = {
template: '<div>Root</div>'
}
const Route1 = {
template: '<div>Route1</div>'
}
const routes = [{
path: '/',
name: 'root',
component: Root
},
{
path: '/1',
name: 'route1',
component: Route1
}
]
const router = new VueRouter({
routes // short for `routes: routes`
})
new Vue({
el: "#app",
router,
data: {
selected: 'root',
options: ['root', 'route1']
},
methods: {
changeRouteName() {
return this.selected
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<select v-model="selected">
<option v-for="(option, i) in options">
{{ option }}
</option>
</select>
<router-view></router-view>
<router-link :to="{ name: changeRouteName() }">{{ selected }}</router-link>
</div>
By adding a method to resolve the name of the component, it's possible to build ANY logic on the to of the <router-link. You could also use path instead of name of course - I just like named components.
It does not remove the click event from the to prop, but you can do your logic before returning the name it's "waiting" for.

vue-router Route with name 'ROUTENAME' does not exist in vuejs

I have some routes which are newly added. the sidebar is dynamically created based on links added to the routes.
I am able to print the route name in plain text but when assigned to the vue-route it simple gives localhost:8080 so where am i going wrong.
configroutes file:
const routes = [
{
path: 'create_schedule',
name: 'activate.create_schedule',
meta: {
_routeName: 'activate_create_schedule',
sectionName: 'Create Schedule'
},
component: createSchedule,
},
]
Main Routes File
import ConfigureRoutes from './configureRoutes.js';
const routes = [
...ConfigureRoutes,
];
export default routes;
export const getActivateConfigRoutes = function () {
return routes;
};
dashboard Component file
data() {
const configRoutes = getActivateConfigRoutes();
const sidebarRoutes = [
{
name: '/',
meta: {
sectionName: 'CONFIGURE'
},
redirect: {
name: 'activate.create_schedule'
},
children: [
...configRoutes
]
},
];
return {
sidebarRoutes
};
}
}
</script>
aside bar:
<aside class="menu">
<ul class="menu-list --campaign-sidebar">
<li class="main-section-menu" v-for="(sidebarRoute, index) in sidebarRoutes" :key="sidebarRoute.id">
<router-link :to="{ name: sidebarRoute.name, params: { campaign_id: currentCampaign.id }}" class="sidebar-link" active-class="is-active">
{{ sidebarRoute.meta.sectionName }}
</router-link>
<ul class="sub-menu-list" v-if="sidebarRoute.children.length > 0">
<li v-for="childRoute in sidebarRoute.children" :key="childRoute.id">
<router-link :to="{ name: childRoute.name , params: { campaign_id: currentCampaign.id }}" class="sidebar-sub-link" active-class="is-active-submenu router-link-active">
{{ childRoute.meta.sectionName }} {{ childRoute.name }}
</router-link></li>
</ul>
<span class="base" v-if="((sidebarRoutes.length - 1) === index)"></span>
</li>
</ul>
</aside>
you can see what when I try to print childRoute.name, it gives me the name and so that data is passed properly to the loop. then what is the issue here ? can someone help on the same ?
[vue-router] Route with name 'activate.create_schedule' does not exist vue-router.esm.js:16

Vue router dynamic link and children reload page - not load correctly component

I add to my routes file path with children:
path: '/warehouse/:id',
name: 'ShowWarehouse',
component: ShowWarehouse,
children: [{
path: 'edit',
name: 'EditWarehouse',
component: EditWarehouse
}
]
Now in component ShowWarehouse I have:
<div v-if="!changeEdit">
<div v-if="warehouseData">
<div>Name: {{ warehouseData.warehouse.name }}</div>
<div>
<router-link
:to="{ name: 'EditWarehouse', params: {id: warehouseData.warehouse.id }}"
>Edit</router-link>
</div>
</div>
</div>
<router-view v-else></router-view>
When the user click edit button I need load component EditWarehouse, but component ShowWarehouse must be disappear, and if user back (without /edit) disappear componet EditWarehouse and load component ShowWarehouse. I write method in watch:
watch: {
$route() {
if (this.$route.path == '/warehouse/' + id_get_from_API + '/edit') {
this.changeEdit = true;
} else {
this.changeEdit = false;
}
}
},
The problem is when the user is at mydomain.com/warehouse/23/edit and click reload page (F5), then Vue loads component ShowWarehouse instead of loading EditWarehouse.
I using mode: 'history'.
Problem:
From the Vue.JS website: "Vue does provide a more generic way to observe and react to data changes on a Vue instance: watch properties." When you refresh the page the watch() method will not be executed because it is a new Vue instance and no data has changed on the Vue instance yet. You should probably use a different pattern to determine which component to show. (https://v2.vuejs.org/v2/guide/computed.html#Computed-vs-Watched-Property)
Solution:
I suggest making the EditWarehouse a sibling route to ShowWarehouse, and make EditWarehouse its own component (you already have this). Your router-link in the ShowWarehouse component can stay the same.
Code Snippet:
const ShowWarehouse = {
template: `<div><h1>ShowWarehouse</h1> <div v-if="warehouseData">
<div>Name: {{ warehouseData.warehouse.name }}</div>
<div>ID: {{ $route.params.id }}</div>
<div>
<router-link :to="{ name: 'EditWarehouse'}">Edit</router-link>
</div>
</div></div>`,
computed: {
warehouseData: function() {
let data;
let id = this.$route.params.id;
if (id) {
data = {
warehouse: {
name: 'Some Warehouse Name',
id: id
}
}
}
return data;
}
}
};
const EditWarehouse = {
template: "<h1>EditWarehouse [{{ $route.params.id }}]</h1>"
}
const router = new VueRouter({
routes: [{
path: '/warehouse/:id',
name: 'ShowWarehouse',
component: ShowWarehouse
},
{
path: '/warehouse/:id/edit',
name: 'EditWarehouse',
component: EditWarehouse
}
]
});
new Vue({
el: '#app',
router
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<p>
<router-link :to="{ name: 'ShowWarehouse', params: { id: 123 }}">Go to Warehouse 123</router-link>
</p>
<router-view/>
</div>
Here is a jsfiddle with the same code:
https://jsfiddle.net/austinwasinger/oruswb3a/39/

how to programmatically return to Vue cli's pre-made Home.vue

I'm using Vue CLI 3 and it makes a few routes. One is Home.vue. In my program I am trying to programmaticaly go to different pages. I added the routes I need in router.js but kept the already created routes for Home.vue and About.vue. It works fine until I get to 'Home' and get a warning: [vue-router] Route with name 'Home' does not exist.'
Here is the code:
<template>
<div class='secondItem'>
<h4 v-for="item in menuItems"
#click="bindMe(item)" v-bind:class="{'active':(item === current)}">{{item}}</h4>
</div>
</template>
<script>
export default {
name: 'Header',
data() {
return {
current: '',
menuItems: ['Home', 'About', 'Portfolio', 'Contact'],
}
},
methods: {
bindMe(item) {
this.current = item;
this.$router.push({
path: item
})
}
}
}
<script>
Are you using named routes? In that case you need to use name instead of path:
this.$router.push({
name: item
})
Also, your example can be simplified quite a lot. Try this:
<template>
<div class="secondItem">
<router-link :to="{ name: item }" tag="h4" active-class="active" v-for="item in menuItems" v-bind:key="item">{{item}}</router-link>
</div>
</template>
<script>
export default {
name: 'Header',
data() {
return {
menuItems: ['Home', 'About', 'Portfolio', 'Contact']
}
}
}
<script>