How to set and pass a JSON prop through routes - vue.js

In vue.js
route.js
[{path: "/path", name: "acomp_name", component: PathComp, props: { abc: {} }}]
comp.vue
<script>
...omitted_for_brevity,
methods: {
changeRoute(json_sample){
this.$router.push({name: "acomp_name", params: { abc: json_sample })
}
}
</script>
Is there a way I can set the props which is an object to return json sample which is another object, like this
that is can I set the value of props of the router in a push
if indeed it is not supported in vue-router4 . what approach has been used or is being used to do this?

I am grateful to God Almighty for helping me to create an intuitive and reliable answer,
N<>B solution works with vue3 and vue-router4x
in the comp.vue
somewhere inside the template I have a nested or child component
so
<template>
<p>...</p>
...omitted_for_brevity
<router-view :prop_from_router.js="this.state.a_key_I_want_to_use"/>
</template>
still in comp.vue
<script>
...omitted_for_brevity
setup(){
const s = reactive({})
return {s}
},
methods: {
changeRoute(t)
this.state.a_key_i_want_to_use = t
}
}
</script>

Related

Can props be accessed in beforecreated of vue?

In the vue docs, the part of "beforeCreate", I read the following:
Called immediately when the instance is initialized, after props resolution, before processing other options such as data() or computed.
Does this means that I can get props in beforeCreate hooks? if so, how can I get it?
In my child component, I try like this to get the message passed by parent component, but failed.
export default {
name: 'Child',
props: ['message'],
beforeCreate() {
console.log(this.message)
}
}
Please check the following snippet, looks like your code is fine:
const app = Vue.createApp({
data() {
return {
msg: 'aaa',
};
},
})
app.component('Child', {
template: `<div>{{ message }}</div>`,
props: ['message'],
beforeCreate() {
console.log('before create: ', this.message)
}
})
app.mount('#demo')
<script src="https://unpkg.com/vue#3.2.29/dist/vue.global.prod.js"></script>
<div id="demo">
<child :message="msg"></child>
</div>

Passing data from route to router-view body

I have a single page application with the structure below.
|- App.vue
|- + Views
| |- Page.vue
|- + Components
| |- Slider.vue
EDIT 1: Solution thanks to #gengar.value
I solved the issue by passing params from Page.vue with
methods: {
emitIndex: function (index) {
this.$router.push({
name: "visualization",
params: { imgCat: "visualization", imgIndex: index },
});
},
}
App.vue containing the router-view container that is routing the Page.vue
Slider.vue is a component of App.vue
I want to pass index of clicked image and whole images data from Page.vue to App.vue then to Slider.vue in order to achieve decoupling Slider from Page for reusability purposes.
How can I pass user selected index from Page.vue too App.vue
I have tried to use, params, props and emit but failed.
Sample Page.vue
<template>
<div v-for="(item, index) in 3" :key="index"></div>
</template>
<script>
export default ({
data() {
return {
urls: ['url1', 'url2', 'url3']
}
}
})
</script>
Thanks in advance
EDIT 1: Solution thanks to #gengar.value
Problem solved by pushing params to router via Page.vue and listening it from Slider.vue as follows:
Page.vue
methods: {
passIndex: function (index) {
this.$router.push({
name: "visualization",
params: { imgCat: "visualization", imgIndex: index },
});
},
}
Slider.vue
watch: {
"$route.params.imgCat": function (val) {
this.state = val;
},
"$route.params.imgIndex": function (newVal) {
if (newVal != -1) this.imgState = newVal;
this.$router.push({ params: { imgIndex: -1 } });
}
My solution is a little bit complicated, but quite native since I only used Props and Emit.
You want to pass value between brother components, so you could simply try below:
App.vue
<template>
<div>
<Page :data="data" #syncData="syncData" />
<Slider :data="data" />
</div>
<template>
<script>
import Page from './Views/Page.vue'
import Slider from './Components/Slider.vue'
export default ({
components: {
Page,
Silder
},
data() {
return {
data: [] // init data in the parent component
}
},
methods: {
syncData(updatedImages) {
this.data = updatedImages
}
}
})
</script>
Page.vue
<template>
<div></div>
<template>
<script>
export default ({
props: {
data: { type: Array, default: () => [] }
},
methods: {
onSelectImage(images) {
this.$emit('syncData', images) // update selected data to App.vue
}
}
})
</script>
Slider.vue
<template>
<div></div>
<template>
<script>
export default ({
props: {
data: { type: Array, default: () => [] }
},
watch: {
data: {
handler(val) {
// when Page.vue emits updated data to App.vue,
// App.vue will pass data to Slider.vue
// and you could receive the updated data 'val' here
},
deep: true
}
}
})
</script>
Update: Sorry I misunderstood before. If you are using vue-router components and assigned different paths (eg. '/page' and '/slider'), you can use
this.$router.push({ path: '/path', query: selectedImage })
in Page.vue and get url query in Slider.vue.
Alternative methods could be using Cookie.js or sessionStorage (not pretty tho). Also you could try Vuex if the specific condition suits you.

vue faile to load mount component

I have to do some simple thing.
I have to generate different select options to generate different data.
So I create component and I passing array with values, but only in theory xD
When I go to road i got error cold:
app.js:37990 [Vue warn]: Failed to mount component: template or render
function not defined.
found in
---> <SelectComponent> at resources/js/components/SelectComponent.vue
<ExampleComponent> at resources/js/components/ExampleComponent.vue
<Root>
My component is simple for test do,
<h1> test connection </h1>
<script>
export default {
name: 'SelectComponent',
data () {
return {}
}
}
</script>
my main component
import SelectComponent from './SelectComponent.vue';
export default {
components: {
SelectComponent,
},
mounted() {
console.log('Component mounted.')
},
}
where is my issue?
If you look at the documentation you'll see that the HTML should be wrapped in the <template> element. So change your component to:
<template>
<h1> test connection </h1>
</template>
<script>
export default {
name: 'SelectComponent',
data () {
return {}
}
}
</script>

Vue: props passed to router-link

I want to have 3 main parts in my webapp:
App.vue - this page only has the <router-view> tag and some general configuration + it fetches an API every second
ControlPanel.vue - this page visualizes some data that the App.vue page gets
Profile.vue - this page visualizes some data that the App.vue page gets too
Right now I set up my App.vue with the API call and it passes the data it receives to the two pages with props like the following example. As you can see when it gets mounted it starts a loop that lasts 1 second where it goes and fetches the API and then it returns it to the two routes.
<template>
<div id="app">
<div id="nav">
<router-link :to="{ name: 'control_panel', params: { APIlogs } }">Control panel</router-link>
<span> | </span>
<router-link :to="{ name: 'profile', params: { APIlogs } }">Profile</router-link>
</div>
<router-view/>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
APIlogs: '',
};
},
mounted() {
setInterval(() => this.refreshData(), 1000);
},
methods: {
refreshData() {
axios.get('http://192.168.30.65:5000/logs')
.then((response) => {
this.APIlogs = response.data;
});
},
},
};
</script>
<style>
...
</style>
On the other hand, Control Panel and Profile are fundamentally the same page and they should get the props from the "father" and use it to visualize data but right now it doesn't work. When I click on one route it shows me the value the prop has in that moment and doesn't update as the App.vue page fetches more and more data.
<template>
<div id="app">
{{APIlogs}}
</div>
</template>
<script lang="ts">
import axios from 'axios';
export default {
name: 'control-panel',
props: ['APIlogs'],
data() {
return {
};
},
mounted(){
console.log(this.APIlogs);
},
methods: {
},
};
</script>
<style>
...
</style>
Did I do something wrong? Is my implementation good enough or is it lacking in some way? Really hope someone can help me out with this one, it's really tearing me apart.
Thanks a lot in advance
EDIT
Just to give a bit more context, before having props I was calling the same exact API from both components and it seemd very inefficient to me so I switched to this method.
Also my router.ts looks like this:
import Vue from 'vue';
import Router from 'vue-router';
import ControlPanel from '../src/components/ControlPanel.vue';
import Profile from '../src/components/Profile.vue';
Vue.use(Router);
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'control_panel',
component: ControlPanel,
props: true,
},
{
path: '/profile',
name: 'profile',
component: Profile,
props: true,
},
],
});
there's no params inside your paths i.e: path: '/:apilogs'
A dynamic segment is denoted by a colon :. When a route is matched,
the value of the dynamic segments will be exposed as
this.$route.params in every component.
(source)
After a while and almost an entire afternoon wasted on this problem, I found out this article which helped me achieve my goal. I just created a file with all my api calls and I call it every time I need to fetch something. It's a way more elegant and intelligent solution I think.
An easy way to make this work is to just make your APIlogs an object. Then it would be passed by reference and any updates to it will be reflected in the other components ..
export default {
data() {
return {
APIlogs: {logs: ''},
};
},
mounted() {
setInterval(() => this.refreshData(), 1000);
},
methods: {
refreshData() {
axios.get('http://192.168.30.65:5000/logs')
.then((response) => {
this.APIlogs.logs = response.data;
});
},
},
};
<template>
<div id="app">
{{APIlogs.logs}}
</div>
</template>
PS: You should probably use clearInterval in your beforeDestroy hook.

VueJs - Passing data to subRoutes component with vue-router

I don't understand how to pass data loaded by a 'route Component' to a 'subRoute Component'..
(I'm using Vue.js with Vue-router)
My router looks like that:
router.map({
'/a': {
component: A,
subRoutes: {
'/b': {
component: B
},
'/c': {
component: C
}
}
}
});
I just want to share data loaded by component A with component B and C.
Thanks in advance !
You have two simple options.
The ugly
Use the $parent option from the subroute components. That give you access to the parent instance, it's not the recommended way, but it's effective
// from the child component
this.$parent.someData
The good
Use props. Props give you the chance to pass any data from the parent to a child. It's better, because prevents error (you pass data not an instance) and you pass only what you need, even if it isn't part of the parent data.
// parent component
<template>
<child :childsdata="parentdata"></child>
</template
<script>
export default {
data: function () {
return {
parentdata: 'Hello!'
}
}
}
</script>
// child component
<template>
{{ childsdata }} <!-- prints "Hello!" -->
</template>
<script>
export default {
props: {
childsdata: {
type: String
}
}
}
</script>