How to call bootstrap-vue modals and toasts from vuex actions?
Asked Answered
M

5

6

Did anyone tried to use boostrap-vue in combination with vuex? I'm having hard time calling modals and toast from vuex actions.

Obviously I can not use this from vuex store, therefore I can't use:

this.$bvModal.show('modalId');

I also tried calling modal like this

import Vue from 'vue';

Vue.prototype.$bvModal.show('transaction');

But console gives me following warning:

BootstrapVue warn]: '$bvModal' must be accessed from a Vue instance 'this' context

Any idea how I can call modals and toasts from vuex actions directly?

Miyamoto answered 11/8, 2019 at 7:12 Comment(1)
If you're calling the action from a component you can pass the component Vue instance. this.$store.dispatch('myAction', { vm: this }), and you can then use that to access $bvModal in your actionClova
S
7

Try to call this._vm.$bvModal.show('modalId');. Reference.

Spider answered 11/8, 2019 at 7:19 Comment(3)
I've tried it, but it's not working. Just realized that I can use v-model on bootstrap modal so I'll just set state to true to show modalMiyamoto
Though i needed it for a nuxt app to show a toast, ._vm worked for me thanks.Effable
It doesn't work for me either. The this._vm.$bvModal exists, but .show('id' does nothing.Tanager
D
6

I think a better approach is to prevent to deal with the UI from the Store. So, you can add a store property and watch for changes from your components.

In the following example, I added an array toastMessages in the state property and a ADD_TOAST_MESSAGE mutation to add some toastMessage. You can then commit an ADD_TOAST_MESSAGE mutation from another mutation or from an action.

Inside your Top-level component (App.vue), you can watch for your toastMessages state property changes and display the last item that was pushed.

App.vue

<script>
export default {
  name: "App",
  created() {
    this.$store.watch(
      state => state.toastMessages,
      toastMessages => {
        this.$bvToast.toast(this.toastMessages.slice(-1)[0]);
      }
    );
  }
}
</script>

store.js

export default new Vuex.Store({
  state: {
    toastMessages: []
  },
  mutations: {
    ADD_TOAST_MESSAGE: (state, toastMessage) => (state.toastMessages = [...state.toastMessages, toastMessage]),
  },
  actions: {
    myActionThatDoSomething({commit}, params) {
      // Do something
      commit('ADD_TOAST_MESSAGE', "Something happened");
    }
  }
});
Donner answered 2/5, 2020 at 16:13 Comment(0)
J
1

found a solution here: https://github.com/vuejs/vuex/issues/1399#issuecomment-491553564

import App from './App.vue';

const myStore = new Vuex.Store({
    state: {
        ...
    },
    actions: {
        myAction(ctx, data) {
           // here you can use this.$app to access to your vue application
              this.$app.$root.$bvToast.toast("toast context", {
                 title: "toast!"
              });
        }
    }
});

const app = new Vue({
    el: '#my-div',
    render: h => h(App),
    store: myStore
});

myStore.$app = app; // <--- !!! this line adds $app to your store object
Jainism answered 21/4, 2020 at 13:25 Comment(0)
L
0

Using @eroak idea, I have implemented this same thing for vue-sweetalert2.

I have also created a store for my Sweet Alert Toaster, then I am watching a property called ticks that is updated whenever state of the toaster is updated. I am using ticks as I only have one message in my state, and ticks just timestamp when action was triggered.

You can find whole demo here: https://github.com/Uraharadono/CallbackFromVuexAction

Lenard answered 2/4, 2021 at 21:1 Comment(0)
H
-1

Try to call this._vm.$root.$bvModal.show('modalId');

Hectare answered 27/10, 2019 at 17:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.