Vue.js, Nuxt.js, Vuetify - open progressbar from TypeScript by using store while the process
About this post
on the web page, the progress bar tends to be global component.
And, it is preferred to be opened from TypeScript (not from Vue template using v-if
) because the bar should be opened only while the process.
In this post, the way of implementation about progress bar opened from TypeScript is introduced.
Target readers
- the developers who want to implement
progressbar
by Vue.js or Nuxt.js - the developers who have basics about store and Vuetify.js (some basic parts of store and Vuetify will be omitted.)
Versions
content | version |
---|---|
nuxt | 2.15.8 |
nuxt-typed-vuex | 0.3.0 |
vue | 2.6.14 |
vuetify | 2.6.1 |
the directory structure
sampleProject
├componens
| └progressbar.vue
├pages
| └index.vue
├store
| ├index.ts
| └progressbar.ts
└types
└index.d.ts
Steps to open the progress bar from TypeScript
- the heavy process is executed.
- the store of
progressbar
is called. - while the heavy process is executed, progress bar component is shown thanks to the store of of
progressbar
. - after the heavy process is done, progress bar component is not shown anymore.
Create a store to control progress bar
Create store/progressbar.ts
.
import { mutationTree, actionTree } from 'typed-vuex';
// isShown is to control whether progress bar is shown or not
export const state = () => ({
isShown: false as boolean,
});
export type RootState = ReturnType<typeof state>;
export const mutations = mutationTree(state, {
change(state, isShown: boolean) {
state.isShown = isShown;
},
});
export const actions = actionTree(
{ state, mutations },
{
async open({ commit }, action: Function) {
// only while action is executed, the progress bar is opened
commit('change', true);
try {
await action();
} finally {
// even if the argument action throws an error, the progress bar should be closed
commit('change', false);
}
},
},
);
Register the store by creating store/index.ts
.
import {
getAccessorType,
getterTree,
mutationTree,
actionTree,
} from 'typed-vuex';
// if there is other stores, import here
import * as progressbar from './progressbar';
export const state = () => ({});
export const getters = getterTree(state, {});
export const mutations = mutationTree(state, {});
export const actions = actionTree({ state, getters, mutations }, {});
export const accessorType = getAccessorType({
state,
getters,
mutations,
actions,
modules: {
// if there is other stores, add here
progressbar,
},
});
Extend the types for vue
so that the store can be accessed from the file of vue
extension.
create types/index.d.ts
import { accessorType } from '~~/store';
declare module 'vue/types/vue' {
interface Vue {
$accessor: typeof accessorType;
}
}
Create a progress bar component
By the implementation of this.$store.subscribe
, catch the change notification of store progressbar
and change the visibility according to isShown
store value.
<template>
<!-- set z-index so that this progress bar can be shown above the modal dialog -->
<v-overlay z-index="100" :value="isShown">
<v-progress-circular indeterminate color="primary"></v-progress-circular>
</v-overlay>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'AppProgressbar',
data() {
return {
isShown: false,
};
},
created() {
this.$store.subscribe((mutation, state) => {
if (mutation.type === 'progressbar/change') {
this.isShown = state.progressbar.isShown;
}
});
},
});
</script>
Open progress bar from TypeScript
Create pages/index.vue
.
Only in the scope of await this.$accessor.progressbar.open(async () => {});
, the progress bar is shown.
<template>
<button @click="doHeavyProcess">Execute</button>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
methods: {
async doHeavyProcess() {
await this.$accessor.progressbar.open(async () => {
// in this scope, the progress bar is shown
await this.$axios.get('https://example.com');
});
// out of the scope of progress bar, the progress bar is not shown
},
},
});
</script>