how is consept of vuex, if i manage many table is will be only one store.js - vuex

i really don't understand concept in vuex, example bellow i only handle one "todo table" there is many code there, i can not imagine if i handle other table like product,order,profile etc
is will write also in store.js
or there is other way if i want to handle many table
example code using vuex, only for one table
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
axios.defaults.baseURL = 'http://localhost:8000/api'
export const store = new Vuex.Store({
state:{
token: localStorage.getItem('access_token') || null,
filter: 'all',
todos: [
]
},
getters:{
loggedIn(state){
return state.token !== null
},
remaining(state) {
return state.todos.filter(todo => !todo.completed).length
},
anyRemaining(state,getters) {
return getters.remaining != 0
},
todosFiltered(state) {
if (state.filter == 'all') {
return state.todos
} else if (state.filter == 'active') {
return state.todos.filter(todo => !todo.completed)
} else if (state.filter == 'completed') {
return state.todos.filter(todo => todo.completed)
}
return state.todos
},
showClearCompletedButton(state) {
return state.todos.filter(todo => todo.completed).length > 0
}
},
mutations:{//harus dengan nama mutations
addTodo(state,todo){
state.todos.push({
id:todo.id,
title:todo.title,
completed:false,
editing:false
})
},
updateTodo(state, todo){
const index = state.todos.findIndex((item) => item.id == todo.id)
state.todos.splice(index, 1, {
'id': todo.id,
'title': todo.title,
'completed': todo.completed,
'editing': todo.editing,
})
},
deleteTodo(state,id){
const index = state.todos.findIndex((item) => item.id == id)
state.todos.splice(index, 1)
},
allChecked(state,checked){
state.todos.forEach(todo => (todo.completed = checked))
},
updateFilter(state, filter){
state.filter = filter
},
clearCompleted(state){
state.todos = state.todos.filter(todo => !todo.completed)
},
retreiveTodos(state,todos){
state.todos = todos
},
retrieveToken(state,token){
state.token = token
},
destroyToken(state){
state.token = null
},
clearTodos(state) {
state.todos = []
},
},
actions:{
clearTodos(context) {
context.commit('clearTodos')
},
register(context, data) {
return new Promise((resolve, reject) => {
axios.post('/register', {
name: data.name,
email: data.email,
password: data.password,
})
.then(response => {
resolve(response)
})
.catch(error => {
reject(error)
})
})
},
destroyToken(context){
if(context.getters.loggedIn){
localStorage.removeItem('access_token')
context.commit('destroyToken')
}
},
retrieveToken(context,credentials){
return new Promise((resolve,reject) => {
axios.post('/login',{
email: credentials.email,
password: credentials.password,
})
.then(response => {
const token = response.data.data[0].token;
localStorage.setItem('access_token',token)// hasil token di simpan di local storage
context.commit('retrieveToken',token)
resolve(response)
})
.catch(error => {console.log(error)
reject(error)
})
})
},
retreiveTodos(context){
axios.defaults.headers.common['Authorization'] = 'Bearer ' + context.state.token
axios.get('/todos')
.then(response => {
context.commit('retreiveTodos',response.data)
})
.catch(error => {console.log(error)})
},
addTodo(context,todo){
axios.post('/todos',{
title: todo.title,
completed: false
})
.then(response => {
context.commit('addTodo',response.data)
})
.catch(error => {console.log(error)})
},
updateTodo(context, todo){
axios.patch('/todos/' + todo.id,{
title: todo.title,
completed: todo.completed
})
.then(response => {
context.commit('updateTodo',response.data)
})
.catch(error => {console.log(error)})
},
deleteTodo(context,id){
axios.delete('/todos/' + id)
.then(response => {
context.commit('deleteTodo',id)
})
.catch(error => {console.log(error)})
},
allChecked(context,checked){
axios.patch('/todosCheckAll',{
completed: checked
})
.then(response => {
context.commit('allChecked',checked)
})
.catch(error => {console.log(error)})
},
updateFilter(context, filter){
context.commit('updateFilter',filter)
},
clearCompleted(context){
const completed = context.state.todos
.filter(todo => todo.completed)
.map(todo => todo.id)
axios.delete('/todosDeleteCompleted',{
data:{
todos:completed
}
})
.then(response => {
context.commit('clearCompleted')
})
.catch(error => {console.log(error)})
}
}
})

Related

How to close Realm when I export it and use it with Promise?

I have 2 questions.
#1:
I found this code on the internet and tried to study it, all this code will be in a .js file, and when I call all the functions in the main .js, the app works fine, but I was reading in the docs that I need to close Ream after use it, and I was trying to do it, but I can’t use realm.close() anywhere, can someone explain how to implement closure please? Sorry for my English, I really tried to explain this.
import Realm from "realm";
export const TODOLIST_SCHEMA = "TodoList";
export const TODO_SCHEMA = "Todo";
export const TodoListSchema = {
name: TODO_SCHEMA,
primaryKey: "_id",
properties: {
_id: "int",
title: { type: "string", indexed: true },
description: "string",
done: { type: "bool", default: false },
}
};
export const TodoSchema = {
name: TODOLIST_SCHEMA,
primaryKey: "_id",
properties: {
_id: "int",
title: "string",
description: "string",
creationDate: "date",
todos: { type: "list", objectType: TODO_SCHEMA },
},
};
const databaseOptions = {
path: "todoList.realm",
schema: [TodoListSchema, TodoSchema],
schemaVersion: 0,
}
export const insertNewTodoList = newTodoList => new Promise((resolve, reject) => {
Realm.open(databaseOptions).then(realm => {
realm.write(() => {
realm.create(TODOLIST_SCHEMA, newTodoList);
resolve(newTodoList);
});
}).catch((error) => reject(error));
});
export const updateTodoList = todoList => new Promise((resolve, reject) => {
Realm.open(databaseOptions).then(realm => {
realm.write(() => {
let updatingTodoList = realm.objectForPrimaryKey(TODOLIST_SCHEMA, todoList._id);
updatingTodoList.title = todoList.title;
updatingTodoList.description = todoList.description;
resolve();
});
}).catch((error) => reject(error));
});
export const deleteTodoList = todoListId => new Promise((resolve, reject) => {
Realm.open(databaseOptions).then(realm => {
realm.write(() => {
let deletingTodoList = realm.objectForPrimaryKey(TODOLIST_SCHEMA, todoListId);
realm.delete(deletingTodoList);
resolve();
});
}).catch((error) => reject(error));
});
export const deleteAllTodoList = () => new Promise((resolve, reject) => {
Realm.open(databaseOptions).then(realm => {
realm.write(() => {
let allTodoList = realm.objects(TODOLIST_SCHEMA);
realm.delete(allTodoList);
resolve();
});
}).catch((error) => reject(error));
});
export const queryAllTodoList = () => new Promise((resolve, reject) => {
Realm.open(databaseOptions).then(realm => {
realm.write(() => {
let allTodoList = realm.objects(TODOLIST_SCHEMA);
resolve(allTodoList);
});
}).catch((error) => reject(error));
});
export default new Realm(databaseOptions);
2#
From the previous code I modified the options to make it simpler and it works fine in a simple CRUD of notes, but I wanted to know if it is poorly structured and it should be 2 schematics as above.
export const NOTELIST_SCHEMA = "NotaList";
export const NoteListSchema = {
name: NOTELIST_SCHEMA,
primaryKey: "_id",
properties: {
_id: "int",
title: "string",
description: "string",
creationDate: "date",
}
};
const databaseOptions = {
path: "NotaList.realm",
schema: [NoteListSchema],
schemaVersion: 0,
}

Unknown action type in Nuxt Vuex store

I have a problem calling the action from vuex. Everytime I try to access the loginUser action I get an error 'unknown action type' from vuex. maybe I'm not calling it the right way. Please tell me what's wrong with my code.
store: user.js
import axios from 'axios'
export const state = () => ({
users: [],
loggedIn: false,
})
export const getters = {
getLoggedIn: (state) => { return state.loggedIn },
}
export const actions = {
loginUser({ commit }, payload){
if(state.loggedIn){
console.log("you're already logged in!")
}else{
return new Promise(async(resolve, reject) => {
const { data } = await axios.post('/api/users/login-admin', {
login: payload.login,
password: payload.password
})
if(data.success){
commit("loggedIn", true)
resolve()
}else{
commit("loggedIn", false)
reject('an error has ocurred')
}
return data.success
}).catch(err => alert(errCodes(err.code)))
}
},
}
export const mutations = {
setLoggedIn(state, payload) {
state.loggedIn = payload
}
}
login.vue
computed: {
...mapGetters(['getCount'] , {user: 'getLoggedIn'}),
...mapActions([
'loginUser'
]),
},
methods: {
onSubmit: function(){
this.$store.dispatch({
type: 'loginUser',
email: this.login,
pass: this.pass
}).then(()=>{
this.$router.push('../admin_2065')
this.onReset()
}).catch(e => console.log(e))
},
onReset(){
this.login = ''
this.pass = ''
this.$nextTick().then(() => {
this.ready = true
})
}
},
error:
any help will be appreciated, thanks.
mapActions should be inside the methods option and add the namespace user/ :
computed: {
...mapGetters(['getCount'] , {user: 'getLoggedIn'}),
},
methods: {
...mapActions([
'user/loginUser'
]),
onSubmit: function(){
this['user/loginUser']({
email: this.login,
pass: this.pass
}).then(()=>{
this.$router.push('../admin_2065')
this.onReset()
}).catch(e => console.log(e))
},
onReset(){
this.login = ''
this.pass = ''
this.$nextTick().then(() => {
this.ready = true
})
}
},

Vuejs Vuex sometimes initial state not working Error: [Vue warn]: Error in render: "TypeError: Cannot read property 'Any_Variable' of undefined"

Other pages are working fine. Only facing issue with this file. May be I am coding wrong.
Store file is included in app.js file as other pages are working I have not included it.
Here Sometimes I get undefined MDU_Number. Sometimes it work fine. I am new to vue js.
Image of error that I am receving:
This is my vue template
<div class="card-body">
<div class="form-group row">
<label class="col-sm-4 col-form-label">MDU Number</label>
<div class="col">
<input
name="MDU_Number"
:value="mduprofile.MDU_Number"
#input="updateMDUNumber"
type="text"
class="form-control"
placeholder="Enter MDU Number Ex:GJXXCHXXXX"
required
/>
</div>
</div>
</div>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
data() {
return {
};
},
created() {
this.fetchForMDU();
},
destroyed() {
this.resetState();
},
computed: {
...mapGetters("MDUSingle", [
"loading",
"country",
"area",
"product",
"mduprofile",
]),
},
methods: {
...mapActions("MDUSingle", [
"resetState",
"fetchForMDU",
"storeMDU",
"setMDUNumber",
]),
submitForm() {
this.storeMDU()
.then(() => {
this.resetState();
this.$eventHub.$emit(
"create-success",
"Created",
"MDU created successfully"
);
})
.catch((error) => {
console.log(error);
});
},
updateMDUNumber(e) {
this.setMDUNumber(e.target.value);
},
},
};
</script>
This is store file name single.js and I have included it in app.js file
MDU_Number should go for null value but it goes for undefined. So I think it is not initialized properly. There are many other variables but for simplicity purpose I have included only one.
What can be the issue?
function initialState() {
return {
mduprofile: {
MDU_Number: null,
},
country: [],
area: [],
product: [],
loading: false
};
}
const getters = {
country: state => state.country,
area: state => state.area,
product: state => state.product,
loading: state => state.loading,
mduprofile: state => state.mduprofile
}
const actions = {
fetchForMDU({ commit }) {
return new Promise((resolve, reject) => {
axios.get('/get/detail/for/mdu')
.then((response) => {
let detail = response.data;
commit('setCountryAll', detail.country);
commit('setStateAll', detail.state);
commit('setProductAll', detail.product);
}).catch(error => {
reject(error);
}).finally(() => {
resolve();
});
});
},
storeMDU({ commit, state, dispatch }) {
commit('setLoading', true);
dispatch('Alert/resetState', null, { root: true });
return new Promise((resolve, reject) => {
let params = _.cloneDeep(state.mduprofile);
axios.post('/save-mdu-profile', params)
.then((response) => {
resolve();
})
.catch(error => {
commit('setLoading', false);
let message = error.response.data.message || error.message;
let errors = error.response.data.errors;
dispatch('Alert/setAlert',
{ message: message, errors: errors, color: danger },
{ root: true });
reject(error);
}).finally(() => {
commit('setLoading', false);
});
});
},
fetchData({ commit }, value) {
axios.get('/mdu/profile/' + value)
.then((response) => {
commit('setAll', response.data.mdu);
}).catch(error => {
}).finally(() => {
});
},
updateMDU({ commit, state, dispatch }) {
commit('setLoading', true);
dispatch('Alert/setAlert', null, { root: true });
return new Promise((resolve, reject) => {
let params = _.cloneDeep(state.mduprofile);
axios.put('/update-mdu-profile/' + params.MDU_Id, params)
.then((response) => {
resolve();
}).catch(error => {
let message = error.response.data.message || error.message;
let errors = error.response.data.errors;
dispatch('Alert/setAlert',
{ message: message, errors: errors, color: danger },
{ root: true });
commit('setLoading', false);
reject(error);
}).finally(() => {
commit('setLoading', false);
});
});
},
resetState({ commit }) {
commit('resetState');
},
setMDUNumber({ commit }, value) {
commit('setMDUNumber', value);
}
}
const mutations = {
resetState(state) {
state = Object.assign(state, initialState());
},
setLoading(state, loading) {
state.loading = loading;
},
setCountryAll(state, items) {
state.country = items
},
setStateAll(state, items) {
state.area = items;
},
setProductAll(state, items) {
state.product = items;
},
setAll(state, items) {
state.mduprofile = items;
},
setMDUNumber(state, value) {
state.mduprofile.MDU_Number = value;
},
setCountry(state, value) {
state.mduprofile.Country = value;
},
setState(state, value) {
state.mduprofile.State = value;
},
setProduct(state, value) {
state.mduprofile.Product = value;
}
}
export default {
namespaced: true,
state: initialState,
getters,
actions,
mutations
}
Try checking somewhere where you change this values, if you don't catch error properly you may encounter empty states.

How to test vuex store file?

Here I have written my vuex store file for state management. But I don't know how to test this file.
products.js
import products from '../api/products';
export function getProductById (products, id) {
const index = products.findIndex(
products => products.id === id
)
let product = null
if (index !== -1) {
product = products[index]
}
return {
index,
product,
}
}
const initialState = {
products: [],
searchText: '',
productLoading: false,
productDetail:{},
};
const getters = {
products: state => {
if (state.searchText) {
const reg = new RegExp(state.searchText.trim().toLowerCase().replace(/\s+/g, '|'))
return state.products.filter(
product => product.name.toLowerCase().search(reg) !== -1
)
} else {
return state.products
}
},
searchText: state => state.searchText,
};
const actions = {
fetchProducts({ commit }) {
return products.getProducts()
.then(({ data }) => {
commit(SET_PRODUCTS,data)
})
.catch((error) => {
if(error.response.status === 403){
commit(SET_PERMISSION_DENIED)
}
return Promise.reject(error.response.data);
}
);
},
createProduct({ commit }, { product_code, name, description, link_to_amazon, price, photo, category }) {
return new Promise((resolve, reject) => {
products.createProduct(product_code, name, description, link_to_amazon, price, photo, category)
.then((res) => {
resolve(res.data)
})
.catch((error) => {
reject(error.response)
});
})
},
updateProduct({ commit }, {id, product_code, name, description, link_to_amazon, price, photo, category}) {
return new Promise((resolve, reject) => {
products.updateProduct(id, product_code, name, description, link_to_amazon, price, photo, category)
.then((res) => {
resolve(res.data)
})
.catch((error) => {
commit(PRODUCT_LOADING, false)
reject(error.response)
});
})
},
deleteProduct({ commit }, { id }) {
return new Promise((resolve, reject) => {
products.deleteProduct(id)
.then((res) => {
commit(REMOVE_PRODUCT_BY_ID,id)
})
.catch((error) => {
reject(error.response)
});
})
},
setSearchText ({ commit }, value) {
commit(SET_SEARCH_TEXT, value)
},
};
const mutations = {
[SET_PRODUCTS](state, products) {
state.products = products;
},
[PRODUCT_LOADING](state, value) {
state.productLoading = value;
},
[REMOVE_PRODUCT_BY_ID](state,value){
const { index } = getProductById(state.products, value)
if (index !== -1) {
state.products.splice(index, 1)
}
},
};
All I want it to test this file, I really don't know how to do that, I have looked into the vuex documentation too. But didn't understand any.
you can write a black-box like following:
import storeConfig from '#/store/modules/salesStore'
import { createLocalVue } from '#vue/test-utils'
import Vuex from 'vuex'
jest.mock('#/api/sales', () => ({
fetchInvoices: jest.fn().mockReturnValue([{id: 1, date: 146352542, title:'John Doe' }]),
deleteInvoice: jest.fn()
})
const localVue = createLocalVue()
localVue.use(Vuex)
const createStore = () => new Vuex.Store(storeConfig)
describe('sales store', () => {
it('should be empty by default', () => {
let store = createStore()
expect(store.getters.invoices).toBeTruthy()
expect(store.getters.invoices.length).toBe(0)
})
it('loadInvocie action gets the incoice form the end-point', async () => {
const store = createStore()
await store.dispatch('loadInvoices', { departmentId: 1 })
expect(store.getters.invocies).toEquals([{
id: 1,
title: 'John doe',
date: 146352542
}])
})
})

VueJs. How to close pre-loader after data from server have been loaded

I use VueX in my VueJs app and I need to close pre-loader after I got an answer from server for 4 my get requests. I try to use callback function to change pre-loader state but it changes after requests STARTs, but I need to change pre-loader state after all requests SUCCESS. Below is my code:
Index.vue
<template>
<div class="index">
<div class="content-is-loading"
v-if="appIsLoading"></div>
<div v-else class="index__wrapper">
<navbarInner></navbarInner>
<div class="index__content">
<sidebar></sidebar>
<router-view></router-view>
</div>
<foo></foo>
</div>
</div>
</template>
<script>
import NavbarInner from './NavbarInner'
import Sidebar from './Sidebar'
import Foo from './../Foo'
import Shows from './Shows/Shows'
import Dashboard from './Dashboard'
import { API_URL } from '../../../config/constants'
import { mapState } from 'vuex'
export default {
name: 'index',
data () {
return {
appIsLoading: true,
bandName: ''
}
},
components: {
NavbarInner,
Sidebar,
Foo,
Shows,
Dashboard
},
created () {
function loadData (context, callback) {
// Loading bands for the user
context.$store.dispatch('getBands')
// Loading contacts for the user
context.$store.dispatch('getContacts')
// Loading merch for the user
context.$store.dispatch('getInventory')
// Loading tours for the active band
context.$store.dispatch('getToursList')
callback(context)
}
loadData(this, function (context) {
context.appIsLoading = false
})
}
}
Below I add code of one of the request:
api/tour.js
import axios from 'axios'
import { API_URL } from '../../config/constants'
export default {
getToursList () {
return new Promise((resolve, reject) => {
let bandId = window.localStorage.getItem('active_band_id')
let token = window.localStorage.getItem('token')
axios.get(API_URL + '/api/bands/' + bandId + '/tours/', {
headers: {'x-access-token': token}
})
.then((result) => {
return resolve(result.data)
})
.catch(err => reject(err))
})
},
getInventory () {
return new Promise((resolve, reject) => {
let token = window.localStorage.getItem('token')
axios.get(API_URL + '/api/merch/listProductForUser/1000/0', {
headers: {'x-access-token': token}
})
.then((response) => {
let items = response.data
return resolve(items)
})
.catch((err) => {
return reject(err)
})
})
},
getContacts () {
return new Promise((resolve, reject) => {
let token = window.localStorage.getItem('token')
axios.get(API_URL + '/api/contact/get_contacts_for_user/1000/0', {
headers: {'x-access-token': token}
})
.then((response) => {
console.log(response.data)
let contacts = response.data
return resolve(contacts)
})
.catch((err) => {
return reject(err)
})
})
},
getBands () {
return new Promise((resolve, reject) => {
let token = window.localStorage.getItem('token')
axios.get(API_URL + '/api/band/getBandsForUser/1000/0', {
headers: {'x-access-token': token}
})
.then((response) => {
console.log(response.data)
let bands = response.data
return resolve(bands)
})
.catch((err) => {
return reject(err)
})
})
}
}
Vuex/tour.js
import api from '../../api/onload'
import * as types from '../mutation-types'
const state = {
tours: [],
contacts: [],
bands: [],
merch: [],
success: false,
loading: false
}
const actions = {
getToursList ({commit}) {
api.getToursList()
.then((tours) => {
commit(types.RECEIVE_TOURS, tours)
}).catch((err) => {
console.error('Error receiving tours: ', err)
commit(types.RECEIVE_TOURS_ERROR)
})
},
getInventory ({commit}) {
api.getInventory()
.then((items) => {
commit(types.RECEIVE_INVENTORY, items)
})
.catch((err) => {
console.error('Error receiving inventory: ', err)
commit(types.RECEIVE_INVENTORY_ERROR)
})
},
getBands ({commit}) {
api.getBands()
.then((bands) => {
commit(types.RECEIVE_BANDS, bands)
})
.catch((err) => {
console.error('Error receiving bands: ', err)
commit(types.RECEIVE_BANDS_ERROR)
})
},
getContacts ({commit}) {
api.getContacts()
.then((contacts) => {
commit(types.RECEIVE_CONTACTS, contacts)
})
.catch((err) => {
console.error('Error receiving bands: ', err)
commit(types.RECEIVE_CONTACTS_ERROR)
})
}
}
const mutations = {
[types.RECEIVE_TOURS] (state, tours) {
state.tours = tours
},
[types.RECEIVE_INVENTORY] (state, items) {
state.items = items
},
[types.RECEIVE_BANDS] (state, bands) {
state.bands = bands
},
[types.RECEIVE_CONTACTS] (state, contacts) {
state.contacts = contacts
console.log(state.contacts)
}
}
export default {
state, mutations, actions
}
How should I change the code?
The code you posted doesn't actually wait on the response from any of the actions you are calling.
You could also move everything to a method and refactor.
Finally I've assumed your actions return a Promise i.e.
created () {
this.getAll()
},
methods: {
getAll () {
Promise.all([
this.$store.dispatch('getBands'),
this.$store.dispatch('getContacts'),
this.$store.dispatch('getInventory'),
this.$store.dispatch('getToursList'),
])
.then(responseArray => {
this.appIsLoading = false
})
.catch(error => { console.error(error) })
EDIT
To get your actions to resolve as you need them (when the mutations have fired and your store is updated) you need to wrap them in a Promise:
Vuex/tour.js (actions object)
getToursList: ({ commit }) =>
new Promise((resolve, reject) => {
api.getToursList()
.then((tours) => {
commit(types.RECEIVE_TOURS, tours)
resolve()
}).catch((err) => {
console.error('Error receiving tours: ', err)
commit(types.RECEIVE_TOURS_ERROR)
reject()
})
})