Skip to content

Instantly share code, notes, and snippets.

@xtrasmal
Last active May 19, 2020 16:30
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xtrasmal/1f7c3ca446d0e0d9f29a6a57258f8d10 to your computer and use it in GitHub Desktop.
Save xtrasmal/1f7c3ca446d0e0d9f29a6a57258f8d10 to your computer and use it in GitHub Desktop.
Use vuex all the time.. it's pretty simple to setup. NO SPA..cause.. yeah.. I dont like spa's
// Based on Laravel's base setup. This is the directory structure until the component
// later on, below this files, I'll show the contents of app.js and store.js
[assets]
|-- [sass]
|-- [js]
|-- app.js
|-- store.js
|-- setup.js
|-- [components]
|-- [medialibrary]
|-- [other-component]
|-- [store]
|-- [modules]
|-- [routes]
// This is the directory structure of the [store] & [routes]
[store]
|-- [modules]
|-- [medialibrary]
|-- actions.js // here you will start
|-- getters.js // helpfull file for shortcuts to the state
|-- index.js // bootstraps all files in this folder
|-- mutation-types.js // birdseye overview of all possible state mutations
|-- mutations.js // place to do the mutations
|-- state.js // to alter the state, one must go through actions > mutations > state
|-- [other-component]
|-- actions.js // same as above
|-- getters.js
|-- index.js
|-- mutation-types.js
|-- mutations.js
|-- state.js
|-- [routes]
|-- medialibrary.js // routes for your component
|-- other-component.js
// Starting point for webpack. Here we bootstrap all root components
require('./setup');
import {store} from './store';
// Root components
if (elementIsFound("medialibrary")) {
new Vue({
store, components: { 'medialibrary': require('components/medialibrary') }
}).$mount('#medialibrary');
}
window.Vue = require('vue');
window.axios = require('axios');
window.flasher = require('./helpers/flasher');
window._ = require('lodash');
window.$ = window.jQuery = require('jquery');
window.Bus = new Vue();
// AXIOS
let token = document.head.querySelector('meta[name="csrf-token"]');
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
// Helpers
window.log = (something) => {return console.log(something)};
window.base64Decode = (obj) => { return JSON.parse(atob(obj)) };
window.base64Encode = (obj) => { return btoa(JSON.stringify(obj)) };
window.elementIsFound = (element) => { return document.body.contains(document.getElementById(element)) };
// ARRAY extra's
Array.prototype.move = function(from, to) {
this.splice(to,0,this.splice(from,1)[0]);
return this;
};
/**
* Default Actions
* get: {method: 'GET'}
* save: {method: 'POST'}
* query: {method: 'GET'}
* update: {method: 'PUT'}
* delete: {method: 'DELETE'}
*
* @param path the resource path
* @param http axios instance
* @param actions custom actions
* @returns the resource object
*/
window.resource = (path, http, actions) => {
let obj = {
all: id => http.get(path),
get: id => http.get(path + '/' + id),
save: obj => http.post(path, obj),
query: params => http.get(path, {params}),
update: (id, obj) => http.put(path + '/' + id, obj),
delete: id => http.delete(path + '/' + id)
};
return Object.assign(obj, actions);
};
import Vue from 'vue';
import Vuex from 'vuex';
import { mapGetters } from 'vuex';
// Import store modules
import MediaLibraryStoreModule from './store/modules/medialibrary';
import OtherComponentStoreModule from './store/modules/other-component';
// Setup Vuex
Vue.use(Vuex);
window.getters = mapGetters;
// Create a store
const store = new Vuex.Store({
strict: process.env.NODE_ENV !== 'production'
});
/*
Register Store modules.
Register here OR register somewhere else, when getters start biting or whatever.
example: this.$store.registerModule('interface', InterfaceStoreModule);
*/
store.registerModule('medialibrary', MediaLibraryStoreModule);
store.registerModule('other-component', OtherComponentStoreModule);
// Export the store
export default store;
// In these are the files that the store individual modules folder
//////////////////////////////////////////////////////////
//
// [ INDEX.JS ]-> where all files below come together
//
//////////////////////////////////////////////////////////
import state from './state';
import mutations from './mutations';
import * as actions from './actions';
import * as getters from './getters';
export default { state, actions, getters, mutations }
//////////////////////////////////////////////////////////
//
// [ MUTATION-TYPES.JS ]-> namepacey kinda way of the things your app can do
//
//////////////////////////////////////////////////////////
export const UPDATE_SEARCH_PARAMETERS = 'UPDATE_SEARCH_PARAMETERS';
export const REMOVE_SEARCH_PARAMETERS = 'REMOVE_SEARCH_PARAMETERS';
export const MOVE_FIELDS = 'MOVE_FIELDS';
export const MEDIA_GET_ALL = 'MEDIA_GET_ALL';
//////////////////////////////////////////////////////////
//
// [ MUTATIONS.JS ]-> where state changes may happen
//
//////////////////////////////////////////////////////////
import * as types from './mutation-types';
const mutations = {
[types.MEDIA_GET_ALL](state, data) {
state.media = data;
Bus.$emit('media_retrieved');
},
[types.UPDATE_SEARCH_PARAMETERS](state, params) {
state.search.params = Object.assign(state.search.params, params);
Bus.$emit('updated_search_parameters');
},
[types.REMOVE_SEARCH_PARAMETERS](state, key) {
delete state.search.params[key];
Bus.$emit('removed_search_parameters');
},
[types.MOVE_FIELDS](state, {from, to}) {
state.fields.custom.move(from, to);
Bus.$emit('moved_fields');
},
}
export default mutations;
//////////////////////////////////////////////////////////
//
// [ ACTIONS.JS ]-> this is what you call from the components
//
//////////////////////////////////////////////////////////
export const all = ({ commit }, params) => {
repository.all().then(
response => commit(types.MEDIA_GET_ALL, response.data),
error => Bus.$emit('error', error)
);
};
export const move = ({ commit }, positions) => commit(types.MOVE_FIELDS, positions );
export const removeSearchParameters = ({ commit }, key) => commit(types.REMOVE_SEARCH_PARAMETERS, key );
export const updateSearchParameters = ({ commit }, params) => commit(types.UPDATE_SEARCH_PARAMETERS, params );
//////////////////////////////////////////////////////////
//
// [ GETTERS.JS ]-> shortcuts to the state, for use in components
//
//////////////////////////////////////////////////////////
export const audio = state => state.media.audio;
export const images = state => state.media.images;
export const searchparams = state => state.search.params;
export const fields = state => state.fields;
export const fieldCount = state => state.fields.custom.length;
export const paginator = state => state.paginator;
export const mediaLoaded = state => state.media.loaded;
//////////////////////////////////////////////////////////
//
// [ STATE.JS ]-> this is the thing where it is all coming from and going to
//
//////////////////////////////////////////////////////////
// initial state
const state = {
participantsLoaded: false,
media: {
audio: [],
images: [],
loaded: false
},
search: {
params: {
slug: '',
limit: 100,
page: 1
}
},
paginator: {
prev_page: false,
next_page: 0,
total: 0,
pages: 0,
current: 1,
offset: 0,
limit: 200,
start: 1,
end: 200
},
fields: []
};
export default state;
// Now when we open [medialibrary] index.vue
<script>
export default {
props: ['slug'],
created() {
this.$store.dispatch('all', {slug: this.slug} );
Bus.$on('searchparamsUpdated', () => this.loadMedia());
this.$nextTick(() => this.loadMedia());
},
methods: {
loadMedia(){
this.$store.dispatch('all', this.searchparams );
}
},
computed: {
...getters({
searchparams: 'searchparams',
mediaLoaded: 'mediaLoaded'
})
}
}
</script>
<template>
// Example of the template. Components needed to be added ofcourse...
<div class="medialibrary">
<div v-if="mediaLoaded">
<another-component></another-component>
<div class="table-wrapper>
<files></files>
</div>
</div>
<media-modal></media-modal>
</div>
</template>
<style lang="scss" scoped></style>
<script>
export default {
props: ['name','icon'],
methods: {
/**
* Search for stuff using a debounce, so that we do not search immediately
*/
search: _.debounce( function(event, key) {
if(event.target.value != ''){
this.$store.dispatch('updateSearchParameters', {[key]: event.target.value} );
} else {
this.$store.dispatch('removeSearchParameters', key );
}
}, 300),
},
}
</script>
<template>
<div class="input-group searchbox">
<input type="text" autocomplete="off" :class="name" :placeholder="name" @input="search($event, name)">
</div>
</template>
@marufmax
Copy link

marufmax commented Oct 5, 2019

Nice!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment