KP1O8
KP1O8

Reputation: 31

Pass Custom JS Object through Vue Router

HELP! I have been banging my head against the wall for hours on this...

Technologies Being Used:

The Goal
I have two pages (Home.vue, MetaUpdate.vue) and one component (Document.vue). Home contains several Document components. Upon clicking the "Update" div/button in one of the Document components, we should route to the MetaUpdate page. The MetaUpdate page needs to hold the whole Doc JS object which is defined below, passed down from the Document component through the router.

The Problem:
For some reason, when I pass my custom object as a prop through the router, it's like it doesn't know how to interpret the object and it passes it as the string "[object Object]". However, if I pass the custom object as a prop from the parent component to the child component, it interprets it correctly. So, how do I actually send props through the router? It should be noted that I was originally passing two Strings through the router successfully, so I do not understand why when I changed it to pass a custom object, everything broke.

JavaScript Object

class Doc {
    constructor(docID, title, status) {
        this.docID = docID;
        this.title = title;
        this.status = status;
    }
}

router.js

import { createRouter, createWebHashHistory } from 'vue-router'

import Home from '../views/Home.vue'
import MetaUpdate from '../views/MetaUpdate.vue'

import {Doc} from '../controllers/data'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/metaupdate/:doc',
    name: 'MetaUpdate',
    component: MetaUpdate
  }
]

const router = createRouter({
  history: createWebHashHistory(),
  routes,
})

export default router

Home.vue
There is more in the file, but this is all that is necessary for the purpose of answering this question.

<template>
<div class="col col-12 col-lg-6 in-progress">
    <div class="doc-status">In Progress</div>
        <template v-for="(doc, index) in inProgress" :key="index">
            <Document :doc="doc"></Document>
        </template>
    </div>
</div>
</template>

<script>
import Document from "../components/Document.vue";
import {Doc} from '../controllers/data'
var inProgress = [];
var pending = []
var completed = [];

export default {
    data: function() {
        return {
            inProgress,
            pending,
            completed
        }
    },
    components: {
        Document
    }
}

/***** Temporary Push of Docs *****/
for(let i = 0; i < 5; i++){
    let docA = new Doc(i, 'Progress Document', 'in-progress');
    let docB = new Doc(i, 'Pending Document', 'pending');
    let docC = new Doc(i, 'Completed Document', 'completed');

    inProgress.push(docA);
    pending.push(docB);
    completed.push(docC);
}
/***** Temporary Push of Docs *****/
</script>

Document.vue

<template>
    <div class="doc">
        <div class="doc-title">{{ doc.title }}</div>
        <router-link to="/docviewer" v-if="isInProgress" class="doc-item submit">Submit</router-link>
        <router-link to="/docviewer" class="doc-item preview">Preview</router-link>
        <router-link 
            :to="{  name: 'MetaUpdate',
                    params: {doc: this.doc} }" v-if="isUpdateOrDelete" class="doc-item update">Update
        </router-link>
        <router-link to="/docviewer" v-if="isUpdateOrDelete" class="doc-item delete">Delete</router-link>
    </div>
</template>

<script>
import {Doc} from '../controllers/data'

export default {
    props: {
        doc: {
            type: Doc,
            required: true
        }
    },
    computed: {
        isInProgress() {
            return this.doc.status === 'in-progress';
        },
        isUpdateOrDelete() {
            return this.doc.status === 'in-progress' || this.doc.status === 'pending';
        }
    }
}
</script>

MetaUpdate.vue
There is more in the file, but this is all that is necessary for the purpose of answering this question.

<template>
    <div class="tabs">{{ $route.params.doc.title }}</div>
</template>

<script>
import { Doc } from '../controllers/data'

export default {
    props: {
        doc: {
            type: Doc,
            required: true
        }
    }
}
</script>

Upvotes: 2

Views: 585

Answers (1)

Decade Moon
Decade Moon

Reputation: 34306

You cannot pass an object as a route param. Route params are strings because the params form part of the URL; if you pass a param that isn't a string then it will be converted to a string. What did you expect the URL would be after navigation with the :doc param set to an object?

Instead you should set the doc ID as the param and then the route component that receives that param would lookup the doc object using the ID somehow. How you do this is up to you, perhaps:

  • Have all docs stored in a global array shared amongst all components (you could use Vuex to do this).
  • The parent component could pass down to the <router-view> the doc array and then the route component can look up the document by ID in this array.

Upvotes: 1

Related Questions