What is the best approach for assigning initial values to data retrieved from Vuex?

My objective is to develop an 'edit account' form where users can update their account details. I aim to display the account information in a pre-filled form that includes fields like username, email, and address.

Users will be able to make changes to the data in the form and submit it, updating their user information in the process.

To achieve this, I am utilizing v-model to connect the form inputs to an object named accountInfo within my data structure, which looks like this:

data() {
    return {
        accountInfo: {
                firstName: ''
        }
    }
}

For instance, here's how a form input appears in the template:

<input v-model.trim="accountInfo.firstName" type="text" class="form-control" id="first-name" />

The current values for the keys in the object are empty strings. However, I intend to retrieve these values from an object called userProfile, which is a state property in vuex.

In my 'edit account' component, I'm mapping the vuex state by importing:

import { mapState } from "vuex";

Then using the following code snippet in a computed property:

computed: {
    ...mapState(["userProfile"])
}

The idea is to set the initial values of accountInfo using values from the userProfile computed property mapped from vuex. The implementation would look something like this:

data() {
        return {
            accountInfo: {
                    firstName: this.userProfile.fristName,
            }
        }
    }

However, this approach does not work as expected, presumably because data rendering occurs earlier in the lifecycle than computed properties.

Below is the complete code:

EditAccount.vue

<template>
    <div class="container-fluid">
        <form id="sign_up_form" @submit.prevent>
            <div class="form-row">
                <div class="form-group col-md-6">
                    <input v-model.trim="signupForm.firstName" type="text" class="form-control" id="first_name" />
                </div>
            </div>
        </form>
    </div>
</template>

<script>
import { mapState } from "vuex";
import SideBar from "../common/SideBar.vue";

export default {
  name: "EditAccount",
  computed: {
    ...mapState(["userProfile"])
  },
  data() {
    return {
      accountInfo: {
        firstName: this.userProfile.firstName
      }
    };
  }
};
</script>

store.js:

export const store = new Vuex.Store({
    state: {
        userProfile: {firstName: "Oamar", lastName: "Kanji"}
    }
});

Answer №1

It is important to note that computeds are evaluated after the initial call to the data function.

Solution

In a comment on @Jacob Goh pointed out:

$store should be ready before the data function is called. Therefore, using

firstName: this.$store.state.userProfile.firstName
should suffice.

export default {
  name: 'EditAccount',
  data() {
    return {
      accountInfo: {
        firstName: this.$store.state.userProfile.firstName
      }
    }
  }
};

Alternative approach

Refer to @bottomsnap's response, where setting the initial value can be achieved in the mounted lifecycle hook.

If you proceed with this method, your code would resemble the following:

import { mapState } from 'vuex';

export default {
  name: 'EditAccount',
  computed: {
    ...mapState(['userProfile'])
  },
  data() {
    return {
      accountInfo: {
        firstName: ''
      }
    }
  }
  mounted() {
    this.accountInfo.firstName = this.userProfile.firstName;
  }
};

Keep in mind that it might initially render without the value and then update once mounted.

Separation of concerns

I elaborate on Vue's communication channels in another post, but here is a simple example of how you could handle this situation.

Consider the Form component as handling presentation logic; therefore, it should not be aware of the store but instead receive profile data as a prop.

export default {
    props: {
        profile: {
            type: Object,
        },
    },
    data() {
        return {
            accountInfo: {
                firstName: this.profile.firstName
            }
        };
    }
}

Consequently, delegate business logic to the parent component, including fetching data from the store and triggering actions.

<template>
    <EditAccount :profile="userProfile" :submit="saveUserProfile"/>
</template>

<script>
import { mapState, mapActions } from "vuex";

export default {
    components: { EditAccount },
    computed: mapState(['userProfile']),
    methods: mapActions(['saveUserProfile'])
}
</script>

While acknowledging that Jacob's suggestion about the readiness of the store and using

this.$store.state.userProfile.firstName
may work, I believe the above solution offers a more sustainable design approach.

Answer №2

Tie your input to v-model as shown below:

<div id="app">
    <input type="text" v-model="firstName">
</div>

Utilize the mounted lifecycle hook to initialize the value:

import Vue from 'vue';
import { mapGetters } from 'vuex';

new Vue({
      el: "#app",
      data: {
        firstName: null
      },
      computed: {
        ...mapGetters(["getFirstName"])
      },
      mounted() {
        this.firstName = this.getFirstName
      }
    })

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

Determine the length of a string in JavaScript and PHP taking into account "invisible characters" such as and

I have a textarea where users can input text, and I want to show them how many characters they have left as they type using JavaScript or jQuery: var area = 'textarea#zoomcomment'; var c = $(area).val().length; After that, the text is validated ...

TypeError: Unable to access the 'items' property of a null value

I am currently working on a program and I am facing an issue where I need to access something from the first component in the second component. Can anyone provide assistance on how to properly construct this? Below is a snippet of my code: ...

The dropdown menu is dynamically populated based on the selection from another dropdown menu, with options retrieved from

Apologies if this has been addressed previously, but the existing solutions do not seem to work for me. I have 5 dropdowns: Brand, Model, Color, Engine No., and Chassis No. My query pertains to how I can link the dropdown options for Model based on the sel ...

Comparing the length of an array to whether the length of the array is greater than

What distinguishes checking an array's length as a truthy value from verifying that it is greater than zero? In simple terms, is there any advantage in utilizing one of these conditions over the other: var arr = [1,2,3]; if (arr.length) { } if (arr ...

How come my invocation of (mobx) extendObservable isn't causing a re-render?

Can't figure out why the render isn't triggering after running addSimpleProperty in this code. Been staring at it for a while now and think it might have something to do with extendObservable. const {observable, action, extendObservable} = mobx; ...

Filtering Gridviews with Javascript or jQuery

My current project involves using an ASP.NET GridView with multiple ListBoxes representing Departments, Categories, Faculties, and more. The data in these ListBoxes and the GridView is dynamically loaded from a MSSQL database in the codebehind. I am in ne ...

Exploring the Intersection of Windows 8 Store Applications and jQuery: Leveraging MSApp.execUnsafeLocalFunction

Developing a Windows 8 JavaScript Store App (using Cordova) has led to some complications when using jQuery. It seems that in order to utilize certain functions, I have had to modify the jQuery library by adding: MSApp.execUnsafeLocalFunction While this ...

Having trouble setting up discord.js on my device, getting an error message that says "Unable to install discord.js /

Trying to install Discord.JS by using the command npm install discord.js seems to be successful at first, but unfortunately it doesn't work as expected. Upon running the index.js file, an error message pops up indicating that the module discord.js is ...

Transferring Information Between Vue Components

In my project, I have implemented 3 Vue components to work together seamlessly. Component A is responsible for listening to an event triggered by a user clicking on HTML text and storing the data into a variable. Component B utilizes this data to make an A ...

The require() function is not functioning properly, even after I tried switching the type from module to common. As a newcomer to this, there may be something essential that I

Despite changing the type from module to common, I am still unable to get require() to work. As a newcomer to this, there may be something I'm overlooking that I can't quite pinpoint. I attempted const express = require('express'); but ...

Tips for determining the time and space complexity of this JavaScript code

Here are two codes utilized by my platform to establish relationships between nodes. code1 : const getNodeRelationship = (node1, node2) => { // if node1 and node2 are the same node if (node1 === node2) return null; // check direct parent ...

Discord.js: Merging strings while pushing to an array

I am currently updating an embed message to notify users who have "enlisted" in a list by reacting. However, I am encountering an issue where the strings from the entire array are getting combined when the length of the array reaches 2 before adding a new ...

The checkbox labeled "Shipping Same as Billing" is not functioning correctly. I have included my JavaScript code below, can someone please help me identify what I am overlooking? (Only JavaScript code is provided; HTML is

I'm having trouble transferring data from a 'shipping' address to the 'billing' address section. I've included all my code, but nothing seems to copy over when the check box useShip is selected. All the HTML code is provided f ...

How can JavaScript be properly embedded using PhantomJS?

My objective is to insert the following code snippet into a website using PhantomJS: javascript document.getElementById("pickupZip").value = "90049"; document.getElementById("refreshStoresForZipPop").click(); After attempting this in my inject.js file, I ...

jqueryajax function returns a boolean value upon completion

Recently, I developed a container method to handle an ajax request: function postRating(formData) { $.ajax({ type: "POST", url: '/api/ratings', data: formData }) .done(function () { return true ...

Tips for preventing the caret (^) symbol from being added to a package when installing with yarn

Is there a way to prevent Yarn from adding the caret prefix to version numbers when installing packages like npm has for changing version prefix (https://docs.npmjs.com/misc/config#save-prefix)? I would like to apply this configuration only for the current ...

From Vanilla Javascript to ES6 Spread Operator

I recently incorporated a script into my project that utilizes the ES6 spread operator to extract parameters from the URL. However, I encountered an issue when I realized that the project does not support ES6 syntax. While it is straightforward to apply t ...

Encountering an Axios Error 404 while attempting to save my information to the MongoDB database

I am encountering an Axios error 404 when trying to register details in a MongoDB database. The error message I am getting is - "Failed to load resource: the server responded with a status of 404 (Not Found)." You can view the Error 404 Image for reference ...

Getting an array of objects that have been sent via Ajax in Laravel can be achieved by accessing the

Currently, my setup involves using Laravel alongside Vuejs and AXIOS for handling HTTP requests. I'm faced with a challenge when sending a post request containing an array of objects. The question now is, how can I extract and work with this data in m ...

Canvas - Occasionally, using lineTo() can result in crisp edges in the drawing

I've created a simple Canvas drawing app. However, I've noticed that occasionally the lineTo() command generates a line with fewer coordinates, resulting in many edges: I'm currently using the latest version of Firefox - could this issue be ...