(Vue Router) Push params when on a certain route - vue.js

I have a component, which has programmatic routing based on external data.
The external data is fetched in the App.vue component and used in child components as props.
The data is used in the child component like this:
props: {
externalData: Array
},
computed() {
data() {
return this.externalData
}
}
Here is my router.js (excerpt)
const routes = [
{
path: "/:hae?",
name: "Home",
component: Home
},
{
path: "*",
name: "NotFound",
component: NotFound
}
];
And my Home.vue with the $router.push method (excerpt):
created() {
if (this.$route.path === "/") {
this.$router.push({
params: {
hae: this.data[0].id
}
});
}
},
So here is what i want to achieve:
This is my example array: [{hae: "hae001"}, {hae: "hae002"}, {hae: "hae003"} ...]
When you navigate to https://website.com/ i want the router to redirect you to a param which is the first element of the array, but if you navigate to somewhere else which is not existing in the array (e.g. /something) i want the router to render my NotFound.vue component.
What am i missing?

created() {
const firstDataElementExists = this.data && this.data[0] && this.data[0].hae
if (!firstDataElementExists) {
this.$router.push('/404')
return
}
const isRootPath = this.$route.path === '/'
if (isRootPath) {
this.$router.push(this.data[0].hae)
return
}
const pathIsInData = !!this.data.find(d => d.hae === p)
if (!isRootPath && !pathIsInData) {
this.$router.push('/404')
}
}

Related

Vue pass query parameters as component properties?

Using vuejs2 & vue-router3, how do I take query parameters and pass them into the props of a route component? And remove the query string from the URL?
This is to support opening a link in a new window
const router = new Router({
routes: [
{
path: "/",
name: "dashboard",
meta: {
title: "",
roles: ["*"]
},
component: DashboardView,
props: AddQueryToPropsAndRemoveQuery
}
]
});
function AddQueryToPropsAndRemoveQuery(route) {
var props = route.params;
if (Object.entries(route.query).length > 0) {
// combine query params into the props
for (const [key, value] of Object.entries(route.query)) {
props[key] = value;
}
router.push({ params: props, query: undefined })
}
return props;
}
export default router;

trigger method in parent from child nested in router in Quasar (vue)

I got this structure with nested routes in my router using Quasar framework (vue 3):
const routes = [
{
path: "/",
component: () => import("layouts/myLayout.vue"),
children: [
{
path: "",
component: () => import("pages/Main.vue"),
children: [
{
path: "",
component: () => import("components/Sub.vue")
}
]
}
]
}
I know I can use $emit in my child to pass to parent like this:
MyChild:
this.$emit("myEvent", "hello world");
MyParent:
<MyChild #myEvent="updateMyEvent" />
However I want to trigger an event in parent without rendering MyChild once again in the parent since it is already displayed through the router ... So I am looking for a way of accessing the parents method more directly so to speak.
What is the correct implementation of doing this in vue 3?
UPDATE:
my method in child for updating vuex:
this.updateValue(JSON.parse(JSON.stringify(myValue)));
Store.js
vuex:
const state = {
value: 0
};
const actions = {
updateValue({ commit }, payload) {
commit("updateMyValue", payload);
},
const mutations = {
updateMyValue(state, payload) {
state.myValue = payload;
},
};
const getters = {
getValue: state => {
return state.value;
},
I actually ended up with a watcher on my getter in my parent:
computed: {
...mapGetters("store", ["getValue"]) // module and name of the getter
},
watch: {
getValue(val) {
console.log("MY VALUE: " , val);
}
In the child parent component define a computed property called stateValue that's based on the store state value and then watch it to trigger that event :
computed:{
stateValue(){
return this.$store.state.value;
}
},
watch:{
stateValue(val){
this.updateMyEvent()// trigger the method
}
}

How to reset state values for the component?

I use vuex, and in my page module I set title and content, I arranged a destroyed method to reset them, If I click a different component there is no problem while resetting values but when I click a different static page, component is not destroyed and data is not updated. Is there a way to reset vuex state values for the same component.?
const state = {
page: {},
};
const getters = {
page(state) {
return state.page;
},
};
const mutations = {
setAPage (state, pPage) {
state.page = pPage
state.errors = {}
},
setCleanPage(state){
state.page = null
},
reset(state) {
const s = state();
Object.keys(s).forEach(key => {
state[key] = s[key];
});
console.log('state', state)
}
}
const actions = {
fetchAPage (context, payload) {
context.commit("setCleanPage");
const {slug} = payload;
return ApiService.get(`pages/${slug}/`)
.then((data) => {
context.commit("setAPage", data.data);
})
.catch((response) => {
context.commit("setError", response.data)
})
},
resetAPage(context){
context.commit("reset");
}
};
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
and in my component :
<script>
import { mapGetters, mapActions, mapMutations } from "vuex";
export default {
name: "Page",
computed: {
...mapGetters('pages', {page: 'page'}),
},
beforeRouteLeave (to, from, next) {
// called when the route that renders this component has changed,
// but this component is reused in the new route.
// For example, for a route with dynamic params /foo/:id, when we
// navigate between /foo/1 and /foo/2, the same Foo component instance
// will be reused, and this hook will be called when that happens.
// has access to >this component instance.
console.log(to)
console.log(from)
console.log(next)
this.$store.dispatch('pages/resetAPage');
},
methods: {
...mapActions(['pages/fetchAPage']),
},
destroyed() {
this.toggleBodyClass('removeClass', 'landing-page');
this.$store.dispatch('pages/resetAPage');
},
created() {
this.$store.dispatch('pages/fetchAPage' , this.$route.params)
},
};
</script>
How can I reset or update data for the same component ?
Thanks
You can use this package for your resets - https://github.com/ianwalter/vue-component-reset
You can use a beforeRouteLeave guard in your component(s) when you want to catch the navigation away from the route where the component is being used (https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards)
The beforeRouteUpdate component guard is called only when the component was used in the current route and is going to be reused in the next route.
I would suggest you watch for that param change.
I don't know how you make use of your params, but you can pass them to your component as props and then add a watcher on them which would call your vuex reset action.
// in your router
// ... some routes
{
path: "/page/:id",
props: true, // this passes :id as prop to your component
component: Page
}
In you component
export default {
name: "Page",
props: ["id"], // your route param
computed: {
...mapGetters('pages', {page: 'page'}),
},
beforeRouteLeave (to, from, next) {
// called when the route that renders this component has changed,
// but this component is reused in the new route.
// For example, for a route with dynamic params /foo/:id, when we
// navigate between /foo/1 and /foo/2, the same Foo component instance
// will be reused, and this hook will be called when that happens.
// has access to >this component instance.
console.log(to)
console.log(from)
console.log(next)
this.$store.dispatch('pages/resetAPage');
},
methods: {
...mapActions(['pages/fetchAPage']),
},
watch: {
id() { // watch the id and reset the page if it has changed or add additionnal logic as needed
this.$store.dispatch('pages/resetAPage');
}
},
destroyed() {
this.toggleBodyClass('removeClass', 'landing-page');
this.$store.dispatch('pages/resetAPage');
},
created() {
this.$store.dispatch('pages/fetchAPage' , this.$route.params)
},
};

Pass data through router to other component in vue

I am trying to pass data through router. My code is working but it shows data in url. I don't want that like as POST method.url should like /data-list . Also I want to catch passing value from component. Here I did not use vuex . Actually my job is to show message that task is done based on this data. I am using Laravel for backend. Thanks in advance
1st component
axios.post("/request/data", dataform).then(function (resp) {
app.$router.push({ path: "/data-list/" + resp.data.success });
});
routes
{
path: '/data-list/:message?',
name: 'dataList',
component: dataList,
meta: {
auth: true
}
},
Another component. Here I want to catch
mounted() {
var app = this;
app.message = app.$route.params.message;
}
So if I understand correctly, you are fetching data in some component and then you are doing a router-push to dataList component.
You want to access the data in dataList component.
Since you always want the route to be /dataList, do this in your routes file
{
path: '/data-list', //removing dynamic tag.
name: 'dataList',
component: dataList,
meta: {
auth: true
}
},
Then in the component where you do router push, add a handleClick like so.
handleClick() {
let data = {
id: 25,
description: "pass data through params"
};
this.$router.push({
name: "dataList", //use name for router push
params: { data }
});
}
}
Then in your dataList component you can access the data passed in the mounted like so :
mounted() {
let data = this.$route.params.data;
console.log("data is", data);
}
Working implementation attached below.
You can push router data in router like this.
this.$router.push({
name: "dataList",
params: { data: resp.data },
});
and in the routes you can define your route as
{
path: "/dataList",
name: "dataList",
props: true,
meta: { title: "Data list" },
component: () => import("path to datalist component")
},
and in the DataList.vue you can use props to get the data
export default {
props:['data'],
mounted(){
alert(this.data);
}
}

Vuejs router listen to events

I have a component wherein the props were passed through the route (https://router.vuejs.org/guide/essentials/passing-props.html). My question is how do I listen to emitted events from the component so that I can mutate the props passed from the route?
In my route I have something like
...
{
path: "details/:id?",
name: "booking.details",
component: BookingDetails,
props: true
}
...
And inside the component I have a props
...
props: {
invoice: {
type: Object,
required: false,
default: () => ({})
}
},
...
methods: {
save () {
this.$emit('reset-invoice') // where do I capture this event
}
}
...
If I understood your question correctly, the listening component would be the <router-view>, so:
<router-view #reset-invoice="resetInvoice"></router-view>
And in whichever component this router view is rendered:
{
methods: {
resetInvoice() {
// ...
}
}
}
You should watch the route and set the props passed from the route, like below
watch: {
'$route' (to, from) {
this.user_id = this.$route.params.id
},
}