Vue component prop not updating on $emit

Viewed 45

I need to update the component's prop on every route change but it stays with the last info given.

For example, I fill the form in RouteTwo, with id, name, lastname and phone, and if I change to RouteOne, ComponentOne stays with those four values (including phone) until I start filling the form in RouteOne.

I'm working with vue 2.6.12, vue-router 3.4.9

Here's an example code:

General.vue

<template>
    <div>
        <div>
            <router-view @data-updated="updateFunction"></router-view>
        </div>
        <div>
            <component-one v-bind:component-prop="reactiveProp" />
        </div>
    </div>
</template>
<script>
import ComponentOne from './ComponentOne.vue';
export default {
    components: {
        ComponentOne,
    },
    data: () => ({
        reactiveProp
    }),
    methods: {
        updateFunction(value) {
            this.reactiveProp = value;
        },
    }
}
</script>

ComponentOne.vue

<template>
    <div>
        <p>{{ componentProp.id }}</p>
        <p>{{ componentProp.name }}</p>
        <p>{{ componentProp.lastname }}</p>
        <p v-if="routePath == 'routetwo'">{{ componentProp.phone }}</p>
    </div>
</template>
<script>
export default {
    props: {
        componentProp: Object,
    },
    data: () => ({
        routePath: ''
    }),
    mounted() {
        this.routePath = this.$route.path.split('/').at(-1);
    },
}
</script>

RouteOne.vue

<template>
    <div>
        <input type="text" v-model="dataObject.id" />
        <input type="text" v-model="dataObject.name" />
        <input type="text" v-model="dataObject.lastname" />
    </div>
</template>
<script>
export default {
    data: () => ({
        dataObject: {
            id: '',
            name: '',
            lastname: '',
        },
    }),
    methods: {
        // some logic methods
    },
    watch: {
        dataObject: {
            handler: function() {
                this.$emit('data-updated',this.dataObject);
            },
            deep: true,
        }
    },
}
</scipt>

RouteTwo.vue

<template>
    <div>
        <input type="text" v-model="dataObject.id" />
        <input type="text" v-model="dataObject.name" />
        <input type="text" v-model="dataObject.lastname" />
        <input type="text" v-model="dataObject.phone" />
    </div>
</template>
<script>
export default {
    data: () => ({
        dataObject: {
            id: '',
            name: '',
            lastname: '',
            phone: '',
        },
    }),
    methods: {
        // some logic methods
    },
    watch: {
        dataObject: {
            handler: function() {
                this.$emit('data-updated',this.dataObject);
            },
            deep: true,
        }
    },
}
</scipt>

Router

{
    name: 'general',
    path: '/general',
    component: () => import('General.vue'),
    children: [
        {
            name: 'route-one',
            path: 'routeone',
            component: () => import('RouteOne.vue')
        },
        {
            name: 'route-two',
            path: 'routetwo',
            component: () => import('RouteTwo.vue')
        }
    ]
}
1 Answers

Switching routes doesn't cause a change in dataObject, so no emit will fire. Technically, switching routes causes one route component to be unmounted (destroyed), and the next route component to be created, meaning dataObject is created/recreated every time you switch back and forth, which is fundamentally different from dataObject being "changed" (which activates the watcher).

Instead, put a watcher on the route itself in the General component and reset reactiveProp when that watcher activates. This will clear the fields when going between RouteOne and RouteTwo:

  watch: {
    $route(to, from) {
      this.reactiveProp = {};
    },
  },
Related