Call Vue store action through browser console - javascript

I'm trying to create a webapp using VUE Vite with a router and store. The getter function in the vue file works fine. I have access to the chatMessages stored in the store.js file.
My problem is that I need to call the addMessage Action from the store.js file in the dev console using the browser.
Question: How could I archive this?
On older vue versions it would be done the following way using the main.js file:
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import './registerServiceWorker';
import { mapGetters, mapMutations, mapActions } from 'vuex';
Vue.config.productionTip = false;
const app = new Vue({
router,
store,
render: function (h) { return h(App) },
methods: {
...mapMutations([
'showLoading',
]),
...mapActions([
'addNotification',
]),
},
}).$mount('#app');
export default app;
Current vue3 chat.vue file:
<template>
<div></div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
name: 'Chat',
data: function() {
return {
}
},
methods: {
},
computed: {
...mapGetters({
chatMessages: 'chatMessageList',
}),
}
}
</script>
Current vue3 store.js file:
import { createStore } from 'vuex'
export default createStore({
state: {
chatMessages: {
list: [
{ type: "a", message: "test" }
]
}
},
mutations: {
addMessage(state, { type, message }) {
state.chatMessages.list.push({ type: type, message: message });
}
},
actions: {
addMessage({ commit }, { type, message }) {
commit('addMessage', { type, message });
}
},
getters: {
chatMessageList(state, getters) {
return state.chatMessages.list;
}
}
})
Current vue3 main.js file:
import App from "./App.vue";
import {createApp} from "vue";
import router from "./router/index.js";
import store from "./store/store";
import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap/dist/js/bootstrap.js";
window.app = createApp(App).use(router).use(store).mount('#app');
EDIT: I tested it the following way and I can call app.addMessage from the dev console but now the router wont work.
import App from "./App.vue";
import {createApp} from "vue";
import router from "./router/index.js";
import store from "./store/store";
import { mapGetters, mapMutations, mapActions } from 'vuex';
import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap/dist/js/bootstrap.js";
window.app = createApp({
methods: {
...mapActions([
'addMessage',
]),
}
}).use(router).use(store).mount('#app');

Assigning the store to the window object seems like a great approach, where you can easily then call it like in domiatorov's answer.
Another approach is:
var store = Array.from(document.querySelectorAll('*')).find(e => e.__vue_app__).__vue_app__.config.globalProperties.$store;
var actions = store._actions;
actions.addMessage[0]('mytype', 'mymessage');
The first part queries the body for an element containing __vue_app__ and will return your instance. In there, you can access config.globalProperties.$store to return your store object.

store is already available in this scope and can be exposed the same way as app:
window.store = store;
It can be used in console the same way as in an app:
store.dispatch(...)

I believe you can simply assign the store to the window object.
But do it from a top level single file component, the very first that is using the store and not in the setup to make sure the store got everything loaded.
Providing you have something like App.vue:
In setup() you would assign:
window.vueStore = store;
and use it from the console calling window.vueStore.

Related

VueX module not triggering actions

I'm following this tutorial about Vuex Pagination (https://whatthecode.dev/easy-vuejs-vuex-pagination/?utm_source=rss&utm_medium=rss&utm_campaign=easy-vuejs-vuex-pagination)
The only difference is that I changed my API request, however I can retrieve frontend data from state, but can't trigger action. I'm new to VueX, can someone spot the mistake?
PS: It never reaches console.log("Let's get")
store.js
import Vue from 'vue';
import Vuex from 'vuex';
import volumes, { VOLUMES_MODULE } from './volumes';
Vue.use(Vuex);
const store = new Vuex.Store ({
modules: {
[VOLUMES_MODULE]: volumes,
},
});
export default store;
volumes/index.js
import state from './state';
import actions from './actions';
export const VOLUMES_MODULE = 'volumes'
export default {
namespaced: true,
actions,
state,
}
export * from './state'
volumes/actions.js
import VolumeService from '../../services/VolumeService';
import {
SET_DATA,
SET_PAGINATION,
} from './mutations'
import state from './state';
export const FETCH_VOLUMES = 'load_volumes'
const volumeService = new VolumeService();
export default {
async [FETCH_VOLUMES]({ commit }, payload) {
console.log("Let Get");
const volumes = await volumeService.getTwentyVolumes({
...state.pagination,
...payload,
})
commit(SET_DATA, volumes.data)
commit(SET_PAGINATION, {
page: 2,
limit: 20,
totalPages: 2,
})
},
}
volumes/mutations.js
export const SET_PAGINATION = 'set_pagination'
export const SET_DATA = 'set_data'
export default {
[SET_PAGINATION](state, pagination) {
state.pagination = pagination
},
[SET_DATA](state, data) {
state.data = data
},
}
volumes/state.js
export const VOLUMES = 'data'
export const PAGINATION = 'pagination'
export default {
[VOLUMES]: [],
[PAGINATION]: {
page: 1,
limit: 20,
totalPages: 1,
},
}
First check if you have installed store to your view, normally in the main.js where you new a Vue instance, code should be like this:
import Vue from "vue";
import App from "./App.vue";
import store from "./store";
Vue.config.productionTip = false;
new Vue({
store,
render: (h) => h(App)
}).$mount("#app");
Then in the component where you want to call the load_volumes, use mapActions to add this function. code sample:
<script>
import {mapActions} from 'vuex'
export default {
name: "App",
components: {
},
methods: {
...mapActions({load_volumes: 'volumes/load_volumes'})
},
mounted(){
this.load_volumes()
}
}
</script>
working example can be found here:
https://codesandbox.io/s/call-vuex-actions-in-components-msdyo

Vuejs register component and getting did you register the component correctly? error

In one of our project i try to use vuejs-countdown-timer component, but i get this error
Unknown custom element: - did you register the component
correctly? For recursive components, make sure to provide the "name"
option.
in this package documentation we have:
//Installation
npm i vuejs-countdown-timer -S Import component
// global register at main.js import VueCountdownTimer from
'vuejs-countdown-timer';
Vue.use(VueCountdownTimer);
and basic usage of that:
<template>
<vue-countdown-timer
#start_callback="startCallBack('event started')"
#end_callback="endCallBack('event ended')"
:start-time="'2018-10-10 00:00:00'"
:end-time="1481450115"
:interval="1000"
:start-label="'Until start:'"
:end-label="'Until end:'"
label-position="begin"
:end-text="'Event ended!'"
:day-txt="'days'"
:hour-txt="'hours'"
:minutes-txt="'minutes'"
:seconds-txt="'seconds'">
</vue-countdown-timer>
</template>
<script >
export default {
name: 'Timer',
methods: {
startCallBack: function(x) {
console.log(x);
},
endCallBack: function(x) {
console.log(x);
},
},
};
</script>
now after installing the package i imported into my app.js:
import Vue from 'vue'
import VueCountdownTimer from 'vuejs-countdown-timer';
Vue.use(Vuelidate)
Vue.use(VueCountdownTimer)
window.Vue = require('vue').default
import Timer from './components/partials/timer.vue'
new Vue({
store,
components: {
Timer,
//
}, computed: {}, mount: {}
}).$mount('#app')
and after that i try to use into html template as:
<login inline-template>
<div class="page-content">
<div class="content-wrapper">
...
</div>
<Timer></Timer>
</div>
</login>
my login.js content:
import {required, minLength, maxLength} from 'vuelidate/lib/validators'
import axios from "axios";
import {route} from "../../routes";
export default {
data() {
return {
//
}
}
}
Register vue-countdown-timer globally in app.js and your custom component timer locally in login.js
app.js
import Vue from 'vue'
import VueCountdownTimer from 'vuejs-countdown-timer';
Vue.use(Vuelidate)
Vue.use(VueCountdownTimer)
window.Vue = require('vue').default
new Vue({
store,
computed: {}, mount: {}
}).$mount('#app')
Login.js
import {required, minLength, maxLength} from 'vuelidate/lib/validators'
import axios from "axios";
import {route} from "../../routes";
import Timer from '../partials/timer.vue'
export default {
data() {
return {
//
}
},
components: {
Timer
},
}

vuex unknown action type: RawHTML in a VueJS using typescript application

I am getting a '[vuex] unknown action type: RawHTML' when trying to dispatch an action on a component.
Those errors are usually caused by not correctly namespaced modules, but I am not using modules here.
store/index.ts
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const SETRAWHTML = ''
const store = new Vuex.Store({
state: {
raw:''
},
mutations: {
[SETRAWHTML](state,str){
state.raw=str
},
},
actions: {
RawHtml({commit}, str) {
commit(SETRAWHTML, str)
},
},
getters: {
getRawHTML (state) {
return state.raw
}
},
})
export default store;
main.ts
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
my component
click(){
store.dispatch('RawHTML', this.rawHTML)
}
Thanks in advance
The name of actions is case-sensitive and you should dispatch the action with the same name as it's defined in the store, RawHTML and RawHtml don't refer to the same action, so you should respect the case and write the action dispatch as follows :
click(){
store.dispatch('RawHtml', this.rawHTML)
}

use `mapActions` or `mapGetters` with Vuex 4 and Vue 3

Anybody knows how to use mapState or mapGetters with Vue 3 in the setup function ?
I know that is possible to use the store with the useStore hook but with this hook We import all the store while with mapState or mapGetters we can specify a module :
// ...
computed: {
...mapGetters('myModule', [
'myStateVariable'
]
)
//...
Perhaps something like this:
import { computed } from 'vue';
import { useStore } from 'vuex';
const module = 'myModule';
export default {
setup() {
const store = useStore();
return {
// getter
one: computed(() => store.getters[`${module}/myStateVariable`],
// state
two: computed(() => store.state[module].myStateVariable,
};
},
};
As far as I can tell, they get flattened so you can't use myModule/myStateVariable, but myStateVariable should work.
This could be something that may change as Vuex gets to RC releases, but for now if you try to have the same getter twice, you get this error
With vue 3 and vuex 4 I managed to do it like this:
suppose we have a store shown below:
our general store index.js (the one on the bottom) would be like this:
import { createStore, createLogger } from 'vuex';
import module1 from '#/store/module1';
import module2 from '#/store/module2';
export default createStore({
modules: {
module1: module1,
module2: module2,
},
plugins: process.env.NODE_ENV !== 'production'
? [createLogger()]
: []
})
whereas the modules would each have such an index.js:
import * as getters from './getters'
import * as actions from './actions'
import mutations from './mutations'
const state = {
postId: 10111,
}
export default {
namespaced: true,
state,
getters,
actions,
mutations,
}
and the getter in each one of the module would be like this:
export const getPostId = state => {
return state.postId
}
finally in a component you could access the getters like that:
<template>
<div>
<div class="major_container">
<p>{{ postIdFromModule1 }}</p>
<p>{{ postIdFromModule2 }}</p>
</div>
</div>
</template>
<script>
import { computed } from "vue";
import { useStore } from "vuex";
export default {
setup() {
const store = useStore();
const postIdFromModule1 = computed(() => store.getters["module1/getPostId"]);
const postIdFromModule2 = computed(() => store.getters["module2/getPostId"]);
return {
postIdFromModule1,
postIdFromModule2,
};
},
};
</script>
Great, now you can use the modules namespaced!
The best way to use mapActions in a vue3 style SFC is to use mapActions in the setup() function's return
import { mapActions } from "vuex"
setup() {
return {
...mapActions("myModule", ["doSomething"])
}
}

vuex mapped namespaced action "is not a function," error

I am importing a Vuex module. Everything works fine if I don't namespace it, but when I do namespace it is reports that the action is "not a function." when called.
index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import MainWindow from './modules/MainWindow';
import ArtEditor from './modules/ArtEditor';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
MainWindow,
ArtEditor
}
});
ArtEditor module:
const state = {
selectedColor : "#FFFFFF"
}
const getters = {
selectedColor: state => state.selectedColor
};
const actions = {
selectColor({commit}, newColor){
commit('selectColor', newColor);
console.log(newColor)
}
};
const mutations = {
selectColor: (state, newColor) => state.selectedColor = newColor
};
export default {
namespaced: true,
state,
getters,
actions,
mutations
};
in Vue component:
import {mapActions, mapGetters} from 'vuex';
...
methods:{
...mapActions(['ArtEditor/selectColor']),
colorChanged(color){
this.selectColor(color);
}
},
...
when the color is changed, it throws the error this.selectColor is not a function. Most of the documentation on namespaced modules either doesn't import external Vuex modules, or uses dispatch() instead of mapActions(), I really don't know what I'm doing wrong.
Your syntax is off, you need to either do:
...mapActions(['ArtEditor/selectColor']),
colorChanged(color){
this['ArtEditor/selectColor'](color);
}
Or separate the action path while mapping:
...mapActions('ArtEditor', ['selectColor']),
colorChanged(color){
this.selectColor(color);
}
See binding helpers with namespace.

Categories

Resources