I am using Vue.js 2.0, and I have this exact same code in 2 differents files, so I decided to build only one component and redirect the 2 routes on it, then I just need to pass the ID to the route, this way my 2 components can display differents resultats.
Note: the only thing that changes is the ID dsgh151rhj12t1j5j I would like that each route can send it own ID to my PageContentfulView component
EDIT: I just want to pass data from Route to the component
<template>
<div>
<div class="container">
<hp-row>
<hp-column>
<component v-for="component in content.column" :data="component" :key="component.id" :is="getComponentIdentifier(component.is)"></component>
</hp-column>
</hp-row>
</div>
</div>
</template>
<script>
import ModularView from '#/views/ModularView'
export default {
name: 'PageContentfulView',
mixins: [ModularView],
created () {
this.fetch('blocks/dsgh151rhj12t1j5j')
},
}
</script>
Routes:
{
path: '/satisfaction-guarantee',
name: 'SatisfactionView',
component: load('PageContentfulView'),
},
{
path: '/about-us',
name: 'AboutUsView',
component: load('PageContentfulView'),
},
'props' can solve your problem.
<template>
<div>
<div class="container">
<hp-row>
<hp-column>
<component v-for="component in content.column" :data="component" :key="component.id" :is="getComponentIdentifier(component.is)"></component>
</hp-column>
</hp-row>
</div>
</div>
</template>
<script>
import ModularView from '#/views/ModularView'
export default {
name: 'PageContentfulView',
mixins: [ModularView],
props: ['id'],
created () {
this.fetch('blocks/' + this.id)
},
}
</script>
route
{
path: '/satisfaction-guarantee',
name: 'SatisfactionView',
component: load('PageContentfulView'),
props: { id: 'dsgh151rhj12t1j5j' },
},
{
path: '/about-us',
name: 'AboutUsView',
component: load('PageContentfulView'),
props: { id: 'blablablabla' },
},
You can do it using Dynamic Route Matching. You just need to include the parameter on the definition of the route, like below:
{
path: '/satisfaction-guarantee/:ID',
name: 'SatisfactionView',
component: load('PageContentfulView'),
}
Inside you component, to access the ID, you just need to use the this.$route.params.ID.
Passing props to route component allows an object mode.
Example from the documentation:
const router = new VueRouter({
routes: [
{ path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }
]
})
Route meta fields
Also you always can use the meta property to pass extra data (like a requireAuth flag)
const router = new VueRouter({
routes: [
{ path: '/test', component: TestComponent, meta: { someBoolean: false } }
]
})
And you can access it within your component
created() {
let meta = this.$route.meta;
}
Set the props in your route to true and place /:id at the end of your path
const router = new VueRouter({
routes: [
{ path: '/promotion/from-newsletter/:id',
component: Promotion,
props: true
}
]
})
You can now extract the param id of your route from the props in the corresponding component
<template>
<div>
<div class="container">
<hp-row>
<hp-column>
<component v-for="component in content.column" :data="component" :key="component.id" :is="getComponentIdentifier(component.is)"></component>
</hp-column>
</hp-row>
</div>
</div>
</template>
<script>
import ModularView from '#/views/ModularView'
export default {
name: 'PageContentfulView',
mixins: [ModularView],
props: ['id'],
created () {
this.fetch('blocks/'+id)
},
}
</script>
Related
I'm trying to pass props from one page to another with a redirect. Here's the code for the redirect:
<router-link :to="{ name: 'shipment', params: { editedItems: getSelected() } }">
Edit Amount
</router-link>
And here's the original code for the route in router:
{
path: "/inventory/shipment",
name: "shipment",
props: { screen: "shipment" },
component: Inventory,
},
As can be seen, I want to also pass a set variable, being screen, all the time. The route, shipment, can be called with router-link or through other methods. I know by setting props: true on the route it allows me to get the props sent via the redirect, but it doesn't allow me to pass the screen prop if router-link isn't called. What I'm looking for is the best of both worlds, being able to send both props.
Side note: I know I can easily get the prop on the page by looking at the url, but learning how to do a method like this will be helpful in the future when I don't have an easy out.
With Vue router you can access both information (props and params), just use a different pattern to get it:
const MainView = {
template: `<div>MAIN VIEW: click on TO INVENTORY to see data passed</div>`
}
const Inventory = {
props: ['screen'],
computed: {
routeParams() {
return Object.entries(this.$route.params).map(e => {
return `${e[0]}: ${e[1]}`
}).join(', ')
}
},
template: `
<div>
INVENTORY<br />
prop: {{ screen }}<br />
editedItems: {{ $route.params.editedItems }}<br />
all params: {{ routeParams }}
</div>
`
}
const router = new VueRouter({
routes: [{
path: '/',
name: "main",
component: MainView
}, {
path: '/inventory/shipment',
name: "shipment",
props: {
screen: "shipment"
},
component: Inventory
}]
})
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="{ name: 'shipment', params: { editedItems: 'someitem' } }">TO INVENTORY</router-link>
<router-link :to="{ name: 'main' }">TO MAIN</router-link>
<router-view></router-view>
</div>
Is there a way to mount multiple components on a single vue instance.
I have my admin dashboard and a forum page and i don't want header and navigation to show up on these pages.
Here's what I've tried:
import App from "./App.vue";
import Admin from "./Admin.vue";
import Forum from "./Forum.vue";
const app = new Vue({
router,
store,
components: {
App, Admin, Forum
}
}).$mount("#app");
Then in my App.vue, I have other child components
<template>
<div>
<div class="general-page">
<AppHeader></AppHeader>
<transition name="fade">
<router-view></router-view>
</transition>
<AppFooter></AppFooter>
</div>
</div>
</template>
<script>
import AppHeader from "./components/AppHeader";
import Login from "./components/Login.vue";
import Register from "./components/Register.vue";
import AppFooter from "./components/AppFooter.vue";
export default {
components: {
AppHeader,
Login,
Register,
AppFooter
}
};
</script>
In Forum.vue
<template>
<div>
<div class="forum-page">
<ForumHeader></ForumHeader>
<transition name="fade">
<router-view></router-view>
</transition>
<ForumFooter></ForumFooter>
</div>
</div>
</template>
<script>
import ForumHeader from "./components/ForumHeader";
import ForumFooter from "./components/ForumFooter.vue";
export default {
components: {
ForumHeader,
ForumFooter
}
};
</script>
Admin.vue
<template>
<div>
<div class="admin-page">
<AdminHeader></AdminHeader>
<transition name="fade">
<router-view></router-view>
</transition>
<AdminFooter></AdminFooter>
</div>
</div>
</template>
<script>
import AdminHeader from "./components/AdminHeader";
import AdminFooter from "./components/AdminFooter.vue";
export default {
components: {
AdminHeader,
AdminFooter
}
};
</script>
Routes for Forum and Admin
{
path: '/admin',
name: 'Admin',
component: Admin,
meta: {
requiresAuth: true
},
children: [
{
path: '',
name: 'Profile',
component: Profile
},
{
path: 'uploads',
name: 'Uploads',
component: Uploads,
meta: {
requiresCreatorAccess: true
}
},
{
path: 'add-post',
name: 'AddPost',
component: AddPost,
meta: {
requiresCreatorAccess: true
}
}
]
},
{
path: '/forum',
name: 'Forum',
component: Forum,
children: [
{
path: '',
name: 'Channel',
component: Channel
},
{
path: 'threads',
name: 'Threads',
component: Threads
},
{
path: 'topic',
name: 'Topic',
component: Topic
}
]
},
How do I dynamically go to each route and mount each component on el: #app ?
Without changing any routing and template structure, you could use CSS to hide the app header, footer.
Another option may be to v-if the app header,footer to not render when on those routes using something like $router.currentRoute for matching.
CSS
/*
Assuming app header and footer have an id attribute
Change to your needs
*/
#app-header,
#app-footer {
display: none;
}
v-if on currentRoute
We have to do a few of things here.
Create a data variable (showMe: true)
Create a method (evaluateShowMe)
Create a watcher for the route ('$route'()) Be aware of the quotes!
Note: Feel free to rename the variable and function to suit your needs.
We need to watch $route because this is outside of a <router-view/> so we need to do this dynamically so the variable performs the evaluator function every time the route changes.
App.vue:
<template>
<div>
<div class="general-page">
<AppHeader
v-if="showMe"
></AppHeader>
<transition name="fade">
<router-view></router-view>
</transition>
<AppFooter
v-if="showMe"
></AppFooter>
</div>
</div>
</template>
<script>
import AppHeader from "./components/AppHeader";
import Login from "./components/Login.vue";
import Register from "./components/Register.vue";
import AppFooter from "./components/AppFooter.vue";
export default {
components: {
AppHeader,
Login,
Register,
AppFooter
},
data() {
return {
showMe: true
}
},
methods: {
evaluateShowMe() {
// Get the substring of the path between first and second slash
// This will allow to include any child pathing
// NOTE: In my test the first index ([0]) was empty so used one ([1]) for the `filter`
const entryPath = this.$router.currentRoute.path.split('/').filter((x,i) => i === 1);
// We want to exclude the following paths i.e. hide when on these
// There should only be one item in the array so we extract with `[0]`
return (entryPath[0] !== 'admin' || entryPath[0] !== 'forum');
}
},
watch: {
'$route'() {
this.showMe = this.evaluateShowMe();
}
}
};
</script>
I'm new in VueJs, trying to set up a web application with Vue-route, and want to update the <header> style when user navigates to a specific URL, whether using "URL bar" directly or "navigation bar". In this case, we have a parent component that contains height_status data and some <router-links> on template.
I've done the "navigation bar" part with $emit technique and it works well but then I've tried to use it on created lifecycle hook in order to update the header whenever the /home route is created but event listener will not reach the parent_component.
How can I solve this? Is there a better way to do that?
Please see the code below:
Parent_component.vue
<template>
<div id="app">
<router-link to="/home" #height_size_ctrl="change_height">Home</router-link>
<router-link to="/about">About us</router-link>
<router-link to="/contact">Contact us</router-link>
<header :class="height_status ? 'head-h-s' : 'head-h-m'"></header>
<router-view/>
</div>
</template>
<script>
export default {
name: "Parent_component"
},
data() {
return {
height_status: false
}
},
methods: {
change_height(h) {
this.height_status = h
}
}
}
</script>
router.js
Vue.use(Router)
export default new Router({
routes: [
{
path: '/home',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
component: about
},
{
path: '/contact',
name: 'contact',
component: contact
}
]
})
home.vue
<template>
<h1>hello</h1>
</template>
<script>
export default {
name: 'home',
created: function(){
return this.$emit("height_size_ctrl", true)
}
}
</script>
You could also change the router:
router.js
{
path: '/home',
name: 'home',
component: Home,
meta: {
headerClass: 'head-h-s'
}
}
In your component
Parent_component.vue
computed: {
headerClass() {
return this.$route.meta.headerClass
}
}
Now headerClass is available in the template.
<header :class="headerClass"></header>
why don't you try class binding on route or route name something like:
<div :class="{'height_status': this.$route == '/home'}">Header</div>
or
<div :class="{'height_status': this.$route.name == 'Home'}">Header</div>
As #kcsujeet said, class binding is the good way we can do this. In this case we need to look at the condition this.$route.path. if value is equal to the /home select 'head-h-m, otherwise select .head-h-s.
<header class="head-sec" :class=" this.$route.path == '/home' ? 'head-h-m' : 'head-h-s'">
Also we're able to access other route defined properties using this.$route. I suggest take a look at the router.js file.
routes: [
{
path: '/home',
name: 'home',
component: Home
}
How can I pass an image as prop in a vue-router tag ?
I have :
<router-link :to="{path: '/details', query: {
name: 'item',
//...
}}">
</routerlink
while in my "details" component I have :
<template>
<img :src="url">
</template>
<script>
export default {
name:'child-img',
props:['url'],
data() {
return {
}
}
}
</script>
So it's a case of passing props to your route which you have to set up in your router.
const router = new VueRouter({
routes: [
{ path: '/details/:url', component: Details, props: true },
// ...
]
})
then when you use your route:
<router-link to="`/details/${url}`">Details</router-link>
In the above url is the dynamic element you would be passing to it. If it comes from a v-for loop it would be item.url or whatever you are v-for ing.
OR if you name your route you can pass a param like this:
const router = new VueRouter({
routes: [
{ path: '/details/:url', name: 'Details', component: Details, props: true },
// ...
]
})
then use it like this:
<router-link :to="{ name: 'Details', params: { url } }">
Details
</router-link>
You can read more here
I have the following router config:
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'notselected',
component: PackageUnselected
},
{
path: '/package/:id',
children: [
{ path: 'meta', name: 'packageMeta', component: ViewPackageMeta },
{ path: 'readme', name: 'packageReadme', component: PackageReadme },
{ path: 'docs', name: 'packageDocs', component: PackageDocs },
{
path: 'playground',
name: 'packagePlayground',
component: PackagePlayground
}
]
},
{
path: '/about',
name: 'about',
component: About
},
{
path: '*',
redirect: '/'
}
]
});
And when I'm at the root route it correctly identifies the route name as notselected. When I route to any of the "/package/[id]" routes though it continues to load the PackageUnselected component instead of the appropriate route (aka, ViewPackageMeta, PackageDocs, etc.).
Now at the point in the DOM where I want the route to insert the route's component I have the following template:
<v-tab-item v-for="item in tabs" :id="'tab-item-' + item" :key="item" exact>
item: {{item}}
<router-view :selectedPackage="selected"></router-view>
</v-tab-item>
And because I have installed vuex-router-sync it's easy to see the route state at any given time. So when clicking on the route that should load PackageDocs:
But the component view window of vue-devtools looks like this:
the highlighted area shows that NO component has been loaded into the tabs. I then tried adding a component to the definition of the parent route /package/:id:
{
path: '/package/:id',
component: Packages,
children: [
{ path: 'meta', name: 'packageMeta', component: ViewPackageMeta },
{ path: 'readme', name: 'packageReadme', component: PackageReadme },
{ path: 'docs', name: 'packageDocs', component: PackageDocs },
{
path: 'playground',
name: 'packagePlayground',
component: PackagePlayground
}
]
},
I then had to create the world simplest component for Packages:
<template>
<view-router-view></view-router-view>
</template>
This results in the following:
Hmmm. Can't figure out what to do next. Anyone have any pointers?
When I route to any of the "/package/[id]" routes though it continues
to load the PackageUnselected component instead of the appropriate
route (aka, ViewPackageMeta, PackageDocs, etc.).
That is the correct behavior of the vue-router.
Children can only be loaded when URL paths are:
/package/[id]/meta
/package/[id]/readme
/package/[id]/playground
/package/[id]/docs
Parent path may not have component defined if you have configured redirect option and your user, who opens /package/[id] will be redirected to your default path (could be anything).
Lets move to the next part of your question...
<v-tab-item v-for="item in tabs" :id="'tab-item-' + item" :key="item" exact>
item: {{item}}
<router-view :selectedPackage="selected"></router-view>
</v-tab-item>
You don't need to create here 4 different <router-view> tags, you just need one where all your children components will display html code.
<v-tab-item v-for="item in tabs" :id="'tab-item-' + item" :key="item" exact></v-tab-item>
<router-view></router-view>
Now you will have only one router-view and it's the default one. When user clicks on any of your tabs you just need to this.$router.push a new path on #click-event in Packages component. That's it.
I have created a simple example (codepen) to demonstrate how this task can be solved:
Vue.use(VueRouter);
// Components
let MetaPackages = {
mounted() { console.log('Mounted MetaPackages...'); },
template: `<div>MetaPackages...</div>`,
};
let DocsPackages = {
mounted() { console.log('Mounted DocsPackages...'); },
template: `<div>DocsPackages...</div>`,
};
let ReadmePackages = {
mounted() { console.log('Mounted ReadmePackages...'); },
template: `<div>ReadmePackages...</div>`,
};
let Packages = {
mounted() { console.log('Mounted Packages... ' + this.$route.path); },
template: '<div>Packages (parent) screen...<br/><router-view></router-view></div>',
};
// Router
const router = new VueRouter({
mode: 'hash',
routes: [
{
path: "/packages/:id",
component: Packages,
children: [
{path:"meta", component: MetaPackages},
{path:"docs", component: DocsPackages},
{path:"readme", component: ReadmePackages}
]
}
]
});
// Vue instance
const vm = new Vue({
el: '#app',
router,
components: {Packages, MetaPackages, DocsPackages, ReadmePackages}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.2/vue-router.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<router-link to="/packages/100/meta">Meta</router-link>
<router-link to="/packages/100/docs">Docs</router-link>
<router-link to="/packages/100/readme">Readme</router-link>
<hr/>
<router-view></router-view>
</div>