Home > Blockchain >  Undefined route.params when passing data between components via route.push
Undefined route.params when passing data between components via route.push

Time:12-13

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-

  1. 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 },
        });
    },
},
  1. On clickthru.vue mounted hook, init the API call to get cve_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-

  1. 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;
    }
  }
})
  1. Same as approach one, you have the cve_id in your route query, so use it to fetch the respected cve_object from the state. So, on clickthru.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.

  • Related