I am trying to pass properties to a component through a router-link on Vuejs, but the component is not recieving them properly. I have a main menu and a secondary menu, which is where I want to pass the properties, when a main menu button is clicked:
const Sidebar = {
name:'sidebar',
template:`
<div>
Sidemenu
<router-link v-for="route in routes" v-key="route" :to="route">{{route}}</router-link>
</div>`,
props: {
routes:{
type: Array,
required: true,
default: function(){return []}
}
}
}
const AppMenu = {
name:'app-menu',
template:`
<div>
<router-link :to="{name:'project', params:{routes: projectMenus}}">Project</router-link>
<router-link :to="{name:'assets', params:{routes: assetsMenus}}">Assets</router-link>
</div>`,
data: function(){
return{
projectMenus: ['overview', 'settings'],
assetsMenus: ['landscapes', 'characters']
}
}
}
const App = {
template:`
<div>
<app-menu/>
<router-view name="sideview"/>
<router-view name="sectionview"/>
</div>`,
components:{AppMenu}
};
const Routes= [
{path: '/', name:'home', redirect: 'project'},
{path:'/project', name:'project', components:{sideview:Sidebar}, props:{sideview:true}},
{path:'/assets', name:'assets', components:{sideview:Sidebar}, props:{sideview:true}}
]
The Sidebar component is rendering, because I can see "Sidemenu" on the page, but the console throws [Vue warn]: Missing required prop: "routes" on Sidebar, so my submenu links are not shown. I've searched on the docs, and many similar issues in many forums, but I can't find what I'm doing wrong.
When you make props an object in the vue routes definitions, it will replace the components props. You are setting them as {sideview: true} which overrides all props in your Sidebar component.
At least that is my understanding from https://router.vuejs.org/guide/essentials/passing-props.html#object-mode
Related
I have some views/components; Home, ScrapeResults, and Search. To help y'all follow what is going on, here are some snippets of code that are relevant to my issue.
Snippet of App.vue
<template>
<v-app-bar>
<Search #selected_card="scrape"/>
</v-app-bar>
<v-content>
<v-container fluid style="width: 80%;">
<router-view :card="card"></router-view> //card prop is in ScrapeResults.vue
</v-container>
</v-content>
</template>
<script>
data() {
return {
card: {}
}
}
methods: {
scrape(card) { //card parameter value is from $emit event from Search
if(this.$router.currentRoute.name != 'scrape-results') {
this.$router.push({name: 'scrape-results', params: { card: card } });
}
else {
this.card = card;
console.log(this.card)
}
}
}
</script>
Snippet of Home.vue
<template>
<div id="home">
<h1>Home</h1>
<Search id="search" #selected_card="scrape"/>
</div>
</template>
<script>
methods: {
scrape(card) { //card parameter value is from $emit event from Search
this.$router.push({ name: 'scrape-results', params: { card: card } });
}
}
</script>
Snippet of ScrapeResults:
<template>
<div id="home">
<h1>Scrape Results</h1>
<p> {{card.name}} - {{card.set_name}} </p>
<v-img :src="card.img_url"></v-img>
</div>
</template>
<script>
...... //irrelevant stuff
props: {
card: Object
},
watch: {
card() {
console.log(this.card)
}
}
</script>
Paths within the app:
/ (Home)
/scrape-results (ScrapeResults)
So how the app work is the user will search for a card (Object) and select from a rendered list. Once the user selects a card from the rendered list, then the user is redirected to the Scrape Results view. All of that works fine when done from Home.vue.
My issue: If the user accessed Scrape Results from Home.vue, and while still on Scrape Results view, if the user were to search for another card via the Search component that is mounted (in the app bar) in App.vue, then the card prop in ScrapeResults.vue doesn't update. The weird thing is that if I manually navigate to Scrape Results by entering /scrape-results in the address bar, search for a card via the Search component in the app bar, then the card prop updates. The card prop will only update if I manually access /scrape-results and then search for a card.
I know all of that sounds confusing, so here's a clip I recorded to that demonstrates what my issue is. Link: https://www.youtube.com/watch?v=aO9qSTa9CCk&feature=youtu.be&hd=1
EDIT: Route definition below
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '#/views/Home'
import ScrapeResults from '#/views/ScrapeResults'
Vue.use(VueRouter);
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/scrape-results',
name: 'scrape-results',
component: ScrapeResults,
props: true
}
]
});
export default router;
So, instead of trying to make passing a prop to router-view work, I just ended up changing the ScrapeResults path in my router.js to /scrape-results/:card_set/:card_name; original was just /scrape-results. I then just pushed extra params in $router.push
this.$router.push({name: 'scrape-results', params: { card: card, card_set: card.set_name, card_name: card.name } });
My router file
import DomainAction from './components/domainaction/DomainAction.vue'
...
{ path: '/domainaction' , component: DomainAction },
...
router link File
...
<router-link to="/domainaction" tag="li" class="list-group-item "class-active="active" exact > Domain Action</router-link>
...
From another routes going to the domainaction Route like this
...
itemAction(action,data){
if(action=='Suspend'){
this.$router.push('/domainaction')
}
}
...
My Actual DomainAction component
<template>
.......
</template>
<script>
export default {
props:['data'],
data(){
return{
.........
</script>
I want to pass data props from itemAction function .
How do i achieve this ?
I'm new to vue js .Sorry if my question is not very complete.
Well if you just need to pass a property (a value) to the component, you just need to use data passing via the router's props: https://router.vuejs.org/guide/essentials/passing-props.html#function- mode.
And receive using this.$router within the component.
Alternatively you can use the Vuex for data passing.
https://vuex.vuejs.org/
So that you can make a communication between components outside this form that was informed, both components have to be parent and child, ie, 1 calls the other inside it, so yes you can pass the values, otherwise it should be used, or the data path via route, or via vuex which is the vue status manager.
There is also the following possibility, as requested in this question.
Passing props to Vue.js components instantiated by Vue-router
Note that sosmii is right about using a Vuex to share data across components.
But if you're looking into pass soma data as params using routes, you have to change a little bit how you're defining the components routes. Using a routers params you would be able to pass props, then you can push the route and add params. See example below.
And related question:
Passing props with programmatic navigation Vue.js
const DomainActionA = {
props: ['dataProp'],
template: '<div>A data: {{dataProp}}</div>'
}
const DomainActionB = {
props: ['dataProp'],
template: '<div>B data: {{dataProp}}</div>'
}
const routes = [
{
path: '/DomainActionA/:dataProp',
name: 'domainA',
component: DomainActionA,
props: true },
{
path: '/DomainActionB/:dataProp',
name: 'domainB',
component: DomainActionB,
props: true
}
]
const router = new VueRouter({
routes
})
const app = new Vue({
router,
methods: {
goToA() {
this.$router.push({name: 'domainA', params: {dataProp: "blah"}})
},
goToB() {
this.$router.push({name: 'domainB', params: {dataProp: "bleh"}})
}
}
}).$mount('#app')
<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">
<h1>Hello Router!</h1>
<div>
<button #click="goToA()">Go A with params: { data: "blah" }</button>
<button #click="goToB()">Go B with params: { data: "bleh" }</button>
</div>
<div>
<h2>router view</h2>
<router-view></router-view>
</div>
</div>
you should use vuex
props are designed to pass variables from a parent component to child components,
so it is unusual to use it when you want to share data between pages.
an example of right usage of prop:
parent.vue
<child-component :data="data">
<child-component :data="anotherData">
so, if you want to share variables between pages, use vuex (store pattern) instead.
similar question:
https://stackoverflow.com/a/40955110/10440108
I am new to Vue and I'm trying to learn how to apply Vue router. I got normal routing to work no problem. When I try to use dynamic routing everything continued to work fine. When I tried to pass props to dynamic routes however my code breaks.
I'm using these cdn versions of Vue and Vue router which are the versions suggested by the official websites:
- https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js
- https://unpkg.com/vue-router#2.0.0/dist/vue-router.js
The HTML
<div id="app">
<h1>{{ message }}</h1>
<nav>
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
<router-link to="/user/John">Name</router-link>
</nav>
<!-- route outlet -->
<!-- component matched by route will render here -->
<router-view></router-view>
</div>
The JS
// Route components
const Home = { template: '<div>Home</div>' };
const About = { template: '<div>About</div>' };
const User = { props: ['name'], template: `
<div>
<div>User {{ name }}</div>
<button #click="checkName">Check</button>
</div>`,
methods: {
checkName: function() {
console.log('Params name: ' + this.$route.params.name);
console.log('Props name: ' + this.name);
}
}
};
// Routes for router
const routes = [
{ path: '/', component: Home },
{ path: '/home', redirect: Home },
{ path: '/about', component: About },
{ path: '/user/:name', component: User, props: true }
];
const router = new VueRouter({
routes: routes
});
const app = new Vue({
el: '#app',
data: {
message: 'VueJS Router'
},
router: router
});
When I navigate to the 'Name' page the static text renders fine but the dynamic text fails to load. I added a button that will log the value of name from props and from $route.params to the user. When clicked it turns out that the value of name in props is undefined but the value of name from params is correct. Why is this?
If you're sticking with VueRouter#2.0.0 or lower :
The name that you expect is not passed as a prop but as a route param, cf. Dynamic route matching.
You need to access it from your template as follow : $route.params.name.
You could also use a computed value instead.
If you can update VueRouter
As stated in another answer, and according to the release note of VueRouter#2.2.0, passing down route params as props has only been introduced in v2.2.0, you were using v2.0.0. If you would like to use props you would need to update to (at least) v2.2.0.
CDN link provided on the Vue Router installation page was outdated. Instead of:
https://unpkg.com/vue-router#2.0.0/dist/vue-router.js
use:
https://unpkg.com/vue-router#3.0.1/dist/vue-router.js
Answer provided here:
https://forum.vuejs.org/t/why-is-component-props-undefined-vue-router/34929/5
This is a part of a Vue-routes application, in one of the routes I have two properties, bga and bgb that will be used to change the colors of divs. I do not know how to declare them correctly, how do I do that?
I get this messages in the Chrome console:
vue.js:597 [Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.
warn # vue.js:597
vue.js:597 [Vue warn]: Property or method "bga", "bgb" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
ColorPage.js
const ColorPage = {
props:
['bga', 'bgb'],
data: {
bga: {
backgroundColor: ''
},
bgb: {
backgroundColor: ''
}
},
template: `
<div id="middle">
<label id="colorLabel"><h2>'Change Colors By Typing Their Names:'</h2></label>
</br>
<input type="text" class="colorInput" v-on:input="bga.backgroundColor = $event.target.value" placeholder="here...">
</br>
<input type="text" class="colorInput" v-on:input="bgb.backgroundColor = $event.target.value" placeholder="... and here!">
</div>
`
,
};
export default ColorPage
This should be used to change the colors of the "container" div and the "top" div:
Index.html
<div id="container" v-bind:style="bga">
<div class="top" v-bind:style="bgb">
<div id="app">
<h1 id="vueHead">Vue routing</h1>
<h2 class="menu">
<router-link to="/">Color</router-link>
<router-link to="/main">Main</router-link>
<router-link to="/settings">Settings</router-link>
<router-link to="/vue">Vue</router-link>
</h2>
</div>
</div>
<router-view></router-view>
</div>
Vue routes is place in index.js:
import MainPage from '../components/mainPage.js'
import ColorPage from '../components/colorPage.js'
const routes = [
{path: '/', component: ColorPage},
{path: '/main', component: MainPage},
];
const router = new VueRouter({
routes // short for `routes: routes`
});
var vm = new Vue({
el: '#container',
router,
});
When you're creating a component there's slight differences between some of the typical syntax with Vue. For instance Data Must Be a Function.
..
data: {
reactive: true,
}
..
In a standard Vue instance the above is perfectly fine. However when you create a component the data property needs to be a function that returns an object:
..
data() {
return { reactive: true }
}
..
Additionally props are available to you just the same as any other property in data.
Question
I have an issue where created event hook keep being called. Is there any sort of hook-once for this kind of even, like "first-created" or "first-mounted"? If possible, no junk code to attach for each component.
POI
Here is an example that shows how the created hook keeps being called if you switch from page "foo" to "bar" (you will need to inspect the page to see the log).
JSFiddle
HTML
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- use router-link component for navigation. -->
<!-- specify the link by passing the `to` prop. -->
<!-- `<router-link>` will be rendered as an `<a>` tag by default -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<!-- route outlet -->
<!-- component matched by the route will render here -->
<router-view></router-view>
</div>
JS
const Foo = { template: '<div>foo</div>', created: function() { console.log('foo created'); } };
const Bar = { template: '<div>bar</div>', created: function() { console.log('bar created'); } };
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
];
const router = new VueRouter({
routes // short for `routes: routes`
});
const app = new Vue({
router
}).$mount('#app');
Consider wrapping your <router-view></router-view> with <keep-alive></keep-alive>, so that when your route changes, the component for the routes isn't recreated: the created hook will only be called once when it is created initially.
<router-view>
{({ Component }) => (
<keep-alive>
<Component />
</keep-alive>
)}
</router-view>