I want to pass data from a Homepage.vue to a clickthru.vue.
Upon clicking on a record in a table (in Homepage.vue) I want to be routed to a new component (clickthru.vue). The goal is to pass two kinds of data in two distinct ways:
First: I want to pass the cve_id as a route.query as shown below
/clickthru?cve_id=CVE-xxxx-xxxx
Second: I also want to pass an object as a param to render/mount on the html template of clickthru.vue. The object looks something like this:
{ "cve": "CVE-2022-45869", "severity": "Medium", "packages": [ { "package": "kernel", "version": "5.15.80.1", "owner": "joslobo", "detection_date": "12-03-2022", "BranchStatus": { "1.0": { "sourceBranch": "NULL", "status": "NULL", "detectedOn": "NULL", "patchedOn": "NULL", "firstPatchedPackageRelease": "NULL", "fixReleaseDate": "NULL", "aid": "NULL", "qid": [ "NULL" ] }, "2.0": { "sourceBranch": "2.0", "status": "Unpatched", "detectedOn": "12-03-2022", "patchedOn": "NULL", "firstPatchedPackageRelease": "NULL", "fixReleaseDate": "NULL", "aid": "11574", "qid": [ "Not Assigned" ] } } }, { "package": "kernel", "version": "5.10.155.1", "owner": "joslobo", "detection_date": "12-03-2022", "BranchStatus": { "1.0": { "sourceBranch": "1.0", "status": "Unpatched", "detectedOn": "12-03-2022", "patchedOn": "NULL", "firstPatchedPackageRelease": "NULL", "fixReleaseDate": "NULL", "aid": "11573", "qid": [ "Not Assigned" ] }, "2.0": { "sourceBranch": "NULL", "status": "NULL", "detectedOn": "NULL", "patchedOn": "NULL", "firstPatchedPackageRelease": "NULL", "fixReleaseDate": "NULL", "aid": "NULL", "qid": [ "NULL" ] } } } ] }
In my homepage.vue, I iterate over records/objects and display in a table format as shown: Homepage.vue
<tbody>
<template v-for="(cve) in backend_res">
<template v-for="(pack_key, index) in Object.keys(cve.packages)">
<tr>
<td>
<span v-if="index == 0" @click.prevent="onAboutClick(cve.cve, cve.packages)">
{{cve.cve}}
</span>
</td>
</tr>
</template>
</template>
</tbody>
methods: {
onAboutClick(cve_id, cve_obj) {
console.log('----> cve_id = ', cve_id)
console.log('----> cve_obj = ', cve_obj) // cve_obj is successfully printed at this point
this.$router.push(
{
name: 'clickthru',
query: {'cve_id': cve_id},
params: {'cve_obj': cve_obj}
})}
clickthru.vue
<script>
export default {
props: ['cve_id', 'cve_obj'],
data() {
return {
cve_id: this.$route.query.cve_id,
cve_obj: this.$route.params.cve_obj, // cve_obj is undefined
};
},
main.js
const routes = [
{
path: '/clickthru',
name: 'clickthru',
component: clickthru,
props: true
}
]
As can be seen below when $route is logged, the query is recognized successfuly, however, params is empty.
{ "fullPath": "/clickthru?cve_id=CVE-2022-45869", "hash": "", "query": { "cve_id": "CVE-2022-45869" }, "name": "clickthru", "path": "/clickthru", "params": {}, "matched": [ { "path": "/clickthru", "name": "clickthru", "meta": {}, "props": { "default": false }, "children": [], "instances": { "default": null }, "leaveGuards": { "Set(0)": [] }, "updateGuards": { "Set(0)": [] }, "enterCallbacks": {}, "components": { "default": { "props": [ "cve_id", "cve_obj" ], "__hmrId": "91ec59e3", "__file": "E:/ASTROLABE_FE/CBL-Mariner-CVE-Website/src/components/clickthru.vue" } } } ], "meta": {}, "href": "/clickthru?cve_id=CVE-2022-45869" }
I want to be able to pass the cve_obj without it being part of the url/path Any tips as to how to do that whether via params, meta or any other way is appreciated
CodePudding user response:
Because your goal is to send data after route to new page with the help of route.push
, I ignored some part of your codes (like using table or v-for
that you used in Homepage.vue
). Here is my codes that I think could help you:
Homepage.vue:
<template>
<div @click="onAboutClick(cveData.cve, cveData.packages)">
some text
</div>
</template>
<script>
export default {
data() {
return {
cveData: { "cve": "CVE-2022-45869", "severity": "Medium", "packages": [ { "package": "kernel", "version": "5.15.80.1", "owner": "joslobo", "detection_date": "12-03-2022", "BranchStatus": { "1.0": { "sourceBranch": "NULL", "status": "NULL", "detectedOn": "NULL", "patchedOn": "NULL", "firstPatchedPackageRelease": "NULL", "fixReleaseDate": "NULL", "aid": "NULL", "qid": [ "NULL" ] }, "2.0": { "sourceBranch": "2.0", "status": "Unpatched", "detectedOn": "12-03-2022", "patchedOn": "NULL", "firstPatchedPackageRelease": "NULL", "fixReleaseDate": "NULL", "aid": "11574", "qid": [ "Not Assigned" ] } } }, { "package": "kernel", "version": "5.10.155.1", "owner": "joslobo", "detection_date": "12-03-2022", "BranchStatus": { "1.0": { "sourceBranch": "1.0", "status": "Unpatched", "detectedOn": "12-03-2022", "patchedOn": "NULL", "firstPatchedPackageRelease": "NULL", "fixReleaseDate": "NULL", "aid": "11573", "qid": [ "Not Assigned" ] }, "2.0": { "sourceBranch": "NULL", "status": "NULL", "detectedOn": "NULL", "patchedOn": "NULL", "firstPatchedPackageRelease": "NULL", "fixReleaseDate": "NULL", "aid": "NULL", "qid": [ "NULL" ] } } } ] }
}
},
methods: {
onAboutClick: function (cve_id, cve_obj) {
console.log('----> cve_id = ', cve_id)
console.log('----> cve_obj = ', cve_obj) // cve_obj is successfully printed at this point
let objData = JSON.stringify(cve_obj);
this.$router.push(
{
name: 'clickthru',
query: {'cve_id': cve_id},
params: {'cve_obj': objData}
}
)
} // end of function
}
}
</script>
clickthru.vue:
<template>
<div>
this is "clickthru" compo
</div>
<section>
{{ cve_id }}
</section>
<section v-for="item in cve2">
<div v-for="subItem in item">
{{ subItem }}
</div>
</section>
</template>
<script>
export default {
name: "clickthru",
data() {
return {
cve_id: this.$route.query.cve_id,
cve_obj: this.$route.params.cve_obj, // cve_obj is "not" undefined
};
},
computed: {
cve2: function () {
let obj = JSON.parse(this.cve_obj);
return obj;
}
}
}
</script>
<style scoped>
</style>
According to vue-router docs:
When specifying params, make sure to either provide a string or number (or an array of these for repeatable params). Any other type (like undefined, false, etc) will be automatically stringified.
Because your cve_obj
data is of type "object", to ensure that no problem will happen, I used JSON.stringify
in Homepage.vue
to convert it to a string. Then in the clickthru.vue
component, I convert it back to an object with the help of computed properties and JSON.parse
method.
If you use this code, you won't need to use props: true
in the main.js
, because you don't use props at all.
CodePudding user response:
As I mentioned in the comments, passing objects as query params is not an appreciated way, so there are two ways to do this-
Approach 1-
Pass only cve_id
to the new route and when the new route's page is mounted, fetch the cve_object
from the backend using this query param cve_id
.
This approach is useful and recommended because you will always have updated data from the backend.
If you follow this approach then a few changes are necessary-
- In Homepage.vue pass only
cve_id
to your new route-
methods: {
onAboutClick(cve_id) {
this.$router.push({
name: "clickthru",
query: { cve_id: cve_id },
});
},
},
- On
clickthru.vue
mounted hook, init the API call to getcve_data
of that id-
mounted() {
// Make an API call to fetch the respected id's data
}
Approach 2-
When you receive the records (on which you are looping) in your HomePage.vue
, save this data to your Vuex state. Now, same as approach one, pass only the cve_id
to your new route and when the new route's page is mounted, fetch the respected data from the Vuex state instead of fetching from an extra API call.
If you follow this approach then the process will be like this-
- When you get the backend response in your HomePage.vue, dump it in the state, like this-
const store = new Vuex.Store({
state: {
records: []
},
mutations: {
SET_RECORDS (state, backend_response) {
// mutate state
state.records = backend_response;
}
}
})
- Same as approach one, you have the
cve_id
in your route query, so use it to fetch the respectedcve_object
from the state. So, onclickthru.vue
mounted, do this-
<script>
export default {
data() {
return {
cve_object: null,
};
},
mounted() {
this.cve_object = this.$store.state.records.find(
(item) => item.id == this.$route.query.cve_id,
);
},
};
</script>
In this way you will have your records in the state, so you can find any single record using the query cve_id
on any page.
NOTE-
I only give the idea to fetch and set data from the state. If you want to follow the second approach, just read about Vuex and follow the documentation.
You can also check out this here complete guide on how to set up Vuex in the Vue application.