0
votes

When using VueJS, how do you pass a prop to a child component from the $root view instance when using vue-router?

$root instance:

const router = new VueRouter({
    routes: [{
        path: "/dashboard",
        component: () => import("./User/Dashboard.vue" /* webpackChunkName: "js/components/user/Dashboard" */ )
    }]
});

var app = new Vue({
    el: '#app',
    router,
    data: () => ({
        passedProp
    }), 
});

Laravel Layout using :

@section('content')
    <transition name="slide">
        <router-view></router-view>
    </transition>
@endsection

Child Component served by vue-router:

<script>
export default {
    props: [
        'clearFormProp'
    ]
}
</script>

Looking through the vue-router documentation, there is a method of passing a prop via the url. However that makes the prop stateless, and doesn't retain reactivity. It only updates the prop on page refresh.

Passing a static prop leaves me with the same problem.

How can I pass a prop to the child while still retaining reactivity for the prop?

2
do you really need use prop via url/passed to vue-router? I ask this because there is a way to extract the data to a const (reactive) and use in root and child component without using prop - Leo
I technically need to emit an event from parent/$root vue instance to a child component served by vue router. Passing the reactive prop was being used as a flag to bridge the two components in order to trigger an event in the child from the $root/parent. Passing a prop through the router is not a necessity as long as I can retain some sort of reactive data element between the two components. - McWayWeb

2 Answers

0
votes

This solution use a State Pattern to solve the problem.

Assume a simple counter application, with a text displaying the current value and a button that increment it every time the user clicks on it.

Extract the state to a const:

const counter = {
    value: 0
}

export { counter };

Then you can import in the child component and mutate it directly using Vue:

<template>
    <div>
        counter value from child:
        {{ counter.value }}
    </div>
    <div>
        <button type="button" @click="() => counter.value++">increment from child</button>
    </div>
</template>

<script>
import { counter }  from "/src/counter.js";

export default {
    data: () => ({ counter })
}
</script>

In root component, you can do the same thing:

<template>
    <div>
        counter value from root:
        {{ counter.value }}
    </div>
    <div>
        <button type="button" @click="() => counter.value++">increment from root</button>
    </div>

    <ChildComponent />
</template>


<script>
import ChildComponent from './components/ChildComponent.vue'
import { counter }  from "/src/counter.js";

export default {
  name: 'App',
  data: () => ({ counter }),
  components: {
    ChildComponent
  }
}
</script>

See image below how the example behaves:

example

Note: this will only works because the two components are mutating the same object and trigger events to refresh themselves, if you increment the counter value outside a component you will not see the refresh, that can bel solved with vuex.

Also, if this scenario of controlling data in multiple components is common in your application I also recommend vuex

Vuex is a state management pattern + library for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion

0
votes

Pass props into <router-view/> and catch them in the children

<router-view :prop1="localData"></router-view>

and in the target component:

<template>
  <h1>
    {{ prop1 }}
  </h1>
</template>
<script>
 export default{
   props:{
     prop1: Object
   }
 }
</script>