5

I'm looking for a simple solution for the following problem:

I have a Vue component button with which I can make an ajax request. I would like to disable this button while the request is pending (to prevent multiple requests).

5
  • "I don't want to maintain the request state inside the button component" <- not entirely sure what this means. I'd use :disabled="someBooleanDataValue" and set this.someBooleanDataValue appropriately Commented Aug 22, 2018 at 13:08
  • How is the AJAX request made? Directly in the component or via a Vuex action? Commented Aug 22, 2018 at 13:11
  • I send the request via a vuex action Commented Aug 22, 2018 at 13:14
  • So the button dispatches the action? Commented Aug 22, 2018 at 13:14
  • yes, the button dispatches the action Commented Aug 22, 2018 at 13:18

3 Answers 3

13

Sounds like you want your action to set (commit) a flag when it starts and then clear it when it ends.

Try something like this in Vuex...

state: {
  loading: false
},
mutations: {
  isLoading (state) {
    state.loading = true
  },
  doneLoading (state) {
    state.loading = false
  }
},
actions: {
  doAjaxRequest ({ commit }) {
    commit('isLoading')
    return doSomeAjaxRequest().then(res => {
      // success
    }).catch(err => {
      // oh noes
    }).finally(() => {
      commit('doneLoading')
    })
  }
}

Now in your component, you can map the loading state and use it to disable your button, eg

<template>
  <button :disabled="loading" @click="doAjaxRequest">Do AJAX!</button>
</template>
<script>
  import { mapState, mapActions } from 'vuex'
  export default {
    computed: mapState(['loading']),
    methods: mapActions(['doAjaxRequest'])
  }
</script>

Alternatively, you can maintain the progress of the request within your component if your action returns a promise (as above). For example, say your button has

<button :disabled="loading" @click="doTheThing">Do the thing!</button>

and

data () {
  return { loading: false }
},
methods: {
  doTheThing() {
    this.loading = true
    this.$store.dispatch('someAjaxActionThatReturnsAPromise').finally(() => {
      this.loading = false
    })
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Alternative way has been worked for me. Thanks. How to show success message after async request complete?
0

State.js:

state: {
  pendingRequest: false
},
actions: {
  fetchRequest: async function(context) {
    context.state.pendingRequest = true
    let req = await fetch(url)
    let data = await req.json()
    context.state.pendingRequest = false
  }
}

Component.vue:

<button :disabled='$store.state.pendingRequest' @click="$store.dispatch('fetchRequest')">Button</button>

6 Comments

state mutations should always be done via a commit. I'm not even sure Vuex will let you directly manipulate state on the context
It will let directly manipulate state on the context, but I agree with you, it's not the best practice.
You can skip the action but not the mutation.
Are you sure about that? Says here it's read-only. If it actually works, I doubt it's reactive
Because your fiddle used the minified version of vuex.js, all errors were suppressed. Here it is, throwing errors ~ jsfiddle.net/r1z0a4gp/8
|
-1

I found another solution: It automatically generates a vuex module for the registered endpoints, watch those endpoints via axios interceptors and sets the proper 'pending' state values based on the status of the related requests.

https://github.com/pharkasbence/pending-request-tracker

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.