-
-
Save duwaljyoti/7dab12a642c9029d538eaf6bd2da4685 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
![](http://res.cloudinary.com/coderjay/image/upload/v1520992200/vue.png)| | |
|:--:| | |
| Image Courtesy https://vuejobs.com | | |
# Using Vue Router, Vuex in modular Applications (Laravel). | |
Hey everyone, some time ago I wrote an article on [using vuex, vue router with laravel](https://medium.com/introcept-hub/using-vue-vuex-vue-router-with-laravel-2c0962c97416). Since this is a kind of sequel to it, I strongly recommend you all get to the article and read it once. | |
It would be terrible to watch second episode of [Games of thrones](https://en.wikipedia.org/wiki/Game_of_Thrones) without watching the first one right? :wink: | |
## What now inspired me to write this very article? | |
One of my good friends shared my article on vue developers group and there was a comment | |
![](https://cdn-images-1.medium.com/max/800/1*oYETyjYp2qvfOzXQ-vBYDQ.png) | |
An excerpt from the above comment. | |
> And the thing not well explained in the article is about managing multiple stores and states. | |
So we will be learning what Madhu suggested in the comment. Use of Vuex, Vue router in modular application. | |
## What I am expected know before getting started with this article? | |
A good basics on Vue, Vuex, Vue Router and Laravel. | |
## Business logic | |
Implementing multiple modules in the previous project would have been a bit hectic and kind of over-engineering, so I thought of adding user module to it. Now here are two modules Note and User. Please make sure to have a quick sneak peek into [Note App](http://note-app-spa.herokuapp.com). | |
## [Github link](https://github.com/coderjay12/spa-test/tree/implementingMultipleModules) | |
Going through the repo will make the article easier to understand. | |
## Lets get started with some codes | |
### Backend part | |
Firstly lets run all the [migrations](https://laravel.com/docs/5.6/migrations) and create our api's to get all the relavant data. | |
``` | |
Route::prefix('api')->group(function() { | |
Route::resource('notes', 'Api\NotesController'); | |
Route::put('/notes/{note}/toggleFavourite', 'Api\NotesController@toggleFavourite'); | |
Route::get('/users', 'Api\UsersController@index'); | |
Route::get('/users/{user}/notes', 'Api\UsersController@getNotesByUser'); | |
Route::get('/users/{user}/getFavouriteNotesId', 'Api\NotesController@getFavouriteId'); | |
}); | |
``` | |
The above api's get all the job done necessary for our application. | |
Lets now create our backend routes. | |
``` | |
Route::get('/note', function() { | |
return view('note.index'); | |
})->name('note'); | |
``` | |
## Frontend | |
As soon as one hits domain/note, we can see __**note/index blade**__ will be called. | |
__**newApp.blade.php**__ has a few changes than the laravel's __**app.blade.php**__ transformed according to our requirement. | |
``` | |
@extends('layouts.newApp') | |
@section('script') | |
<script src="{{ mix('build/js/noteApp.js') }}"></script> | |
@endsection | |
``` | |
We can see on the __**index blade**__ we called a file called __**noteApp.js**__, which actually is a bundled form of __**note/app.js**__. | |
__*NoteApp.js*__ | |
``` | |
const router = new VueRouter({ | |
routes, // note routes | |
}); | |
const NoteApplication = new Vue({ | |
router, | |
store, // note's store | |
}); | |
NoteApplication.$mount('#app'); | |
``` | |
We are importing routes and stores from notes, creating a router, store instance with it and finally mounting the unmounted vue instance. | |
Lets see how note's store and routes look like! | |
__*NoteRoutes.js*__ | |
``` | |
const routes = [ | |
{ path: '/', name: 'note', component: Note }, | |
{ path: '/create', name: 'create', component: Create }, | |
{ path: '*', redirect: '/' }, | |
]; | |
export default routes; | |
``` | |
As we saw earlier on hitting domain/note by the above code we can see we will get to the Note component. Lets have a quick look on how we managed our store before jumping to the note component. | |
__*note/store/index.js*__ | |
``` | |
const store = new Vuex.Store({ | |
state, // note's state | |
actions, // note's action | |
mutations, // note's mutations | |
}); | |
export default store; | |
``` | |
We imported state, actions and mutations, created a store out of it and finally exported it. | |
__*note/store/state.js*__ | |
``` | |
const state = { | |
notes: [], | |
favouriteNotes: [], | |
}; | |
export default state; | |
``` | |
All we have done here is created a state object with notes and favouriteNotes and exported it. | |
__*note/store/actions.js*__ | |
``` | |
// const RESOURCE_NOTE = 'api/notes'; | |
export default { | |
getAll({commit}) { | |
return axios.get(RESOURCE_NOTE) | |
.then((response) => { | |
commit('GET', response.data); | |
}) | |
.catch(); | |
}, | |
getFavourite({commit}) { | |
// function definition here | |
}, | |
save({commit}, note) { | |
// function definition here | |
}, | |
// Other methods here | |
``` | |
Our note's actions is responsible to carry out all the operations like listing note and favourite notes with the help of note's mutation, toggling and saving notes basically everything related to note. | |
__*note/store/mutations.js*__ | |
``` | |
export default { | |
['GET'](state, notes) { | |
state.notes = notes; | |
}, | |
['GET_FAVOURITE'](state, notes) { | |
// mutation definition | |
}, | |
} | |
``` | |
If we have a look on our __*notes/store/index.js*__ we have imported note’s state, note’s action and note’s mutation then created a store with it and exported it. | |
In previous post of mine, we had all our state, actions and mutations on one single file, it probably will be fine if we still choose to do so, but as our application goes on getting larger, segregating state, actions and mutations will be more scalable and readable. Its all personal preference so one can do as wish and self ease. | |
Lets now see how our note component looks like. | |
__*components/Note.vue*__ | |
``` | |
computed: { | |
...mapState([ | |
'notes', | |
'favouriteNotes', | |
]), | |
}, | |
methods: { | |
...mapActions([ | |
'getAll', | |
'getFavourite', | |
'getUserFavouriteId', | |
]), | |
} | |
``` | |
If we again have a look on our __**note/app.js**__ we are injecting the note's store object while creating the vue instance because of which the note's store will be accessible to our note component. This way we can easily map state or actions(methods) which we did above or even getters . After doing so the data inside of note's state will be accessible to us just by doing | |
``` | |
this.notes; | |
``` | |
and actions by | |
``` | |
this.getAll(); | |
``` | |
Since the note component is also responsible for displaying, editing and toggling favourite notes it got a bit long. | |
I hope you got a good grasp on how are things are working above, if so understanding the user module would be a breeze and if not please let me know in the comments below. | |
I would not explain the user module since it is almost the same and it would make the post superlong. But wait here is something I would like to talk something regarding the user module, almost everything else is just the same. | |
User is an entirely different(Business logic wise) module from note but here is a situation, we need to access some methods in the user module that is already present in the note’s action so what shall we do? | |
Everything is pretty much the same leaving | |
__*user/store/index.js*__ | |
``` | |
const noteModule = { | |
state: {}, | |
actions: noteActions, | |
mutations: {}, | |
}; | |
const userModule = { | |
state, | |
actions, | |
mutations, | |
}; | |
const store = new Vuex.Store({ | |
modules: { | |
userModule, | |
noteModule, | |
} | |
}); | |
export default store; | |
``` | |
Directly from docs | |
> Vuex allows us to divide our store into modules. Each module can contain its own state, mutations, actions, getters, and even nested modules | |
what we did above was divided user and note module and while creating the user store we injected both the modules and now we are free to use actions that are inside of note's action from user component. | |
For more on modules please refer [Vuex's Module Doc](https://vuex.vuejs.org/en/modules.html). | |
Now what we can do is | |
``` | |
...mapActions([ | |
'get', | |
'getUserNotes', | |
'toggleFavourite', | |
'getUserFavouriteId', | |
]), | |
``` | |
if we look closely toggleFavourite and getUserFavouriteId are placed inside of note's actions and with the modular approach we can safely still access note's actions. | |
So with this, we come to end of the article and by now you should have some idea on using vue router and vuex on modules. | |
## Refactorings | |
* Code is messy at places and style is just horrible, I would soon be fixing them up. | |
* Implementing Proper validation. | |
## Future plans | |
* I would love let the user create public and private notes. | |
* Synchronisation between multiple tabs in a browser. | |
Please pour in any words of suggestions or places of improvement. | |
## Thanks | |
I would love to take a time to thank my colleagues Madhu, Ayush, Sabin, Sanesh and Asmit for all the technical assistance. | |
Many thanks to Sajan for providing me the loading component. | |
Biggest thanks to all of you awesome devs for going through the article in spite of your super busy schedule. | |
## I took a loads of ideas from | |
* [coliogo's tutotial on vuex](https://coligo.io/learn-vuex-by-building-notes-app/) | |
* [Simple note app](https://simplenote.com/) | |
* [Evernote](https://evernote.com/) | |
## References | |
* Vue, Vuex, Vue router official documentation. | |
* Laravel documentation. | |
* Stack overflow(needless to say). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
great post! thanks keep going!