VueJS push a route with params data - javascript

I am very new to VueJS. How can I get the deviceId in Device component in vuejs. The deviceId in h1 tag was not printed out in the Device component page.
goForward() {
console.log("go forward");
this.$router.push({ name: "Device", params: { deviceId: "Air-conditioning" } });
},
<template>
<div class="about">
<h1>This is the device page {{ deviceId }}</h1>
</div>
</template>
<script>
export default {
name: "Device",
props: ["deviceId"],
data() {
return {};
},
};
</script>
const routes = [
{
path: '/device',
name: 'Device',
component: Device,
},
]

In order to receive your params as props you need to add the props: true option in the route object.
const routes = [
{
path: "/device",
name: "Device",
component: 'Device',
props: true
}
];
https://router.vuejs.org/guide/essentials/passing-props.html#boolean-mode

It's also worth noting that you can improve the URL scheme a bit by adding a route parameter like so:
{
path: "/device/:deviceId",
...
}
Thus, the URL in the address bar will look cleaner:
https://www.example.com/device/Air-conditioning

Related

How can I access props passed in Vue router, inside a Vue component?

I have a route defined below:
{
path: 'fit-details',
name: 'fit-details',
component: Fitment,
props: true
},
I'm passing props through my route with data from the state:
this.$router.push({ path: 'fit-details', query: {
year: this.query.year,
make: this.query.make,
model: this.query.model
}
})
I see the route getting properly defined when passed: www.placeholder.com?year=2008&make=Acura&model=MDX
And finally inside my receiving component I have the props instantiate:
export default {
props: ['year', 'make', 'model'],
},
However I can't access this data in the component for some reason. Any help would be much appreciated, Im honestly not the best when it comes to Vue router stuff
No need to define that props inside the visited component, you could use this.$route.query.year and this.$route.query.make or you could do something like :
const {'year', 'make', 'model'}=this.$route.query
or :
{
path: 'fit-details',
name: 'fit-details',
component: Fitment,
props:(route) => ({ year: route.query.year,make:route.query.make,model:route.query.model })
},
in Fitment component :
export default {
props: ['year', 'make', 'model'],
},

How to get Vuejs links to switch between components?

To simplify the demo I'm using fake/pointless API)
I have the routers
const routes = [
{ path: '/', component: Menu},
{path: '/books', component: Index,
props: route => ({ api: `https://jsonplaceholder.typicode.com/posts` })
},
{path: '/videos',component: Index,
props: route => ({ api: `https://jsonplaceholder.typicode.com/todos` })
}
]
const router = new VueRouter({ routes })
const app = new Vue({ router }).$mount('#app')
The Menu component
var Menu = Vue.component('Menu', {
template: `<ul>
<li><router-link to="/">home</router-link></li>
<li><router-link :to="{ name: 'videos'}">videos</router-link></li>
<li><router-link :to="{ name: 'books'}">books</router-link></li>
</ul>`})
This is the problem, it does not switch from videos to books.
Finally the Index component
var BookComponent = {
props: {
api: { type: String }
},
data: function () {
return {
items: null,
}
},
mounted: function(){
this.getItems()
},
methods: {
async getItems() {
fetch(this.api).then(res => res.json())
.then(res =>{
this.items = res;
this.loading = false
})
},
},
template: `
<div class="home">
<p v-for="post in items" :key="post.id">{{post.title}}</p>
</div>
`
}
var Home = Vue.component('Home', BookComponent)
var Index = {
props: {
api: {type: String,},
filterBy: {type: String},
},
template: `
<div>
<Menu />
<div class="mainApp" style="margin-top: 40px!important">
<Home :api=api />
</div>
</div>`,
component: { Menu, Home },
};
It doesn't work on jsfiddle but here's the code anyway jsfiddle
You're calling named routes but you haven't defined any name in your routes so either use the path
<li><router-link to="/videos">videos</router-link></li>
<li><router-link to="/books">books</router-link></li>
or name your routes
const routes = [
{ path: '/', component: Menu},
{path: '/books', component: Index, name: 'books',
props: route => ({ api: `https://jsonplaceholder.typicode.com/posts` })
},
{path: '/videos',component: Index, name: 'videos',
props: route => ({ api: `https://jsonplaceholder.typicode.com/todos` })
}
]
To fix navigation - replace objects in router-link attribute to with to='/videos' and to='/books'
To fix render error, add v-if to post items loop, like this:
<div class="home">
<p v-if="items" v-for="post in items" :key="post.id">{{post.title}}</p>
</div>
Here is official docs for vue-router
It seems that I just needed to watch for the route changes and trigger the fetch method again.
watch: {
// call again the method if the route changes
'$route': 'getItems'
}

Vue: display response from form submit on another page

I have a <form> in vue. I send that form to server, get a JSON response, print it to console. It works fine.
However I need to take that JSON response and display it on another page. For instance, I have two .vue files: GetAnimal.vue that has the form and retrieves the animal data from an API and a DisplayAnimal.vue that displays animal's data. I need to direct the response animal data from GetAnimal.vue to DisplayAnimal.vue.
GetAnimal.vue:
<template>
<form v-on:submit.prevent="getAnimal()">
<textarea v-model = "animal"
name = "animal" type="animal" id = "animal"
placeholder="Enter your animal here">
</textarea>
<button class = "custom-button dark-button"
type="submit">Get animal</button>
</form>
</template>
<script>
import axios from 'axios';
export default {
name: 'App',
data: function() {
return {
info: '',
animal: ''
}
},
methods: {
getAnimal: function() {
axios
.get('http://localhost:8088/animalsapi?animal=' + this.animal)
.then(response => (this.info = response.data));
console.log(this.info);
}
}
}
</script>
response:
retrieves a JSON with animal data, say like this:
{
"fur-color": "yellow",
"population": 51000,
"isExtinct": false,
"isDomesticated": true
}
and I now want to give that JSON to a DisplayAnimal.vue at /viewanimal endpoint:
DisplayAnimal.vue:
<template>
<div>
<p>Animal name: {{animal}}}</p>
<p>Fur color: {{furColor}}</p>
<p>Population: {{population}}</p>
<p>Is extinct: {{isExtinct}}</p>
<p>Is domesticated: {{isDomesticated}}</p>
</div>
</template>
How would I do that? I know I can redirect via this.$router.push({ path });, but I've only used it for navigation, while here JSON response needs to be passed. Is this even a correct / good practice way of approaching this?
EDIT:
I tried this:
in GetAnimal.vue I added this data:
data: function() {
return {
animal: {
name: 'Cat',
furColor: 'red',
population: '10000',
isExtinct: false,
isDomesticated: true
}
and in DisplayAnimal.vue this:
<script>
export default {
props: {
animal: {
name: {
type: String
},
furColor: {
type: String
},
population: String,
isExtinct: String,
isDomesticated: String
}
}
}
</script>
and in GetAnimal.vue I added this:
methods: {
animals: function() {
alert("animals");
this.$router.push({name: 'viewanimal',
query: {animal: JSON.stringify(this.animal)}});
},
to try to display that test animal using the display component. However it just didn't work - I get an empty page.
Using Vuex, you can solve this easily
Working example on netlify
https://m-animalfarm.netlify.app/
code on github
https://github.com/manojkmishra/animalfarm
GetAnimal.vue ( I have disabled axios call for testing and hardcoded info)
<template>
<form v-on:submit.prevent="getAnimal()">
<textarea v-model = "animal" name = "animal" type="animal" id = "animal"
placeholder="Enter your animal here">
</textarea>
<button class = "custom-button dark-button"
type="submit">Get animal</button>
</form>
</template>
<script>
import axios from 'axios';
export default
{
name: 'App',
data: function() { return { info: '', animal: '' } },
methods: {
getAnimal: function() {
// axios
// .get('http://localhost:8088/animalsapi?animal=' + this.animal)
// .then(response => (this.info = response.data),
this.info={"fur-color": "yellow","population": 51000,"isExtinct":
false,"isDomesticated": true },
this.$store.dispatch('storeAnimals', this.info)
//);
}
}
}
</script>
DisplayAnimal.vue
<template>
<div>
<p>Animal name: {{stateAnimal.animal}}</p>
<p>Fur color: {{stateAnimal.furColor}}</p>
<p>Population: {{stateAnimal.population}}</p>
<p>Is extinct: {{stateAnimal.isExtinct}}</p>
<p>Is domesticated: {{stateAnimal.isDomesticated}}</p>
</div>
</template>
<script>
import {mapState, mapGetters} from 'vuex';
export default {
computed:{ ...mapState({ stateAnimal:state => state.modulename.stateAnimal }),
},
}
</script>
modulename.js ( store module)
export default
{
state: {stateAnimal:null, },
getters:{ },
mutations:
{ ['STORE_ANIMALS'] (state, payload)
{ state.stateAnimal = payload;
console.log('state=',state)
},
},
actions:
{ storeAnimals: ({commit}, data) =>
{ console.log('storeanim-data-',data);
commit( 'STORE_ANIMALS', data );
},
}
}
Index.js (for vuex store), you can disable persistedstate as its for saving state if page is refreshed
import Vue from 'vue'
import Vuex from 'vuex'
import modulename from './modules/modulename'
import createPersistedState from "vuex-persistedstate";
Vue.use(Vuex)
export default new Vuex.Store({
plugins: [createPersistedState({ storage: sessionStorage })],
state: { },
mutations: { },
actions: { },
modules: { modulename }
})
State is available/shared for all the components
well first of all create a second folder call it services and create service.js for you axios call- good practice and cleaner code overall.
second use vuex. this kind of data is best used with vuex.
As far as I understand GetAnimal.vue is the parent component and you wish to display it in the child component DisplayAnimal.vue.
If so and you wish to see if this works just use props.
you can also send that same information or any other information for the child back to the parent using an $emit().
STRONGLY recommended to use vuex in order to manage the state
Vue.component('product',{
props:{
message:{
type:String,
required:true,
default:'Hi.'
}
},
template:`<div>{{message}}</div>`,
data(){...}
})
//html in the other component you axios call is in this component //<product meesage="hello"></product>
I would pass the animal name/id as a route param to the display page and have that component responsible for fetching and displaying the relevant animal data. This avoids the situation where a user could visit the display page directly via the URL and see an incomplete page.
In situations where you want to share local state between pages, as others have pointed out you'd probably want to use Vuex.
EDIT:
I'm adding some code to my answer as requested by the OP.
Routes:
const routes = [
{ path: "/", component: SearchAnimals },
{ path: "/viewanimal/:name", component: DisplayAnimal, name: "displayAnimal" }
];
DisplayAnimal.vue:
<template>
<div>
<p>Animal name: {{animal.name}}</p>
<p>Fur color: {{animal.furColor}}</p>
<p>Population: {{animal.population}}</p>
<p>Is extinct: {{animal.isExtinct}}</p>
<p>Is domesticated: {{animal.isDomesticated}}</p>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "DisplayAnimal",
data: () => ({
animal: {}
}),
methods: {
fetchAnimal(name) {
axios
.get(`http://localhost:8088/animalsapi?animal=${name}`)
.then(response => {
this.animal = response.data;
});
}
},
created() {
this.fetchAnimal(this.$route.params.name);
}
};
</script>
SearchAnimals.vue:
<template>
<form v-on:submit.prevent="onSubmit">
<textarea
v-model="animal"
name="animal"
type="animal"
id="animal"
placeholder="Enter your animal here"
></textarea>
<button type="submit">Get animal</button>
</form>
</template>
<script>
export default {
name: "SearchAnimal",
data: () => ({
animal: ""
}),
methods: {
onSubmit() {
this.$router.push({
name: "displayAnimal",
params: { name: this.animal }
});
}
}
};
</script>
Obviously this is a bare-bones example, so doesn't contain any error handling etc., but it should get you up and running.

How to expose a component's data to child components in a router context? [duplicate]

Suppose I have a Vue.js component like this:
var Bar = Vue.extend({
props: ['my-props'],
template: '<p>This is bar!</p>'
});
And I want to use it when some route in vue-router is matched like this:
router.map({
'/bar': {
component: Bar
}
});
Normally in order to pass 'myProps' to the component I would do something like this:
Vue.component('my-bar', Bar);
and in the html:
<my-bar my-props="hello!"></my-bar>
In this case, the router is drawing automatically the component in the router-view element when the route is matched.
My question is, in this case, how can I pass the the props to the component?
<router-view :some-value-to-pass="localValue"></router-view>
and in your components just add prop:
props: {
someValueToPass: String
},
vue-router will match prop in component
sadly non of the prev solutions actually answers the question so here is a one from quora
basically the part that docs doesn't explain well is
When props is set to true, the route.params will be set as the component props.
so what you actually need when sending the prop through the route is to assign it to the params key ex
this.$router.push({
name: 'Home',
params: {
theme: 'dark'
}
})
so the full example would be
// component
const User = {
props: ['test'],
template: '<div>User {{ test }}</div>'
}
// router
new VueRouter({
routes: [
{
path: '/user',
component: User,
name: 'user',
props: true
}
]
})
// usage
this.$router.push({
name: 'user',
params: {
test: 'hello there' // or anything you want
}
})
In the router,
const router = new VueRouter({
routes: [
{ path: 'YOUR__PATH', component: Bar, props: { authorName: 'Robert' } }
]
})
And inside the <Bar /> component,
var Bar = Vue.extend({
props: ['authorName'],
template: '<p>Hey, {{ authorName }}</p>'
});
This question is old, so I'm not sure if Function mode existed at the time the question was asked, but it can be used to pass only the correct props. It is only called on route changes, but all the Vue reactivity rules apply with whatever you pass if it is reactive data already.
// Router config:
components: {
default: Component0,
named1: Component1
},
props: {
default: (route) => {
// <router-view :prop1="$store.importantCollection"/>
return {
prop1: store.importantCollection
}
},
named1: function(route) {
// <router-view :anotherProp="$store.otherData"/>
return {
anotherProp: store.otherData
}
},
}
Note that this only works if your prop function is scoped so it can see the data you want to pass. The route argument provides no references to the Vue instance, Vuex, or VueRouter. Also, the named1 example demonstrates that this is not bound to any instance either. This appears to be by design, so the state is only defined by the URL. Because of these issues, it could be better to use named views that receive the correct props in the markup and let the router toggle them.
// Router config:
components:
{
default: Component0,
named1: Component1
}
<!-- Markup -->
<router-view name="default" :prop1="$store.importantCollection"/>
<router-view name="named1" :anotherProp="$store.otherData"/>
With this approach, your markup declares the intent of which views are possible and sets them up, but the router decides which ones to activate.
const User = {
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, props: true }
// for routes with named views, you have to define the props option for each named view:
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
})
Object mode
const router = new VueRouter({
routes: [
{ path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }
]
})
That is the official answer.
link
Use:
this.$route.MY_PROP
to get a route prop

Passing dynamic data to Vue params/routes

I'm fairly new to Vue and am struggling to get something to work. Not entirely sure if this is possible but I'll ask and we'll see what the Stack Overflow gods have to conjure.
I wanted to know if it is possible to store component data/props for lots of IDs inside the data () portion of the default export.
So the {{$route.params.id}} manages to capture the id from the end of the url, but I want to know whether I can then have the View return other data stored somewhere in a component. So essentially is it possible for me to store data for let's say 5 different IDs all inside the Project.Vue file, or do I simply have to make 5 different files (Project1.Vue, Project2.Vue etc) and then set them all up as separate routes?
So far I have tried adding addings bits to the data () element such as
data () {
return {
msg: 'Projects',
id: [{ 1: 'hi'}, {2: 'hey'}],
two: 'project two',
three: 'project three',
}
}
And then referencing id inside the <template> but that didn't work as it simply returned the whole object. I also tried decoupling as mentioned here: https://router.vuejs.org/en/essentials/passing-props.html but had no joy with that either.
Apologies for my poor explanation but I hope somebody can help to shed light on whether this is possible. Code used below:
index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '#/components/Home'
import Contact from '#/components/Contact'
import About from '#/components/About'
import Projects from '#/components/Projects'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/contact',
name: 'Contact',
component: Contact
},
{
path: '/about',
name: 'About',
component: About
},
{
path: '/projects',
name: 'Projects',
component: Projects
},
{
path: '/projects/:id',
name: 'Projects',
component: Projects,
props: {default: true}
},
]
})
Projects.Vue
<template>
<div id="projects">
<h1>{{ header }} {{ $route.params.id }}</h1>
{{id}}
</div>
</template>
<script>
export default {
name: 'Projects',
watch: {
'$route'(to, from) {
// react to route changes...
}
},
data () {
return {
header: 'Projects',
}
}
}
</script>
<style scoped>
</style>
I have managed to figure it out.
In order to dynamically pass data based on the id passed in to the url, you need to create a data object and then inside of the of the <template>, you can pass in the object you have created but then pass the $route.params.id inside of the square brackets. However, it's worth noting that because the object created inside of your data() will use the zero index, it is worth adding a -1 inside of the template. See the below code to understand how it all works:
<template>
<div id="projects">
<h1>{{ msg }} {{ projects[$route.params.id - 1] }}</h1>
</div>
</template>
<script>
export default {
name: 'Projects',
watch: {
'$route'(to, from) {
// react to route changes...
}
},
data () {
return {
projects: [
{ id: 1,
name: 'Project numero uno'
},
{ id: 2,
name: 'Project secundo'
},
{ id: 3,
name: 'Project three'
},
]
}
}
}
</script>
<style scoped>
</style>

Categories