Skip to main content

Vuex State Management Sample


Vuex is a state management pattern or state management library. Vuex makes data management easy and more maintainable in the application. Vuex main target of integration with Vue.js library. 

In simple words, Vuex is a data store that supplies or provide data to Vue components with much consistently, more efficiently by making code more simple. Transferring of data between the component can be done effectively using Vuex when comparing with the traditional way(Vue.js passing data by input parameters). Vuex pattern is similar to Redux, Flux existing libraries for state management.

Vuex Core Building Blocks:

Actions: Actions are task performers which have the capabilities to do either synchronous or asynchronous operations. In Vuex actions are used to invoke the rest API's to fetch the data and then actions call mutations to change the store state. To invoke mutations actions use a command called 'commit'. This 'commit' command invokes appropriate mutation and receives the rest API data as input to save into the store state.

Mutations: Mutations are to perform mutable operations. In Vuex the only option to change the state of the store is to use mutations. So the only way to add or update the data of the Vuex store is done by mutations.

State: State is a simple javascript object literal. A Vuex store saves or holds the data in the state object.

Getters: Getters are to perform tasks to retrieve the data from the Vuex store state. Getters are helped to retrieve data and then we can bind the data to components. So using these Getters in n-number of Vue Components can share the same data from the Vuex store.

Create A Sample Vue App:

To learn Vuex implementation step by step, here we are going to implement a sample Vue application.
Here I'm Vue CLI(command line interface) to operate or create Vue application.
Command To Install Vue CLI Globally On Your System:

npm run -g @vue/cli
Command To Create Vue App:

vue create your_application_name
After creating sample application run the following command to start the application.
Command To Run Vue App:

npm run serve
After the application starts then output shows as below.

Test API:

We are going to use a free development rest API in our sample application to consume the data. Here we are going to use 'Dummy Rest API Example' a free hosted API for developers.
Dummy Rest API Example
http://dummy.restapiexample.com/
Sample dummy rest API output shows as below(screenshot to understand JSON response structure and it's property name that we going to bind in our sample app)

Install Vuex And Axois:

Vuex package needs to install to implement store in our Vue application. Axios package installs to help to fetch API data with easy steps. So run the following commands to install both the packages.
Command To Install Vuex Package

npm install Vuex
Command To Install Axios Package

npm install Axios

Add A Store Folder And index.js File:

Now let's create a separate folder structure to save them all store related files in the folders as below.

In-store management of Vue application will have an n-number of stores(like example student store, teachers store, employee store, account store, etc). Each store will have it's own 'js' file to maintain store and all these store files will be saved under the folder 'modules'
Now let's create an index.js file in the 'store' folder. This index.js file is like a global store that will hold all other application stores and will expose them to the components.
src/store/index.js:
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
    modules:{
        
    }
})
  • (Line:4) To load or integrate Vuex into the Vue js then Vuex is passed parameter to 'Vue.use()' method. This method is similar to the middleware configuration in other frameworks
  • (Linet:6-10) Create an instance of the Vuex Store and this store should be exposed to the application by using the 'export' key. On initializing the Vuex Store expects configurations like 'state', 'mutation','getters','actions', etc. Here we can see we have configured modules property with an empty object literal. This module will be configured with our individual store module in the upcoming steps.

Register Store In main.js:

To make our store accessible to our Vue application need to register our global store index.js file in our main.js.
src/main.js:
import Vue from 'vue'
import App from './App.vue'
import store from './store/index'

Vue.config.productionTip = false

new Vue({
  store,
  render: h => h(App),
}).$mount('#app')
  • (Line:3) index store imported into the main.js file.
  • (Line:8) our global store(src/store/index.js) configured into the entry Vue instance of the application. This configuration makes our store can be accessed into the Vue application components.

Create An Employee Store Module:

In this Vue sample, we are going to work on employee data. So here we are going to create an employee-store module.
src/store/module/employee.js:
const state = {};

const getters = {};

const actions = {};

const mutations = {};

export default {
    state,
    getters,
    actions,
    mutations
}
  • Here we created an employee-store module with a basic skeleton structure of the store.
  • we can observe the core building block of the store like 'state', 'getters', 'actions', 'mutations', and all are initialized as object literal.
  • (Line: 9-14) exposing the store configuration to make it accessible to the application.
  • (Line: 1) the state is the storage area of application data. All the API data that going to be rendered or utilized by the application will be stored in the state object. So for our sample, all our employee data will be stored in this 'state' object as well.
  • (Line: 3) the getters contain all the filters or methods for fetching data to Vue components in the application from the 'state' object.
  • (Line: 5) the actions perform the tasks like fetching API data and stores the data into the 'state' object.
  • (Line: 7) the mutations perform the tasks like manipulating of data in the store state object

Register Employee Module Store In Global Store index.js:

All module-level stores need to be registered in index.js file to expose them to the application through a single pipeline of the store.
src/store/index.js:
import Vue from 'vue';
import Vuex from 'vuex';
import employee from './modules/employee';

Vue.use(Vuex);

export default new Vuex.Store({
    modules:{
        employee
    }
})
  • (Line: 9) 'employee' store module registered in the Vuex.Store instance.

Create An Employee Vue Component:

In this sample, we are going to work on employee data, so to display or operate on that data we are going to create an 'Employee.vue' Vue component.
src/components/Employee.vue:
<template>
    <div></div>
</template>

<script>
export default {
    name: "Employee"
}
</script>
Now update the App.vue with our 'Employee' Vue component as follow:
src/App.vue:
<template>
  <div id="app" class="container">
    <h1>Employees</h1>
    <Employee />
  </div>
</template>

<script>
import Employee from './components/Employee.vue'

export default {
  name: 'App',
  components: {
    Employee
  }
}
</script>
  • App.vue component is the root component of our application. All our child component will be registered under this root component
  • (Line: 14) 'Employee' component registered inside with the 'App' Vue component.
In our application folder structure, we can observe the 'Public' folder inside it we can observe the index.html file this our HTML file that's gets loaded on accessing our application. Here we are going to use 'Bootstrap' for design, so add the following style tag on the 'public/index.html' file just above the closing tag of 'head'.
public/index.html:(just above closing tag of head)
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
Now run our Vue application and the output shows as below:

Employee Store Actions To Call API :

Actions meant to be a trigger API calls for an application when using Vuex Store. So now we need to call API to fetch all employees from the test API. After a successful API calls, actions will pass the response data to the store state by calling mutations using the 'commit' command('commit' command triggers mutations).
src/store/module/employee.js:
import axios from "axios";

const state = {};

const getters = {};

const actions = {
    async fetchEmployees(){
        const response = await axios.get("http://dummy.restapiexample.com/api/v1/employees");
        console.log(response.data);
    }
};

const mutations = {};

export default {
    state,
    getters,
    actions,
    mutations
}
  • Axios library will be used for API communication with simple steps in our sample application.
  • (Line: 8-11) In 'actions' we have implemented a method 'fetchEmployees' where we are going to consume the employee API data. For now, we added to console log to check the data later code will update to save the data 'state' object.

Call Store Action From Vue Component:

To load employee data on our application page loads, then need to access the action method into our Vue component.

To access actions Vuex offers 'mapActions' method like a mapper method, which returns actions method references into the Vue component. The 'mapActions' method takes input parameters as an array of names of the action methods. So on specifying the array of actions method all those will be referenced into the Vue component. In our Vue component, 'mapActions' are declared inside of the 'methods' property.
src/components/Employee.vue:
<template>
    <div></div>
</template>

<script>
import { mapActions } from "vuex";
 
export default {
    name: "Employee",
    methods:{
        ...mapActions(['fetchEmployees'])
    },
    created(){
        this.fetchEmployees();
    }
}
</script>
  • (Line: 6) mapAction got imported from the Vuex Library.
  • (Line: 10-12) mapAction that takes the input parameter as an array of action names and it was declared inside of the Vue component 'method' object. After initializing the mapAction method then all the action functions can be accessed using component 'this' scope.
  • (Line: 13-15) 'Created' method is a life-cycle method of the Vue component which will be executed on the creation of the component. So here we will try to invoke the employee API by calling the actions related function like 'fetchEmployess'.
Now run the application and check the browser console check the output as below:

Action Use Commit Command To Save Response Data To State Object:

To save or update the data to state object is only done by using the mutations. But actions should not call mutations directly. So actions use the 'commit' command which will indirectly invoke the mutations.
src/store/module/employee.js:
import axios from "axios";

const state = {
    employees = []
};

const getters : {};

const actions = {
    async fetchEmployees({commit}){
        const response = await axios.get("http://dummy.restapiexample.com/api/v1/employees");
        commit('setEmployees', response.data.data);
    }
};

const mutations = {
    setEmployees:(state,data) => {
        state.employees = data;
    }
};

export default {
    state,
    getters,
    actions,
    mutations
}
  • (Line: 4) 'employees' property created inside the state object, this property will hold the list of employees.
  • (Line: 17-19) 'setEmployees' method is used to update the state object with the employee's data.
  • (Line: 12) fetchEmployees(actions method) uses the commit command to invoke the mutation. 'commit' command takes input parameters like the mutations method name(like 'setEmployees') as the first parameter and rest API data as the second parameter.

Create Getters To Fetch Data From State:

Need to create Getters to fetch data from the state object.
src/store/modules/employee.js:
import axios from "axios";

const state = {
    employees : []
};

const getters = {
    allEmployees:(state) => state.employees
};

const actions = {
    async fetchEmployees({commit}){
        const response = await axios.get("http://dummy.restapiexample.com/api/v1/employees");
        commit('setEmployees', response.data.data);
    }
};

const mutations = {
    setEmployees:(state,data) => {
        state.employees = data;
    }
};

export default {
    state,
    getters,
    actions,
    mutations
}
  • (Line: 8) 'allEmployees' getter method fetches the employee's data from the state object. Here you can observe the input parameter as a 'state' object, this input parameter will automatically be passed by Vuex internally on invoking or accessing the getters(eg: 'allEmployees' getter)
Now Vue component will access the store getters for data binding. The best way to access the store getters is accessed as computed properties. Because computed properties will always get the latest changes of the data so assigning getters as computed props will help to fetch the latest data to our Vue component.

So Vuex provides 'mapGetter' instance to access the store getters into the Vue component. 'mapGetter' expects an array of getters names as the input parameter. On initializing 'mapGetter' inside of the computed object of VueComponent, then the all getter's names in the array will become the computed properties of the Vue component which means store getters props or method names can be directly used in Vue component as properties for data binding.
src/components/Employee.vue:
<template>
  <div class="row">
    <div class="card" style="width: 18rem;" v-for="emp in allEmployees" v-bind:key="emp.id">
      <div class="card-header">{{emp.employee_name}}</div>
<ul class="list-group list-group-flush"> <li class="list-group-item">Salary: {{emp.employee_salary}}</li> <li class="list-group-item">Age: {{emp.employee_age}}</li> </ul> </div> </div> </template> <script> import { mapActions, mapGetters } from "vuex"; export default { name: "Employee", methods: { ...mapActions(["fetchEmployees"]) }, computed: { ...mapGetters(["allEmployees"]) }, created() { this.fetchEmployees(); } }; </script>
  • (Line: 23) using mapGetters, store getter properties, or method is declared inside of the Vue component computed object. On doing this mapGetters initialization now 'allEmployees' will become as the computed property of the 'Employee.vue' Vue component.
  • (Line: 3) 'allEmployees' computed property object is used for the data binding.
Now run the application and the output shows below:

Update Employee Store For Adding New Employee: 

Now update the employee module store for creating the new employee as follow:
src/store/modules/employee.js:
// code hidden for display purpose

const actions = {
  async addEmployee({ commit }, newEmployee) {
     // Note:-
     // Dummy Rest API Example create API returning returning cross-orgin issue
     // so i'm explaining by mocking data here
     
    //   const response = await axios.post("http://dummy.restapiexample.com/create", newEmployee);
    //   commit('addEmployee', response.data);


      const mapNewEmployee = {
          id:0,
          employee_name: newEmployee.name,
          employee_salary: newEmployee.salary,
          employee_age: newEmployee.age,
          profile_image:""
      }
      commit('addEmployee', mapNewEmployee);
  },
};

const mutations = {
  addEmployee:(state, data) => state.employees.unshift(data)
};

  • Note: Dummy Rest API Create endpoint has an issue of cross-origin. So here we implementing in static approach for understanding Vuex.
  • (Line: 21) 'addEmployee' action method committing new employee data to 'addEmployee' method in mutation object using the 'commit' command.
  • (Line: 26) 'addEmployee' mutation method changing the state of the 'employees' object by adding the new employee object at the top of the 'employees' object collection. 'ushift' javascript method is used to add the new employee record at the top.

Create A AddEmployee Vue Component:

Now we are going to create a new Vue component named 'AddEmployee' which contains a simple form for creating new employees by using 'addEmployee' method from the store actions.
src/components/AddEmployee.vue:
<template>
  <div>
    <form>
      <div class="form-row">
        <div class="col">
          <input type="text" class="form-control" placeholder="Name" v-model="employee.name" />
        </div>
        <div class="col">
          <input type="text" class="form-control" placeholder="age" v-model="employee.age" />
        </div>
        <div class="col">
          <input type="text" class="form-control" placeholder="salary" v-model="employee.salary" />
        </div>
        <div class="col">
          <button type="button" class="btn btn-success" @click="save()">Save</button>
        </div>
      </div>
    </form>
  </div>
</template>

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

export default {
  name: "AddEmployee",
  data: function() {
    return {
      employee: {
        id: 0,
        name: "",
        age: "",
        salary: ""
      }
    };
  },
  methods: {
    ...mapActions(["addEmployee"]),
    save: function() {
      this.addEmployee(this.employee);
      this.resetEmployee();
    },
    resetEmployee: function() {
        this.employee = {
            id:0,
            name: "",
            age: "",
            salary: ""
        };
    }
  }
};
</script>
  • (Line: 27-36) 'data' property of the Vue component contains all the model properties for the data binding.
  • (Line: 38) fetches the store action method
  • (Line: 39-42)The 'save' method gets invoked on clicking the save button on the form.
  • (Line: 43-50) 'resetEmployee' method to reset form with empty fields after saving the item.
Now register the 'AddEmployee' component inside of the 'Employee' component.
src/component/Employee.vue:
<template>
  <div>
    <AddEmployee />
    <br/>
    <div class="row">
      
    </div>
  </div>
</template>

<script>
import AddEmployee  from "./AddEmployee.vue";

export default {
  // code hidden for display purpose
  name: "Employee",
  components: {
    AddEmployee
  },
};
</script>
  • (Line: 18) 'AddEmployee' registered inside of the 'Employee.vue' component
  • (Line: 3) added 'AddEmployee' component HTML tag.
Now run the application and see the output of  newly added item in the list as below:

Here in the image, we can observe that newly added items automatically updated to the list this happens because store getters are assigned to the computed properties of the Vue component.

Update Existing Employees Using Store:

In previous steps fetch and creating operation of employee data done using the store. Now we are going to write the logic for updating the employee data using the store.

src/store/modules/employee.js:
const state = {
  employees: [],
  employeeToUpdate: null,
  operation:"Add"
};
  • In the sample, we are developing we have 2 Vue components like 'Employee' and 'AddEmployee'. The 'Employee' component has a list of employees and the 'AddEmployee' has form fields either to create or update the employee. So on clicking the edit button on the list of an employee on the 'Employee' Vue component needs to pass the data of the employee to be edited to the 'AddEmployee' Vue component. So sharing data between components will be done with the store we are developing here.
  • (Line: 3) 'employeeToUpdate' property of the store state to hold the employee information that will be used to share the data between from 'Employee' component to the 'AddEmployee' component.
  • (Line: 4) 'operation' property of the store state to hold the information of operation like 'Add' or 'Update' using this information 'save' button on the 'AddEmployee' component will execute its tasks conditionally.
src/store/modules/employee.js:
const mutations = {
  setEmployeeToUpdate: (state,data) => {
    state.employeeToUpdate = data.employeeToUpdate;
    state.operation = data.operationName;
    return state;
  },
};
  • 'setEmployeeToUpdate' is a method of store mutations, in this method we are updating the store state object properties like 'employeeToUpdate' and 'operation'. 
  • Mostly methods of mutation take 2 input parameters, a 1st parameter is a state object this parameter is automatically passed by Vuex on invoking the mutations method using the 'commit' command. 2nd parameter like our application input param like data that need to updated in-store, if we have multiple data points to be passed to the mutation function then all those properties will be passed single javascript object literal parameter.
src/store/modules/employee.js:
const actions = {
  setEmployeeToUpdate({ commit },data) {
    commit("setEmployeeToUpdate",data);
  },
};
  • 'setEmployeeToUpdate' in-store actions method, for action method Vuex by default passes an object literal as 1st input parameter to the method in action method if needed and inside of the object literal 'commit' command is defined.
  • The 'commit' command is used to invoke the 'mutation' methods. The 'commit' command takes 2 types of input parameters like 1st parameter is the name of the function of the mutations to be invoked and 2nd parameter is the data that needs to save into the store state.
src/store/modules/employee.js:
const getters = {
  findEmployeeById: (state) =>(id) => {
    var employee = state.employees.filter((e) => {
      if (e.id === id) {
        return e;
      }
    });
    return employee[0];
  }
};
'findEmployeeById' is the property of the getters of the store. Here fetching the employee by id and this employee object will be stored in the state of object property like 'employeeToUpdate'. getters are purely properties but to pass a parameter to the getters its return type needs to function like above code.

src/components/Employee.vue:
<script>
import { mapActions, mapGetters } from "vuex";
export default {
  methods: {
    ...mapActions(["setEmployeeToUpdate"]),
    edit:function(id){
      var employee = this.findEmployeeaById(id);
      this.setEmployeeToUpdate({employeeToUpdate : employee,operationName:"Update"});
    }
  },
  computed: {
    ...mapGetters(["findEmployeeById"])
  },
};
</script>
  • (Line: 5) Using 'mapActions' loaded 'setEmployeeToUpdate' store action in to the Vue components methods.
  • (Line: 12) Using 'mapGettes' loaded 'findEmployeeById' store getter into Vue components computed properties. Getters always assigned to computed properties because they maintain the latest changes or track the latest changes.
  • (Line: 6-9) The 'edit' method gets invoked on the edit button on the employee box with employee id as an input parameter. Uses 'findEmployeeById' action getter to fetch data. Then fetched data is passed to 'setEmployeeToUpdate' action along with additional info like operational(eg: add or update)
src/components/Employee.vue:
<button type="button" class="btn btn-success" @click="edit(emp.id)">Edit</button>
Employee edit button with 'edit' click event with employee id as an input parameter.

src/store/modules/employee.js:
const getters = {
  getOperation: (state) => state.operation,
  getEmployeeToUpdate:(state) => state.employeeToUpdate
};
  • 'getOperation', 'getEmployeeToUpdate' are store getters. These values are set in the 'Employee' Vue component and these getters will be used in the AddEmployee Vue component. 
  • 'getOperation' getter fetches the value of operation property its value more likely either add or update that defines employee creation or update functionality. 'getEmployeeToUpdate' getter fetches the employee data that need to be updated.
src/components/AddEmployee.vue:
<script>
import {  mapGetters } from "vuex";

export default {
  name: "AddEmployee",
  data: function() {
    return {
      employee: {
        id: 0,
        name: "",
        age: "",
        salary: ""
      }
    };
  },
  computed: {
    ...mapGetters(["getOperation", "getEmployeeToUpdate"])
  },
  watch: {
    getEmployeeToUpdate: function() {
      if (this.getOperation && this.getOperation.toLowerCase() === "update") {
        this.employeeToUpdate();
      } else {
        this.resetEmployee();
      }
    }
  },
  methods: {
    employeeToUpdate: function() {
      if (this.getEmployeeToUpdate) {
        this.employee.name = this.getEmployeeToUpdate.employee_name;
        this.employee.age = this.getEmployeeToUpdate.employee_age;
        this.employee.salary = this.getEmployeeToUpdate.employee_salary;
        this.employee.id = this.getEmployeeToUpdate.id;
      }
    },
    resetEmployee: function() {
      this.employee = {
        id: 0,
        name: "",
        age: "",
        salary: ""
      };
    }
  }
};
</script>
  • (Line: 17) 'mapGetters' load the 'getOperation', 'getEmployeeToUpdate' into component computed properties. On assigning getters in computed props they will become the computed property of the Vue component.
  • (Line: 19) Vue component Watch object is to observe the changes of the data in computed properties
  • (Line: 20-26) 'getEmployeeToUpdate' property changes are watched to update the employee data in the form. 'getOperation' returns 'Update' value then form act as updating form or on returning 'Add' form act as employee creator.
src/store/module/employee.js:
const actions = {
  async updateEmployee({commit}, data){
    // Note:-
    // Dummy Rest API Example create API returning returning cross-orgin issue
    // so i'm explaining by mocking data here

    // const response = await axios.put(`http://dummy.restapiexample.com/update/${data.id}`, data);
    //   commit('addEmployee', response.data);
    const updateEmp = {
      id: data.id,
      employee_name: data.name,
      employee_salary: data.salary,
      employee_age: data.age,
      profile_image: "",
    };
    commit('updatedEmployee',updateEmp)
  }
};
The 'Update' action method is used to update the rest API to save the updated employee on the server. But our dummy rest API returning a cross-origin issue so we are implementing a static way to understand the Vuex. Finally calling mutation function 'updatedEmployee' using the 'commit' command along with bypassing the updated employee data.

src/store/modules/employee.js:
const mutations = {
  updatedEmployee:(state,data) => {
    var employees = state.employees.filter((e) => {
      if (e.id !== data.id) {
        return e;
      }
    });
    employees.unshift(data);
    state.employees = employees;
    return state;
  }
};
Here removing the old object and assigning the newly updated object at the top of the list of store state objects.

src/components/AddEmployee.vue:
export default {

  methods: {
    ...mapActions(["addEmployee","updateEmployee","setEmployeeToUpdate"]),
    save: function() {
      if (this.getOperation.toLowerCase() === "add") {
        this.addEmployee(this.employee);
      }else{
        this.updateEmployee(this.employee);
      }
      this.setEmployeeToUpdate({ employeeToUpdate: null, operationName: "Add" });
      this.resetEmployee();
    },
  }
}
  • The 'save' method is update to do 2 different tasks like creating employee or updating employee based on the 'getOperation' value.
  • (Line: 11) After successful create or update the value of 'operationName' reset back to 'Add'.
Now the full implementation of the update employee-store looks as below:
src/store/modules/employee.js:
import axios from "axios";

const state = {
  employees: [],
  employeeToUpdate: null,
  operation:"Add"
};

const getters = {
  allEmployees: (state) => state.employees,
  findEmployeeById: (state) =>(id) => {
    var employee = state.employees.filter((e) => {
      if (e.id === id) {
        return e;
      }
    });
    return employee[0];
  },
  getOperation: (state) => state.operation,
  getEmployeeToUpdate:(state) => state.employeeToUpdate
};

const actions = {
  async fetchEmployees({ commit }) {
    const response = await axios.get(
      "http://dummy.restapiexample.com/api/v1/employees"
    );
    commit("setEmployees", response.data.data);
  },
  async addEmployee({ commit }, newEmployee) {
    // Note:-
    // Dummy Rest API Example create API returning returning cross-orgin issue
    // so i'm explaining by mocking data here

    //   const response = await axios.post("http://dummy.restapiexample.com/create", newEmployee);
    //   commit('addEmployee', response.data);

    const mapNewEmployee = {
      id: 0,
      employee_name: newEmployee.name,
      employee_salary: newEmployee.salary,
      employee_age: newEmployee.age,
      profile_image: "",
    };
    commit("addEmployee", mapNewEmployee);
  },
  setEmployeeToUpdate({ commit },data) {
    commit("setEmployeeToUpdate",data);
  },
  async updateEmployee({commit}, data){
    // Note:-
    // Dummy Rest API Example create API returning returning cross-orgin issue
    // so i'm explaining by mocking data here

    // const response = await axios.put(`http://dummy.restapiexample.com/update/${data.id}`, data);
    //   commit('addEmployee', response.data);
    const updateEmp = {
      id: data.id,
      employee_name: data.name,
      employee_salary: data.salary,
      employee_age: data.age,
      profile_image: "",
    };
    commit('updatedEmployee',updateEmp)
  }
};

const mutations = {
  setEmployees: (state, data) => {
    state.employees = data;
  },
  addEmployee: (state, data) => state.employees.unshift(data),
  setEmployeeToUpdate: (state,data) => {
    state.employeeToUpdate = data.employeeToUpdate;
    state.operation = data.operationName;
    return state;
  },
  updatedEmployee:(state,data) => {
    var employees = state.employees.filter((e) => {
      if (e.id !== data.id) {
        return e;
      }
    });
    employees.unshift(data);
    state.employees = employees;
    return state;
  }
};

export default {
  state,
  getters,
  actions,
  mutations,
};
src/components/Employee.vue:
<template>
  <div>
    <AddEmployee />
    <br/>
    <div class="row">
      <div class="card" style="width: 18rem;" v-for="emp in allEmployees" v-bind:key="emp.id">
        <div class="card-header">{{emp.employee_name}}</div>
        <ul class="list-group list-group-flush">
          <li class="list-group-item">Salary: {{emp.employee_salary}}</li>
          <li class="list-group-item">Age: {{emp.employee_age}}</li>
        </ul>
        <div>
          <button type="button" class="btn btn-success" @click="edit(emp.id)">Edit</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { mapActions, mapGetters } from "vuex";
import AddEmployee  from "./AddEmployee.vue";

export default {
  name: "Employee",
  components: {
    AddEmployee
  },
  methods: {
    ...mapActions(["fetchEmployees", "setEmployeeToUpdate"]),
    edit:function(id){
      var employee = this.findEmployeeById(id);
      this.setEmployeeToUpdate({employeeToUpdate : employee,operationName:"Update"});
    }
  },
  computed: {
    ...mapGetters(["allEmployees","findEmployeeById"])
  },
  created() {
    this.fetchEmployees();
  }
};
</script>  
src/components/AddEmployee.vue:
<template>
  <div>
    <form>
      <div class="form-row">
        <div class="col">
          <input type="text" class="form-control" placeholder="Name" v-model="employee.name" />
        </div>
        <div class="col">
          <input type="text" class="form-control" placeholder="age" v-model="employee.age" />
        </div>
        <div class="col">
          <input type="text" class="form-control" placeholder="salary" v-model="employee.salary" />
        </div>
        <div class="col">
          <button type="button" class="btn btn-success" @click="save()">Save</button>
        </div>
      </div>
    </form>
  </div>
</template>

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

export default {
  name: "AddEmployee",
  data: function() {
    return {
      employee: {
        id: 0,
        name: "",
        age: "",
        salary: ""
      }
    };
  },
  computed: {
    ...mapGetters(["getOperation", "getEmployeeToUpdate"])
  },
  watch: {
    getEmployeeToUpdate: function() {
      if (this.getOperation && this.getOperation.toLowerCase() === "update") {
        this.employeeToUpdate();
      } else {
        this.resetEmployee();
      }
    }
  },
  methods: {
    ...mapActions(["addEmployee","updateEmployee","setEmployeeToUpdate"]),
    save: function() {
      if (this.getOperation.toLowerCase() === "add") {
        this.addEmployee(this.employee);
      }else{
        this.updateEmployee(this.employee);
      }
      this.setEmployeeToUpdate({ employeeToUpdate: null, operationName: "Add" });
      this.resetEmployee();
    },
    employeeToUpdate: function() {
      if (this.getEmployeeToUpdate) {
        this.employee.name = this.getEmployeeToUpdate.employee_name;
        this.employee.age = this.getEmployeeToUpdate.employee_age;
        this.employee.salary = this.getEmployeeToUpdate.employee_salary;
        this.employee.id = this.getEmployeeToUpdate.id;
      }
    },
    resetEmployee: function() {
      this.employee = {
        id: 0,
        name: "",
        age: "",
        salary: ""
      };
    }
  }
};
</script>
Now run the application and click on any employee item to edit then output shows below.

Edit employee info as below:

Now save the edited information and output shows as below:

Delete Operation With Store:

The final crud operation we are going to do with our sample is to delete employees.
src/store/module/employee.js:
const actions = {
  async deleteEmployee({commit}, id){
    // Note:-
    // Dummy Rest API Example delete API returning returning cross-orgin issue
    // so i'm explaining by mocking data here
    // const response = await axios.delete(`http://dummy.restapiexample.com/v1/delete/${data.id}`)
    commit('deleteEmployee', id);
  }
};

const mutations = {
  deleteEmployee:(state, id) =>{
    var employees = state.employees.filter((e) => {
      if (e.id !== id) {
        return e;
      }
    });
    state.employees = employees;
    return state;
  }
};
  • (Line: 2-8) 'deleteEmploye' action method call the rest API to delete the employee. Here our Dummy Rest API returning cross-origin issue, so we are implementing the process in a static way to understand the delete operation in the store. The 'commit' command is used to call 'deleteEmployee' mutation method with id passing as the parameter.
  • (Line: 12-20) 'deleteEmployee' mutation method changes the state of the store object by removing the employee matches with the input parameter id.
src/components/Employee.vue:
<template>
  <div>
    <AddEmployee />
    <br />
    <div class="row">
      <div class="card" style="width: 18rem;" v-for="emp in allEmployees" v-bind:key="emp.id">
        
        <div>
          <button type="button" class="btn btn-danger" @click="deleteEmp(emp.id)">Edit</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
// some code hidden for displya purpose
import { mapActions, mapGetters } from "vuex";
import AddEmployee from "./AddEmployee.vue";

export default {
  methods: {
    ...mapActions(['deleteEmployee']),
    deleteEmp: function(id) {
      this.deleteEmployee(id);
    }
  }
};
</script>
  • (Line: 9) 'delete' button added in Employee.vue component and to it clicks the event assign 'deleteEmp' method by passing id as the input parameter to it.
  • (Line: 23) 'mapAction' loads store 'deleteEmployee' action method.
  • (Line: 24-26) 'deleteEmp' method that's triggered on clicking the 'Delete' button.

Wrapping Up:

Hopefully, I think this article delivered some useful information about Vuex Store Management implementation. I love to have your feedback, suggestions, and better techniques in the comment section below.

Refer:

Follow Me:

Comments

Popular posts from this blog

Endpoint Routing In Asp.Net Core

How Routing Works In  Core 2.1 And Below Versions?: In Asp.Net Core routing is configured using app.UseRouter() or app.UseMvc() middleware. app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); Here in Dotnet Core version 2.1 or below versions on the execution of route middleware request will be navigated appropriate controller matched to the route.

An operation or functionality which is dependent on route URL or route values and that need to be implemented before the execution of route middleware can be done by accessing the route path from the current request context as below
app.Use(async (context, next) => { if(context.Request.Path.Value.IndexOf("oldvehicle") != -1) { context.Response.Redirect("vehicle"); } else { await next(); } }); app.UseMvc(routes => { routes.MapRoute( name: "vehicleRoute", template: "vehicle", defaults:new { …

GraphQL API Integration In Asp.Net Core Application

Introduction:
GraphQL is a query language for your API and a server-side runtime for executing queries by using a type system you define for your data. GraphQL can be integrated into any framework like ASP.NET, Java, NestJs, etc and it isn't tied to any specific database or storage engine and is instead backed by your existing code and data.
How GraphQL API Different From Rest API: GraphQL exposes a single end-point or route for the entire application, regardless of its responses or actions.HTTP-POST is the only Http verb recommended by the GraphQL.The client applications (consumers of API) can give instructions to GraphQL API about what type of properties to be returned in the response. Building Blocks Of GraphQL API:The main building blocks of GraphQL API is Schemas and Types. A 'Schema' in GrpahQL API describes the functionality available to the clients connect to API. Schema mostly consists of GraphQL Object Types, Queries, Mutations, etc.Types likely to be called Grap…

ASP.NET Core Web API Versioning

Introduction: An iteration and evolutionary changes of an ASP.NET Core Web API is handled by Versioning. Versioning of an API gives confidence to the clients which consumes API for a long time. Any changes or development of an API will be accessible using the new version and it won't cause issues to the clients consuming the old version of API.
When To Use Versioning:Any API response changes.Developing an API by implementing testing levels like 'Alpha', 'Beta', and 'RC' versions before releasing Production.Deprecating an API which means API going to be removed or upgraded by a version within a short period. Versioning Types:Query String VersioningUrl Path VersioningMedia Type Versioning API Version Nuget: To Configure versioning to AspNet Core Web API Microsoft provided a library(Microsoft.AspNetCore.Mvc.Versioning). So to use the versioning library please install NuGet below.
 Install-Package Microsoft.AspNetCore.Mvc.Versioning -version 4.0.0 Register API V…

.NET Core MVC Application File Upload To Physical Location With Buffered Technique

Buffering Technique In File Upload:The server will use its Memory(RAM) or Disk Storage to save the files on receiving a file upload request from the client. Usage of Memory(RAM) or Disk depends on the number of file requests and the size of the file. Any single buffered file exceeding 64KB is moved from Memory to a temp file on disk. If an application receives heavy traffic of uploading files there might be a chance of out of Disk or RAM memory which leads to crash application. So this Buffer technique used for small files uploading. In the following article, we create a sample for the file uploading using .NET Core MVC application.
Create The .NET Core MVC Project: Let's create a .NET Core MVC project, here for this sample I'm using Visual Studio Code as below.  Check the link to use the Visual Studio Code for .NET Core Application.
IFormFile: Microsoft.AspNetCore.Http.IFormFile used for file upload with buffered technique. On uploading files from the client, then the entire …

Ionic Picker Sample Code In Angular

Introduction: Ionic Picker(ion-picker) is a popup slides up from the bottom of the device screen, which contains rows with selectable column separated items.
The main building block of ion-picker as follows: PickerControllerPickerOptions PickerController: PickerController object helps in creating an ion-picker overlay. create(opts?: Opts): Promise<Overlay> PickerController create method helps in create the picker overlay with the picker options
PickerOptions: PickerOptions is a configuration object used by PickerController to display ion-picker.
Single Column Ionic Picker: single.item.picker.ts: import { Component } from "@angular/core"; import { PickerController } from "@ionic/angular"; import { PickerOptions } from "@ionic/core"; @Component({ selector: "single-column-picker", templateUrl:"single.item.picker.html" }) export class SingleItemPicker { animals: string[] = ["Tiger", "Lion", "Elephant"…

Asp.Net Core MVC Form Validation Techniques

Introduction: Form validations in any applications are like assures that a valid data is storing on servers. All programing frameworks have their own individual implementations for form validations. In Dotnet Core MVC application server-side validations carried on by the models with the help of Data Annotations and the client-side validations carried by the plugin jQuery Unobtrusive Validation. jQuery Unobtrusive Validation is a custom library developed by Microsoft based on the popular library jQuery Validate.
In this article, we are going to learn how the model validation and client-side validation works in Asp.Net Core MVC Application with sample examples.
Getting Started: Let's create an Asp.Net Core MVC application project using preferred editors like Microsoft Visual Studio or Microsoft Visual Studio Code. Here I'm using Visual Studio.
Let's create an MVC controller and name it as 'PersonController.cs' and add an action method as below.
PersonController.cs: us…

Blazor WebAssembly Dynamic Form Validation

Introduction: In Blazor WebAssembly(client-side framework) form validation can be done with Data Annotations. Using Data Annotations we can validate form either by default validation attributes or by creating custom validation attributes. Using this Data Annotation attribute we can dynamically add or remove validation on a specific field in a form.
Create Blazor WebAssembly Project: To create a Blazor WebAssembly template project need to install the latest version of VisualStudio 2019 for rich intelligence support or we can use VisualStudio code but less intelligence support from the editor. Click here to know about Blazor WebAssembly template creation. Blazor WebAssembly is in preview mode, not yet ready for production.
Create Razor Component: After creating a sample project using the Blazor WebAssembly template, in "Pages" folder add new Razor Component, name it as "UserForm.razor"
Add Route: In Blazor routing can be configured using @page  directive, and URL should b…

Blazor Server CRUD Operations

Introduction: Blazor Server is a web framework to develop server-side single-page applications. Blazor is made up of components with the combinations on C#, Html, CSS.  Blazor Server is production-ready from the .Net Core 3.0.  Blazor Server Working Mechanism:Blazor Server is a very light-weight web development framework. In Blazor Server, not all code gets downloaded to the client browsers. Blazor Server made of components these components can be a block of code or page with respective navigation. Blazor server application communicates with the server with a SignalR background connection which is inbuilt functionality. Application click,  form submission, change events, application page navigation every operation is carried out by the SignalR connection by communicating with the server. Blazor updates the Html DOM very gently on every data update without any overhead. Blazor Server application maintains a nice intelligent tree structure to update the required information or changed …

NestJS API CRUD Operations With MongoDB

Introduction: NestJS is a framework used to develop server-side applications. NestJS built on top of Node.js frameworks like Express. It is a combination of Progressive Javascript, Object-Oriented Programming, Functional Programming, and Functional Reactive Programming.
Nest CLI Installation: Using Nest CLI we are able to generate the NestJS starter project with the default template. To install Nest CLI globally over our system open command prompt and run the command
npm i -g @nestjs/cli Now create a sample project by using Nest CLI command  nest new your_project_name package.json: Now open the package.json file from the sample application created, you can observe few properties like "scripts", "dependencies", and "devDependencies".
"dependencies" contains all plugins to be installed and used them to run the application.
"devDependencies" contain all plugins to be installed and used them at the time of application development.
"scrip…

How Response Caching Works In Asp.Net Core

What Is Response Caching?: Response Caching means storing of response output and using stored response until it's under it's the expiration time. Response Caching approach cuts down some requests to the server and also reduces some workload on the server. Response Caching Headers: Response Caching carried out by the few Http based headers information between client and server.
Main Response Caching Headers are like below
Cache-ControlPragmaVary Cache-Control Header: Cache-Control header is the main header type for the response caching. Cache-Control will be decorated with the following directives. public - this directive indicates any cache may store the response.private - this directive allows to store response with respect to a single user and can't be stored with shared cache stores.max-age - this directive represents a time to hold a response in the cache.no-cache - this directive represents no storing of response and always fetch the fresh response from serverno-store…