Vue router is designed to maintain the state of child components without requiring them to

Encountering a strange problem with vue-router.

Developed a simple CRUD app for managing users.

The app includes four main views:

  1. User list and a create button
  2. Create view with a form child component that fetches field data from an API within the created() lifecycle hook.
  3. User show view
  4. User update view with a similar form child component.

Issue arises when navigating to edit page of different users. The form displays values of the first user (id: 1) without making any new Ajax request upon switching users.

Seems like the component is being reused. Attempted giving unique :key values to form child components, but no luck.

<router-view :key="$route.fullPath"></router-view>

Setting key on router-view also did not resolve the issue...

Refreshing browser correctly displays form content

Providing a brief overview below:

Defined routes:

import Index from "./views/Index";
import Show from "./views/Show";
import Edit from "./views/Edit";
import Create from "./views/Create";

export default [
    {
        path: '/admin/users',
        name: 'users.index',
        component: Index
    },
    {
        path: '/admin/users/create',
        name: 'users.create',
        component: Create
    },
    {
        path: '/admin/users/:id',
        name: 'users.show',
        component: Show,
        props: true
    },
    {
        path: '/admin/users/:id/edit',
        name: 'users.edit',
        component: Edit,
        props: true
    },
];

Edit component (Create has same structure without id):

<template>
        <ResourceForm
            resource="user"
            :resource-id="id"
            @cancel="$router.push({name: 'users.index'})"
        />
</template>

<script>
    import ResourceForm from "../../../components/ResourceForm";

    export default {
        components: {ResourceForm},

        props: ['id'],
    }
</script>

ResourceForm component:

<template>
    <form @submit.prevent="submitResourceForm">
        <component
            v-for="(field, index) in fields"
            :key="field.name + index"
            :ref="`${field.name}-field`"
            :is="field.component"
            :field="field"
            :validation-errors="getValidationErrors(field)"
        />
        <div class="mt-8 border-t border-gray-200 pt-5">
            <div class="flex justify-end">
                        <span class="inline-flex rounded-md shadow-sm">
                            <button type="button" @click="$emit('cancel')"
                                    class="py-2 px-4 border border-gray-300 rounded-md text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800 transition duration-150 ease-in-out">
                                {{this.cancelText}}
                            </button>
                        </span>
                <span class="ml-3 inline-flex rounded-md shadow-sm">
                            <button type="submit"
                                    class="btn">
                                {{this.submitText}}
                            </button>
                        </span>
            </div>
        </div>
    </form>
</template>
<script>
    import _ from 'lodash';
    import api from "../lib/api";
    import Form from "../lib/mixins/Form";

    export default {
        mixins: [Form],
        props: {
            resource: {
                type: String,
                required: true
            },
            resourceId: {
                required: false,
                default: null
            },
            cancelText: {
                type: String,
                default: 'Cancel'
            },
            submitText: {
                type: String,
                default: 'Submit'
            },
        },
        data() {
            return {
                fields: []
            }
        },
        watch: {
            '$route': function () {
                console.log('route changed');
                this.fetchResourceForm();
            }
        },
        created() {
            this.fetchResourceForm();
        },
        methods: {
            async fetchResourceForm() {
                let route;
                if (this.resourceId !== null) {
                    route = Cms.route('cms.api.forms.show', {
                        resource: this.resource,
                        id: this.resourceId
                    });
                } else {
                    route = Cms.route('cms.api.forms.new', {resource: this.resource});
                }

                const response = await api(route);
                this.fields = response.data.data.fields;
            },

            async submitResourceForm() {
                const formData = this.getFormData();

                try {
                    const foo = {
                        ...Cms.route('cms.api.forms.store', _.pickBy({
                            resource: this.resource,
                            id: this.resourceId
                        })),
                        data: formData
                    };
                    const response = await api(foo);

                    this.$emit('success', response.data.data);

                } catch (error) {
                    if (error.response.status === 422) {
                        this.validationErrors = error.response.data.errors;
                        Cms.flash('error', 'There are validation errors in the form.')
                    }
                }
            }
        }
    }
</script>

The Cms.route method generates API routes and does not relate to vue-router functionalities.

Answer №1

Monitor the router within a parent component to execute specific actions.

watch:{
  `$route`:function(route){
     if(route.name === 'users.create'){
       this.getData(route.params.id);
     }
   }
},
methods:{
   getData:function(id){
     // Fetch data based on the id
     // Save the response to store using `commit`.
     // this.$store.commit('SET_FIELDS',response.data.data.fields);
   }
}

Create a mutation and state in the store.

const state = {
  fields:{}
}

const mutations = {
  SET_FIELDS:(state,value)=>state.fields = value;
}

In the ResourceForm component, access data from the store using the computed method.

computed:{
  fields:function(){
    return this.$store.state.fields;
  }
}

The fields value will update automatically when the route changes.

Answer №2

In my opinion, you could store the user data in a vuex state and then access this state from both components. Alternatively, you might consider making the API request in the beforeEnter hook.

Answer №3

If you're looking for the right solution, consider using In Component Guards. These guard methods are accessible in components when you directly pass an imported view to vue-router:


    {
        path: '/admin/users',
        name: 'users.index',
        component: Index // <-- makes Component Guards available in './views/Index.vue'
    },

Instead of:


created() {
  this.fetchResourceForm();
}

try using:


  // This will trigger if you're already on a DYNAMIC route and a uri parameter like :id changes
  // For example, it will run if you move from `/admin/users/123` to `/admin/users/456`
  beforeRouteUpdate(to, from, next) {
    this.fetchResourceForm();
    next()
  },

  // This will be called when you switch between different router entries.
  // When navigating from `/something` to `/another-path
  beforeRouteEnter(to, from, next) {
    this.fetchResourceForm();
    next()
  },

However, if you're fetching data within a component inside a Router View, using a watch as others have suggested may be necessary. But why not simply pass the data down as a prop instead?

Answer №4

I have identified the issue. It is not directly tied to this feature, but rather to the component responsible for generating the api routes. @Rijosh's solution should be effective if anyone else experiences this problem with vue-router.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Acquiring variables from a JQuery Ajax request while invoking a JavaScript file

I'm currently experimenting with using JQuery Ajax to retrieve a javascript file. I need to pass some parameters to it, but I'm not entirely sure how to do so in Javascript (PHP seems easier for this). Here is my current setup: function getDocum ...

Troubleshooting jQuery compatibility issues with Wordpress

Having some trouble implementing zclip on my Wordpress site to copy dynamically generated text. The code works fine as a standalone html page with embedded jquery, but it's not translating well to my Wordpress site. Even though I've placed the co ...

How can a JavaScript map be created with string keys and values consisting of arrays containing pairs of longs?

Struggling with JavaScript data structures, I am trying to create a map in which the key is a string and the value is an array of two longs. For instance: var y = myMap["AnotherString"]; var firstNum = y[0][0]; var secondNum = y[0][1]; // perform opera ...

"Activate the parent window by navigating using the accesskey assigned to the href

I have integrated a bank calculator tool into a website. The calculator opens in a new window, but I am encountering an issue. Users need a shortcut to open the calculator multiple times. I have discovered the accesskey feature, which works the first tim ...

Leveraging JavaScript and PHP for fetching image files and generating a downloadable zip folder

Currently, I am in the process of creating a Safari extension specifically designed for imageboard-style websites. One of the key features that I am eager to incorporate is the ability to download all images that have been posted on the site (not including ...

Utilizing Vue Cli's Webpack Proxy feature

While working on a project using the vue-cli and the Webpack template, I am facing some difficulties with setting up a custom host. Currently, Webpack is listening to localhost:8080, but I need it to work with a custom domain like . Has anyone found a solu ...

The Android webview encountered an error: XMLHttpRequest failed to load because the specified Origin <url> is not permitted by Access-Control-Allow-Origin restrictions

I have developed an application that loads an entire website in an Android WebView. The native code in the Android project communicates with the webpage using the Android Jockey Library, and vice versa. Everything is working smoothly except for one instan ...

A guide to efficiently managing multiple v-on:click events within a Vue component to toggle the visibility of various elements

I am working with a method called toggleShow. I have two different elements calling this method, but I need the toggleShow function to toggle the v-if value of the specific element that triggered it. How can this be achieved in vue.js? Check out my attemp ...

What is the best method to modify the accurate phone number within my script?

I need help with a text format script. link HTML CODE: <label for="primary_phone">Primary Phone Number<span class="star">*</span></label> <br> <input type="text" name="primary_phone" id="primary_phone" class="_phone requ ...

Content duplication within Three.js, React.js, and Next.js is a common issue

I've encountered a case where I am using Three.js in react(next js) and a Mesh I have created is duplicated multiple times import * as THREE from 'three'; function Index() { if (process.browser) { const scene = new THREE.Scene( ...

Discovering an object by its id in vue-router parameters and subsequently sending its attributes to a template within Vue

In my ContactDetails component, I am fetching data from the vuex state and storing it in a contacts array. Then, within a computed property, I am attempting to find and return an object based on the id prop passed from the router params. Here is the code ...

Capture microphone and audio in a SIP call with sip.js

Greetings Stack Overflow community! I am in need of assistance with a project involving sip.js and VoIP for making real phone calls. The Objective I aim to enable users to record audio from both parties during a call and save the data on a server (either ...

Accessing data stored in XML or JSON files from a local server

I am currently working on loading a list of coordinates for a Google map from either an XML or JSON file, both of which are hosted in the same directory on my local test server. So far, I have used a hard-coded JSON object to load map coordinates for tes ...

Prioritize loading CMS content before mounting the React component

I am facing a challenge with importing my post from ButterCMS to React due to the async issue. import React, { useState } from "react" import Butter from "buttercms" import gradient from "../../images/TealLove.jpg" export default () => { const butt ...

Enhancing CKEditor: Inserting new elements upon each dialog opening

I am facing a challenge where I need to dynamically add varying numbers of elements to a dialog window each time it is opened. Below is the code I am working with: CKEDITOR.on( 'dialogDefinition', function(ev) { var dialogName = ev.data.name ...

Utilizing a universal JavaScript array within the jQuery document(ready) function

After using jsRender to render the following HTML template, I encountered an issue with passing data values through jQuery selectors when submitting a form via AJAX. <div class="noteActions top" style="z-index: 3;"> <span onclick="noteAction(&a ...

XMLHttpRequest request shows blank result

Issue: After clicking the submit button on my HTML form, a JavaScript function is called with an Ajax request. The request returns successfully, but the result disappears quickly. I'm curious if I may be overlooking something here (besides jQuery, w ...

Displaying Dynamic Content in React Table Rows Based on Conditions

I'm populating a table with multiple rows using props. If a returned prop is an empty string "" , I want to exclude that row from rendering. <Table.Body> <Table.Row> <Table.Cell>Producer</Table.Cell> ...

The priority of custom attributes in HTML

There seems to be some ambiguity regarding whether data- attributes should be considered primary or secondary syntax. Is there a defined standard for this in major frameworks like Angular? For example, if an attribute is specified as both my-attr and dat ...

What are the steps to run a webpack project without relying on webpack-dev-server?

I've been working on hosting my project on GitHub pages by creating a /doc file and placing all my HTML, CSS, and JS there. If you're interested, you can check out my project here: https://github.com/mattfrancis888/the_movie_db The only way I&a ...