I have a masterData.js file that is a store for my master data, in short the file reads my mongo db data & sends it to other project components. I created a function to export the string in the masterData.js file as:
/ ***************************** MUTATIONS
const mutations = {
exportColumns (payload) {
Object.keys(payload[0]).map(x => { return x; });
}
}
Where payload will store all the rows and payload[0] holds the value of column header names. The output of this chunk of code is like this:
["_id","businessAreaName","businessAreaDisplay","councilDisplay","councilID"]
I want to transfer the values to masterData.vue file. My code on masterData.Vue is:
importColumns ()
{
let payload = {
vm: this,
mutation: 'masterData/exportColumns'
};
}
What else should I add to to check whether the column names are received or not?
If you're trying to access the data in your store from within a component, then you'll want to either just map the state to the component or map a getter to the component. Mutations are used by components (or by actions) to modify the state of the store. So instead you would do something like...
//masterData.js
//assuming this gets rolled up as a module called masterdata to the primary store
//store for payload state
const state = {
payload: null,
}
//allows payload to be set -- not sure how you are retrieving the payload but you can use this to store it however you get it
const mutations = {
setPayload (state, payload) {
state.payload = payload
}
}
//get just the columns
const getters = {
getColumns (state) {
Object.keys(state.payload[0]).map(x => { return x; })
}
}
export default {
state,
mutations,
getters,
}
Then
//masterData.vue
<template>
//...
</template>
<script>
import { mapGetters, mapState } from 'vuex'
export default {
computed: {
//I believe getting state from a store module requires a function like this
...mapState({
payload: function(state) {
return state.masterdata.payload
},
}),
//I think for getters you can just reference the method and it will find it
...mapGetters([
'getColumns',
])
},
}
</script>
This is how you import stuff in a single file component.
<template>
<!-- html stuff -->
</template>
<script>
import Mutations from 'yourModule.js'
export default {
name: 'YourComponent',
props: {},
data(){
return {
foo: 'foo'
}
},
methods{
mymethod() {
Mutations.exportColumn(this.foo);
},
}
}
</script>
Related
I am figuring how to pass callback to vuex action
I tried below code but not working. The code run before I fire it
src/store/modules/web3.module.js
import Web3 from "web3";
const state = {};
const getters = {};
const mutations = {};
const actions = {
async test(context, confirmCallback, rejectCallback) {
confirmCallback();
rejectCallback();
}
};
export default {
state,
getters,
actions,
mutations
};
App.vue
<template>
<div id="app"></div>
</template>
<script>
import { mapActions } from "vuex";
export default {
name: "App",
methods: {
...mapActions(["test"]),
onModalOpen() {
console.log("open");
},
onModalClose() {
console.log("Close");
},
},
async created() {
let result = await this.test({
confirmCallback: this.onModalOpen(),
rejectCallback: this.onModalClose(),
});
},
};
</script>
The issue takes place in 2 places:
the payload syntax in your store is wrong
you are firing the functions with the () at the end when passing it through an object:
Solve the payload issue
An action has 2 parameters, first comes the context which is an object that contains the state, mutations etc. then comes the payload which is an object aswell
const actions = {
async test(context, {confirmCallback, rejectCallback}) {
confirmCallback();
rejectCallback();
}
}
Solve the decleration issue
To solve the decleration issue simply remove the () at the end like shown below:
async created() {
let result = await this.test({
confirmCallback: this.onModalOpen,
rejectCallback: this.onModalClose,
});
},
I have a prop that I'm binding to a child component. I'm trying to get rid of this and set the value to a data in a vuex global state.
<VideoPip :asset="asset" v-show="pipEnabled === true" />
How can I set this.$store.state.assetVideo; which is by default an empty object equal to the asset value? Would I do this in a computed property?
For reading the video state data, you can just use the mapState helper. For example, in your Video component
import { mapState } from 'vuex'
export default {
name: 'Video',
computed: mapState(['assetVideo'])
}
You can then reference this.assetVideo in your component's methods and assetVideo in its template. This will be reactive to changes in the store.
For setting the value, you should (must) use a mutation. For example
const store = new Vuex.Store({
strict: true, // always a good idea
state: {
assetVideo: {} // personally, I'd default to "null" but that's up to you
},
mutations: {
setVideoAsset: (state, assetVideo) => (state.assetVideo = assetVideo)
}
}
and in your components
methods: {
selectVideo (video) {
this.$store.commit('setVideoAsset', video)
}
}
in your parent component:
// if you dont use namespace
import { mapMutations, mapState } from 'vuex'
export default {
computed: {
...mapState(['assetVideo']),
asset: {
get() {
return this.assetVideo
},
set(newValue) {
this.setAssetVideo(newValue)
}
}
},
methods: {
...mapMutations(['setAssetVideo']),
}
}
store
const store = {
state: {
assetVideo: {}
},
mutations: {
setAssetVideo(state, payload) {
state.assetVideo = payload
}
}
}
in your parent component you can change the state using this.asset = 'something' and it will change in store and anywhere else used
and also you can pass it to child components
I try to add Vuex to my Nuxt.js project. I made a custom ligthbox and to share through all pages I write the code into the default layout page.
From a page, to hide or show the ligthbox I need to change the state value. This is all the modules into the "store" folder:
// state.js
export const state = () => ({
lightbox: false,
});
// getters.js
export const getters = {
getLightbox(state)
{
return state.lightbox
},
}
// actions.js
export const actions = {
showLightbox({commit})
{
commit('UPDATE_LIGHTBOX', true)
},
hideLightbox({commit})
{
commit('UPDATE_LIGHTBOX', false)
},
}
// mutations.js
export const mutations = {
UPDATE_LIGHTBOX(state,value)
{
state.lightbox = value
},
}
Then when I try to call "this.$store.state.lightbox" from a method I get an 500 error:
TypeError: Cannot read property 'getters' of undefined
Even I try to use this way and I get the same error:
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['getLightbox']),
lightboxState()
{
return this.getLightbox
},
}
mounted()
{
console.log( this.lightboxState )
}
}
Later I try with asyncData but the console print an "undefined" value:
export default {
asyncData({ store })
{
console.log('Store =',store);
}
}
So, what is the right way to using Vuex with Nuxt.js? Maybe I need to add something else to "nuxt.config.js"?
If you're using separate files for state.js, getters.js, mutations.js and actions.js, they should only have a single, default export.
So instead of
// getters.js
export const getters = ...
you should use
// getters.js
export default {
getLightbox: state => state.lightbox
}
This applies to all the files in your store directory.
See https://nuxtjs.org/guide/vuex-store/#modules-mode
I have a following store module:
const state = {
user: {}
}
const mutations = {
saveData(state, payload) {
state.user = payload
}
}
const actions = {
async loadData({ commit }, payload) {
try {
const res = await axios.get('https://api.example.com/user/1')
commit('saveData', res.data.data)
} catch(e) {
console.log(e)
}
}
}
const getters = {
getData(state) {
return state.user
}
}
Now what's the best way to save the data in component? Is it using watch
import { mapGetters } from 'vuex'
export default {
data() {
return {
user: {}
}
},
computed: {
...mapGetters({
getData
})
},
watch: {
'$store.state.users.users'() {
this.user = this.getData
}
}
}
... or store.subscribe?
import { mapGetters } from 'vuex'
export default {
data() {
return {
user: {}
}
},
computed: {
...mapGetters({
getData
})
},
created() {
this.$store.subscribe((mutation, state) => {
if(mutation.type === 'saveData') {
this.user = this.getData
}
})
}
}
Since you already know about store mapping I suppose you try to have some kind of edit form where you need the actual data taken from the database and also the ability to change this data to later send it back to the database.
You don't need a getter to have a simple reference to a store item. You will be very fine with mapState in your component:
{
computed: {
...mapState({
user: state => state.user,
}),
}
}
So as soon as user changed in the store your component will know about it. And here you can update the object you're editing. Let's rename it to edit to avoid collision:
{
data() {
return {
edit: {},
}
},
computed: {
...mapState({
user: state => state.user,
}),
},
watch: {
user: {
immediate: true,
handler(user) {
this.edit = { ...user }
},
},
},
}
Now edit is updated accordingly even if the component was mounted after the store item was updated (thanks to immediate option), and you can safely modify it in your component without any impact on the store reference.
P.S. Have to mention that in this implementation if you want to have reactivity on fields within edit object, then you need to update the whole edit object on each it's field update like this: this.edit = {...this.edit, [prop]: value}. But if you want it to be the natural Vue way, then first you need to initialize edit with actual object structure, and in the watcher for user perform something like Object.assign(this.edit, user).
It's preferable to use computed properties to access store data and keep it reactive.
It's possible to create a computed property using mapGetters as you do in the shared snipped, however, taking into account the getter is simply returning user from state, I don't think you need a getter at all, you can simply map the value from state by using mapState helper. In this way the component would be simplified to something like as follows:
import { mapState } from 'vuex'
export default {
computed: {
...mapState([
'user'
])
}
}
With the above approach you can reference user as this.user in the component's methods or simply as user in template of the component. Also, since the getter is out of use, you can delete the getter definition from the store (unless you are using it anywhere else).
I am working with vuex (2.1.1) and get things working within vue single file components. However to avoid too much cruft in my vue single file component I moved some functions to a utils.js module which I import into the vue-file. In this utils.js I would like to read the vuex state. How can I do that? As it seems approaching the state with getters etc is presuming you are working from within a vue component, or not?
I tried to import state from '../store/modules/myvuexmodule' and then refer to state.mystateproperty but it always gives 'undefined', whereas in the vue-devtools I can see the state property does have proper values.
My estimate at this point is that this is simply not 'the way to go' as the state.property value within the js file will not be reactive and thus will not update or something, but maybe someone can confirm/ prove me wrong.
It is possible to access the store as an object in an external js file, I have also added a test to demonstrate the changes in the state.
here is the external js file:
import { store } from '../store/store'
export function getAuth () {
return store.state.authorization.AUTH_STATE
}
The state module:
import * as NameSpace from '../NameSpace'
/*
Import everything in NameSpace.js as an object.
call that object NameSpace.
NameSpace exports const strings.
*/
import { ParseService } from '../../Services/parse'
const state = {
[NameSpace.AUTH_STATE]: {
auth: {},
error: null
}
}
const getters = {
[NameSpace.AUTH_GETTER]: state => {
return state[NameSpace.AUTH_STATE]
}
}
const mutations = {
[NameSpace.AUTH_MUTATION]: (state, payload) => {
state[NameSpace.AUTH_STATE] = payload
}
}
const actions = {
[NameSpace.ASYNC_AUTH_ACTION]: ({ commit }, payload) => {
ParseService.login(payload.username, payload.password)
.then((user) => {
commit(NameSpace.AUTH_MUTATION, {auth: user, error: null})
})
.catch((error) => {
commit(NameSpace.AUTH_MUTATION, {auth: [], error: error})
})
}
export default {
state,
getters,
mutations,
actions
}
The store:
import Vue from 'vue'
import Vuex from 'vuex'
import authorization from './modules/authorization'
Vue.use(Vuex)
export const store = new Vuex.Store({
modules: {
authorization
}
})
So far all I have done is create a js file which exports a function returning the AUTH_STATE property of authorization state variable.
A component for testing:
<template lang="html">
<label class="login-label" for="username">Username
<input class="login-input-field" type="text" name="username" v-model="username">
</label>
<label class="login-label" for="password" style="margin-top">Password
<input class="login-input-field" type="password" name="username" v-model="password">
</label>
<button class="login-submit-btn primary-green-bg" type="button" #click="login(username, password)">Login</button>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import * as NameSpace from '../../store/NameSpace'
import { getAuth } from '../../Services/test'
export default {
data () {
return {
username: '',
password: ''
}
},
computed: {
...mapGetters({
authStateObject: NameSpace.AUTH_GETTER
}),
authState () {
return this.authStateObject.auth
},
authError () {
return this.authStateObject.error
}
},
watch: {
authError () {
console.log('watch: ', getAuth()) // ------------------------- [3]
}
},
authState () {
if (this.authState.sessionToken) {
console.log('watch: ', getAuth()) // ------------------------- [2]
}
},
methods: {
...mapActions({
authorize: NameSpace.ASYNC_AUTH_ACTION
}),
login (username, password) {
this.authorize({username, password})
console.log(getAuth()) // ---------------------------[1]
}
}
}
</script>
On the button click default state is logged on to the console. The action in my case results in an api call, resulting a state change if the username - password combination had a record.
A success case results in showing the console in authState watch, the imported function can print the changes made to the state.
Likewise, on a fail case, the watch on authError will show the changes made to the state
For anyone wondering how to access a mutation from a javascript file, you can do the following:
import store from './store'
store.commit('mutation_name', mutation_argument);
Or for actions,
store.dispatch('action_name', action_argument)
import store from './store'
and than
store.commit('mutation_name', mutation_argument)
if you use js file
You can also access actions like:
import store from './store'
store.dispatch('action_name', action_argument)