What is the best way to refresh VUE components while executing a promise?

Seeking assistance with updating the DOM to display a loading element while a login screen is submitted and stopping it when errors occur. Struggling to figure out how to update the DOM when the promise resolves using Vue.js, Vuex, and Vuetify. Setting a variable on the state in vuex doesn't seem to be working as intended, as changing the state affects all loading elements visibility.

Tried various solutions and searched online but couldn't find examples matching our use case due to starting from a boilerplate code.

Here's the front-end code:

<template>
  <div class="auth-page">
    <div class="container page">
      <div class="row">
        <div class="col-md-6 offset-md-3 col-xs-12">
          <h1 class="text-xs-center">Login</h1>
          <p class="text-xs-center"></p>
          <ul v-if="errors" class="error-messages">
            <li v-for="(v, k) in errors" :key="k">{{ v.detail }}</li>
          </ul>
          <form v-on:submit.prevent="onSubmit(email, password);">
            <fieldset class="form-group">
              <input
                class="form-control form-control-lg"
                type="text"
                v-model="email"
                placeholder="Email"
              />
            </fieldset>
            <fieldset class="form-group">
              <input
                class="form-control form-control-lg"
                type="password"
                v-model="password"
                placeholder="Password"
              />
            </fieldset>
            <v-progress-circular
              right
              :size="30"
              color="black"
              indeterminate
              v-show="isLoading"
            ></v-progress-circular>
            <button
              class="btn btn-lg btn-primary pull-xs-right"
              style="background:black; border-color:black"
            >
              Login
            </button>
          </form>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { mapState } from "vuex";
import { LOGIN } from "@/store/actions.type";

export default {
  name: "RwvLogin",
  data() {
    return {
      email: null,
      password: null,
      isLoading: false
    };
  },
  methods: {
    onSubmit(email, password) {
      this.isLoading = true;
      this.$store
        .dispatch(LOGIN, { email, password })
        .then(() => this.$router.push({ name: "policies" }))
        .catch((e) => {
          console.log(e);
          this.isLoading = false;
        });
    }
  },
  computed: {
    ...mapState({
      errors: state => state.auth.errors
    })
  }
};
</script>

For the module code:

import ApiService from "@/common/api.service";
import JwtService from "@/common/jwt.service";
import {
  LOGIN,
  LOGOUT,
  REGISTER,
  CHECK_AUTH,
  UPDATE_USER
} from "./actions.type";
import { SET_AUTH, PURGE_AUTH, SET_ERROR } from "./mutations.type";

const state = {
  errors: null,
  user: {},
  isLoading: false,
  isAuthenticated: !!JwtService.getToken()
};

const getters = {
  currentUser(state) {
    return state.user;
  },
  isAuthenticated(state) {
    return state.isAuthenticated;
  },
  isLoading(state) {
    return state.isLoading;
  }
};

const actions = {
  [LOGIN](context, credentials) {
    return new Promise(resolve => {
      ApiService.post("login", credentials)
        .then(({ data }) => {
          context.commit(SET_AUTH, data.access_token);
          resolve(data);
        })
        .catch(({ response }) => {
          if(response.status == 401){
            response.data.errors = [{"status":"401","code":0,"title":"Loginn error","detail":"The password entered is incorrect."}] 
          }
          context.commit(SET_ERROR, response.data.errors);
        });
    });
  },

... (omitted for brevity)

mutations and exports follow...

When clicking submit, the LOGIN function interacts with the API and returns either wrong password or validation errors. Successfully displaying the errors. On submission, this.isLoading = true; and upon encountering an error, this.isLoading = false;.

Looking for guidance on where to implement these changes. Any help would be appreciated!

Answer №1

If you only need a loading feature on this specific page and not on all pages, it's best to handle the isLoading state locally instead of storing it in the vuex store.

One approach is to use the finally method with Promises in your onSubmit function to manage the loading state like so:

onSubmit(email, password) {
  this.isLoading = true;
  this.$store
    .dispatch(LOGIN, { email, password })
    .then(() => this.$router.push({ name: "policies" }))
    .catch((e) => {
      console.log(e);
    }).finally(() => this.isLoading = false);
}

Remember, vuex is designed for managing global states, so be mindful of what states you store there. Understanding the distinction between local and global states will prevent confusion in the long run.

When it comes to global state management, less is often more efficient.

Answer №2

I came up with a clever solution by utilizing a global state variable to toggle the progress bar visibility and updating it whenever there are background actions. You can see the code snippet below for reference.

By implementing this approach, I now have the flexibility to have multiple progress bars on the same page and update specific ones by making minor adjustments to the code.

If anyone proficient in vue.js has any insights or suggestions, please feel free to share them.

<template>
  <div class="auth-page">
    <div class="container page">
      <div class="row">
        <div class="col-md-6 offset-md-3 col-xs-12">
          <h1 class="text-xs-center">Login</h1>
          <p class="text-xs-center"></p>
          <ul v-if="errors" class="error-messages">
            <li v-for="(v, k) in errors" :key="k">{{ v.detail }}</li>
          </ul>
          <form v-on:submit.prevent="onSubmit(email, password);">
            <fieldset class="form-group">
              <input
                class="form-control form-control-lg"
                type="text"
                v-model="email"
                placeholder="Email"
              />
            </fieldset>
            <fieldset class="form-group">
              <input
                class="form-control form-control-lg"
                type="password"
                v-model="password"
                placeholder="Password"
              />
            </fieldset>
            <v-progress-circular
              right
              :size="30"
              color="black"
              indeterminate
              v-show="this.$store.getters.isLoading"
            ></v-progress-circular>
            <button
              class="btn btn-lg btn-primary pull-xs-right"
              style="background:black; border-color:black"
            >
              Login
            </button>
          </form>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { mapGetters } from "vuex";
import { mapState } from "vuex";
import { LOGIN } from "@/store/actions.type";

export default {
  name: "RwvLogin",
  data() {
    return {
      email: null,
      password: null
    };
  },
  methods: {
    onSubmit(email, password) {
      this.$store.commit(SET_LOADING, true);
      this.$store
        .dispatch(LOGIN, { email, password })
        .then(() => this.$router.push({ name: "policies" }));
    }
  },
  mounted() {

  },
  computed: {
    ...mapState({
      errors: state => state.auth.errors
    })
  }
};
</script>
import ApiService from "@/common/api.service";
import JwtService from "@/common/jwt.service";
import {
  LOGIN,
  LOGOUT,
  REGISTER,
  CHECK_AUTH,
  UPDATE_USER
} from "./actions.type";
import { SET_AUTH, PURGE_AUTH, SET_ERROR, SET_LOADING } from "./mutations.type";

const state = {
  errors: null,
  user: {},
  isLoading: false,
  isAuthenticated: !!JwtService.getToken()
};

const getters = {
  currentUser(state) {
    return state.user;
  },
  isLoading(state) {
    return state.isLoading;
  },
  isAuthenticated(state) {
    return state.isAuthenticated;
  }
};

const actions = {
  [LOGIN](context, credentials) {
    return new Promise(resolve => {
      ApiService.post("login", credentials)
        .then(({ data }) => {
          context.commit(SET_AUTH, data.access_token);
          resolve(data);
        })
        .catch(({ response }) => {
          context.commit(SET_LOADING, false);
          if(response.status == 401){
            response.data.errors = [{"status":"401","code":0,"title":"Loginn error","detail":"The password entered is incorrect."}] 
          }
          context.commit(SET_ERROR, response.data.errors);
        });
    });
  },
  [LOGOUT](context) {
    context.commit(PURGE_AUTH);
  },
  [REGISTER](context, credentials) {
    return new Promise((resolve, reject) => {
      ApiService.post("users", credentials)
        .then(({ data }) => {
          context.commit(SET_AUTH, data.access_token);
          resolve(data);
        })
        .catch(({ response }) => {
          context.commit(SET_ERROR, response.data.errors);
          reject(response);
        });
    });
  },
  [CHECK_AUTH](context) {
    if (JwtService.getToken()) {
      // ApiService.setHeader();
      // ApiService.get("user")
      //   .then(({ data }) => {
      //     context.commit(SET_AUTH, data.access_token);
      //   })
      //   .catch(({ response }) => {
      //     context.commit(SET_ERROR, response.data.errors);
      //   });
    } else {
      context.commit(PURGE_AUTH);
    }
  },
  [UPDATE_USER](context, payload) {
    const { email, username, password, image, bio } = payload;
    const user = {
      email,
      username,
      bio,
      image
    };
    if (password) {
      user.password = password;
    }

    return ApiService.put("user", user).then(({ data }) => {
      context.commit(SET_AUTH, data.user);
      return data;
    });
  }
};

const mutations = {
  [SET_ERROR](state, error) {
    state.errors = error;
  },
  [SET_LOADING](state, status) {
    state.isLoading = status;
  },
  [SET_AUTH](state, token) {
    state.isAuthenticated = true;
    state.errors = {};
    state.token = token;
    JwtService.saveToken(state.token);
  },
  [PURGE_AUTH](state) {
    state.isAuthenticated = false;
    state.user = {};
    state.policies = {};
    state.errors = {};
    JwtService.destroyToken();
  }
};

export default {
  state,
  actions,
  mutations,
  getters
};

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

Traversing a series of HTML form elements in order to extract their current values and store them in an object

Suppose we have an HTML structure like this: <nav data-filters class=""> <input type="radio" name="type" value="company" checked>Company <input type="radio" name="type" value="product">Product <input type=" ...

Adjusting the height of the Tinymce Editor in React Grid Layout after the initial initialization

I am facing a challenge with my React Component that displays a tinymce editor. The task is to dynamically adjust the height of the editor after it has been initialized. To achieve this, I am utilizing the "React Grid Layout" package for resizing the compo ...

What is the reason for the neglect of this function's definition?

Is there a reason behind the error message I am receiving? TypeError: getStatusCode(...) is not a function This error occurs when I execute the following code: const getStatusCode = require('./getStatusCode') tmpStatus = await getStatusCode({url ...

Tips for personalizing the NavigatorIOS's right side

Looking to create a navigation bar similar to Whatsapp's? I want to include a profile picture and call button on the right side of the bar. Any tips on how to achieve this look? Which properties should be used for this customization? Would it be bet ...

VueRouter is modifying the route prior to triggering the Vue.beforeCreate function

I've recently started working with vue.js and I'm having trouble initializing the router. My goal is to redirect the user to '/home' when they hit '/' if they are already signed in, otherwise redirect them to '/login&apo ...

Struggling to make PayPal Cordova Plugin function properly in both production and sandbox modes

While using the cordova paypal plugin and switching to sandbox mode, I encountered an error. The plugin can be found at https://github.com/paypal/PayPal-Cordova-Plugin https://i.stack.imgur.com/lD2EH.png Running the plugin in PayPalEnvironmentNoNetwork m ...

Adding methods to a constructor's prototype in JavaScript without explicitly declaring them

In the book Crockford's JavaScript: The Good Parts, there is a code snippet that demonstrates how to enhance the Function prototype: Function.prototype.method = function (name, func) { this.prototype[name] = func; return this; }; Crockford elabo ...

ResizableBox is failing to render any content

My current project involves trying out react-resizable. Unfortunately, my basic example only shows the text XYZ in the browser without displaying any resizable box as expected. There are no error messages either. import { ResizableBox } from 'react-re ...

Console log showing no response from AJAX request

For my group project, I've been working on setting up an API to display a response in the console log. After troubleshooting and fixing errors, I am still not seeing any response when I click submit. JavaScript var zipcode = ""; function localMovie ...

Exploring the power of "then" in AngularJS promises: Jasmine's journey

In my AngularJS controller, I have the following function: service.getPlaceByAddress = function(address) { return $q(function(resolve, reject) { geocoder().geocode({'address': address}, function(result, status) { // gets ...

Integrating Vue with an existing session storage array

I've developed an API that transmits a video along with all its comments, and in the frontend, the video is called on mount. I have implemented a create comment button that triggers a createComment route to add a comment to the video and store it in t ...

Creating an endless variety of modals using HTML - The ultimate guide

Currently, I am in the process of developing a Project Manager website by utilizing w3school's To-do-list tutorial. To enhance the functionality, I have included a detail button (denoted by ...) that triggers a modal displaying task information. Howev ...

Replace the plus signs in a string with spaces using the JSON.stringify method

When utilizing AJAX, I am sending the string someString to a PHP handler. xmlHttp.open("POST", url, true); var someString = 'Foo+Bar'; var params = 'operation='+operation+'&json='+JSON.stringify(someString); xmlHttp.send( ...

The jQuery .val(#) function does not update the selection after an AJAX call, but it functions correctly when debugging or paused

Currently encountering an interesting issue - after executing an AJAX call that updates the Appointment List dropdown with new entries based on page load or a user-entered filter, the .val() method is failing to set the value correctly. The successful exe ...

Create an input field dynamically by utilizing the append method in jQuery

Concern: As part of an edit page, I am working on appending an input field from a modal window to an existing panel while retaining the format of the rest of the fields. The user is currently able to create and add the new field using the code provided in ...

Strategies for testing a split get() function using expressJS and jestJS to streamline unit testing

How can I define a get() route in an Express.js application for easy unit testing? To start, I extracted the get() function into its own file: index.js const express = require('express') const socketIo = require('socket.io') const Gp ...

jQuery simplifies the syntax by using $.ajax() instead of the traditional loadXMLDoc() function to make XMLHTTPRequests

My question is: Is using $.ajax() in jQuery just a way to streamline the normal code structure? $.ajax( {url:"index.php/a", type:"POST", contentType:"application/json; charset=utf-8", data:{some_string:"blabl ...

Encountered an error while attempting to search for '/user/profile' in the views directory

I am currently working on developing a shopping cart using node.js, express.js, and mongodb. I am focusing on setting up the sign-up functionality at the moment. However, when I attempt to access the localhost:3000/user/profile link, I encounter the follow ...

A step-by-step guide on storing JSON data into a variable using NodeJS

Just starting out with Node.js and running into an issue. I need to figure out how to extract and save data from a JSON object retrieved from the GitHub API. var http = require("http"); var express = require('express'); var app = express(); var ...

Validation of input using AngularJS regular expressions

How can I create an AngularJS regex validation that permits alphabets, numbers, spaces, and the special characters ! ' " & - ( )? ...