Vuetify toggle between light and dark theme (with vuex) - vue.js

so in my Vue-project I basically have two pages/components that will be shown with the use of vue-router depending on the URL. I can switch between those pages/components via a button.
I am also using VueX for the management of some data.
Now I included a switch in one of the components to toggle between a dark and a light theme from Vuetify.
In the template for this component I do:
<v-switch
label="Toggle dark them"
#change="toggleDarkTheme()"
></v-switch>
And in the function that gets called I do:
toggleDarkTheme() {
this.$vuetify.theme.dark = !this.$vuetify.theme.dark;
console.log(this.$vuetify.theme.dark);
},
In app.vue I have included the <v-app dark> and in my main.js i have the following:
Vue.use(Vuetify);
const vuetify = new Vuetify({
theme: {
// dark: true,
themes: {
light: {
primary: colors.purple,
secondary: colors.grey.darken1,
accent: colors.shades.black,
error: colors.red.accent3,
background: colors.indigo.lighten5,
},
dark: {
primary: colors.blue.lighten3,
background: colors.indigo.base,
},
},
},
});
Vue.config.productionTip = false;
new Vue({
router,
store,
vuetify,
render: (h) => h(App),
}).$mount('#app');
So my problem now is, when I click the switch, the theme is indeed toggled from light to dark mode in this component. Light mode is the default and when I click the switch once, I get dark theme. However when I click the button to switch to the other URL, there the light theme will be used.
How do I implement this feature correctly?
Thanks in advance!

You should have a JavaScript class called vuetify.js, that should look like this in your case.
import Vue from "vue";
import Vuetify from "vuetify/lib";
Vue.use(Vuetify);
export default new Vuetify({
theme: {
themes: {
light: {
primary: colors.purple,
secondary: colors.grey.darken1,
accent: colors.shades.black,
error: colors.red.accent3,
background: colors.indigo.lighten5
},
dark: {
primary: colors.blue.lighten3,
background: colors.indigo.base
}
}
}
});
Your switch should be working, but just in case, try this button I've made in your component.
<div>
<v-tooltip v-if="!$vuetify.theme.dark" bottom>
<template v-slot:activator="{ on }">
<v-btn v-on="on" color="info" small fab #click="darkMode">
<v-icon class="mr-1">mdi-moon-waxing-crescent</v-icon>
</v-btn>
</template>
<span>Dark Mode On</span>
</v-tooltip>
<v-tooltip v-else bottom>
<template v-slot:activator="{ on }">
<v-btn v-on="on" color="info" small fab #click="darkMode">
<v-icon color="yellow">mdi-white-balance-sunny</v-icon>
</v-btn>
</template>
<span>Dark Mode Off</span>
</v-tooltip>
</div>
The Button calls this method in your <script>
darkMode() {
this.$vuetify.theme.dark = !this.$vuetify.theme.dark;
}

The below code creates a dark mode toggle switch btn.
Note: Its use Localstore
DarkModeToggel.vue
<template>
<v-icon class="mr-2">
mdi-brightness-4
</v-icon>
<v-list-item-title class="pr-10">
Dark Mode
</v-list-item-title>
<v-switch v-model="darkmode" color="primary" />
</template>
--
<script>
export default {
data () {
return {
darkmode: false
}
},
watch: {
darkmode (oldval, newval) {
this.handledarkmode()
}
},
created () {
if (process.browser) {
if (localStorage.getItem('DarkMode')) {
const cookieValue = localStorage.getItem('DarkMode') === 'true'
this.darkmode = cookieValue
} else {
this.handledarkmode()
}
}
},
methods: {
handledarkmode () {
if (process.browser) {
if (this.darkmode === true) {
this.$vuetify.theme.dark = true
localStorage.setItem('DarkMode', true)
} else if (this.darkmode === false) {
this.$vuetify.theme.dark = false
localStorage.setItem('DarkMode', false)
}
}
}
}
}
</script>
#ckuessner answer is working but not persistent.

Button theme switcher with persistence of dark theme state in cookies based on solution of #rohit-nishad.
NPM package used for cookies reading/writing: 'cookie-universal-nuxt'.
ColorThemeSwitch.vue
<template>
<v-tooltip bottom>
<template #activator="{ on }">
<v-btn v-on="on" icon #click="switchTheme">
<v-icon>
{{ $vuetify.theme.dark ? 'mdi-white-balance-sunny' : 'mdi-moon-waxing-crescent' }}
</v-icon>
</v-btn>
</template>
<span>Change theme</span>
</v-tooltip>
</template>
<script>
export default {
created() {
const darkModeCookie = this.$cookies.get('app.darkMode');
if (darkModeCookie) {
this.$vuetify.theme.dark = darkModeCookie;
}
},
methods: {
switchTheme() {
this.$vuetify.theme.dark = !this.$vuetify.theme.dark;
this.$cookies.set('app.darkMode', this.$vuetify.theme.dark);
},
},
};
</script>
It is better to put the code from 'created' hook somewhere in layouts or plugin so your app will change the theme no matter if component is presented on the current page. Example for plugin:
~/plugins/persistedThemeLoader.js
export default function ({ $vuetify, $cookies }) {
const darkModeCookie = $cookies.get('app.darkMode');
if (darkModeCookie) {
$vuetify.theme.dark = darkModeCookie;
}
}
nuxt.config.js
plugins: [
'~/plugins/vuetify',
{ src: '~/plugins/persistedThemeLoader', mode: 'client' },
],

Related

Opening a modal component with a button in another ccomponent using Vuetify

I have 2 components. Modal and Navbar. I'm trying to open Modal using a button in Navbar using vuex. I have a state called modalIsOpen. This states value changes from false to true when clicked on the button in Navbar but only a blank row is rendered as a modal and modal content is not shown. I could not figure out what is wrong.
At the beginning i thought it was a vuetify v-dialog problem. But ive tried other libraries too. And as i said nothing worked yet.
Here is the components ,app.vue and store.js.
AddUpdateModal.vue:
<template>
<v-dialog>
<v-card width="50%" height="50%">
<v-card-title class="text-h5 grey lighten-2">
Privacy Policy
</v-card-title>
<v-card-text>
Lorem
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary" text #click="dialog = false">
I accept
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
export default {
name: "AddUpdateModal",
components: {},
data: () => ({}),
}
</script>
<style>
.v-card {
display: block !important;
}
.v-easy-dialog {
height: 500px !important;
}
</style>
NavBar.vue:
<template>
<div id="Navbar">
<v-row>
<v-btn color="primary" #click.stop="openModal" rounded>
Add / Update
</v-btn>
<v-btn color="primary" #click="closeModal" rounded>
Refresh
</v-btn>
</v-row>
<v-row>
<v-divider class="grey darken-4"></v-divider>
</v-row>
</div>
</template>
<script>
export default {
name: 'NavBar',
components: {},
data: () => ({}),
methods: {
openModal() {
this.$store.commit('openModal');
},
closeModal() {
this.$store.commit('closeModal')
}
},
}
</script>
App.vue:
<template>
<v-app>
<v-container>
<NavBar />
<br>
<div class="parent">
<!-- <AddButton></AddButton> -->
<v-btn #click="konsol">Konsol</v-btn>
<div id="modal" v-if="$store.state.modalIsOpen">
<template>
<AddUpdateModal></AddUpdateModal>
</template>
</div>
<v-row>
<v-col>
<DataTable />
</v-col>
<v-divider class="grey darken-4" vertical inset></v-divider>
<v-col>
<PieChart />
</v-col>
</v-row>
</div>
</v-container>
</v-app>
</template>
<script>
import NavBar from './components/NavBar.vue';
import PieChart from './components/PieChart.vue';
import DataTable from './components/DataTable.vue';
// import AddButton from './components/AddButton';
import AddUpdateModal from './components/AddUpdateModal';
// eslint-disable-next-line no-unused-vars
import store from './store/store'
// import axios from 'axios';
export default {
name: 'App',
components: {
NavBar,
AddUpdateModal,
PieChart,
DataTable,
// AddButton,
},
created() {
this.$store.dispatch("initApp")
},
data: () => ({
}),
methods: {
konsol() {
console.log("modalIsOpen", this.$store.state.modalIsOpen)
}
},
};
</script>
<style>
* {
margin: 5px;
}
.v-dialog__container {
display: unset !important;
position: relative !important;
}
</style>
store.js:
import Vue from "vue";
import Vuex from "vuex";
import axios from "axios";
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
binance24HrData: [],
modalIsOpen: false,
},
mutations: {
initPortfolioDetails(state, newCoin) {
state.binance24HrData = newCoin;
},
openModal(state) {
state.modalIsOpen = true;
},
closeModal(state) {
state.modalIsOpen = false;
},
},
actions: {
initApp(context) {
axios
.get("https://api2.binance.com/api/v3/ticker/24hr")
.then((response) => {
context.commit("initPortfolioDetails", response.data);
console.log("Binance", response.data);
});
},
openModal({ commit }) {
commit("openModal");
},
closeModal({ commit }) {
commit("closeModal");
},
},
getters: {
getCoinsDetails(state) {
return state.binance24HrData;
},
},
});
export default store;
main.js:
import Vue from "vue";
import App from "./App.vue";
import vuetify from "./plugins/vuetify";
import store from "./store/store.js";
Vue.config.productionTip = false;
new Vue({
vuetify,
store,
render: (h) => h(App),
}).$mount("#app");
I figured it out: all I had to do was add v-model to v-dialog. I thought it was unnecessary because I already had a v-if that wrapped the component containing the v-dialog. I assumed that with this requirement fulfilled, it should render the child component, but it didn't because I didn't have v-model in v-dialog.

beforeRouteLeave doesn't work imediately when using with modal and emit function

I have a Vue application with many child components. In my case, I have some parent-child components like this. The problem is that in some child components, I have a section to edit information. In case the user has entered some information and router to another page but has not saved it, a modal will be displayed to warn the user. I followed the instructions on beforeRouteLeave and it work well but I got a problem. When I click the Yes button from the modal, I'll emit a function #yes='confirm' to the parent component. In the confirm function, I'll set this.isConfirm = true. Then I check this variable inside beforeRouteLeave to confirm navigate. But in fact, when I press the Yes button in modal, the screen doesn't redirect immediately. I have to click one more time to redirect. Help me with this case
You can create a base component like the following one - and then inherit (extend) from it all your page/route-level components where you want to implement the functionality (warning about unsaved data):
<template>
<div />
</template>
<script>
import events, { PAGE_LEAVE } from '#/events';
export default
{
name: 'BasePageLeave',
beforeRouteLeave(to, from, next)
{
events.$emit(PAGE_LEAVE, to, from, next);
}
};
</script>
events.js is simply a global event bus.
Then, in your page-level component you will do something like this:
<template>
<div>
.... your template ....
<!-- Unsaved changes -->
<ConfirmPageLeave :value="modified" />
</div>
</template>
<script>
import BasePage from 'src/components/BasePageLeave';
import ConfirmPageLeave from 'src/components/dialogs/ConfirmPageLeave';
export default
{
name: 'MyRouteName',
components:
{
ConfirmPageLeave,
},
extends: BasePage,
data()
{
return {
modified: false,
myData:
{
... the data that you want to track and show a warning
}
};
}.
watch:
{
myData:
{
deep: true,
handler()
{
this.modified = true;
}
}
},
The ConfirmPageLeave component is the modal dialog which will be shown when the data is modified AND the user tries to navigate away:
<template>
<v-dialog v-model="showUnsavedWarning" persistent>
<v-card flat>
<v-card-title class="pa-2">
<v-spacer />
<v-btn icon #click="showUnsavedWarning = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text class="pt-2 pb-3 text-h6">
<div class="text-h4 pb-4">{{ $t('confirm_page_leave') }}</div>
<div>{{ $t('unsaved_changes') }}</div>
</v-card-text>
<v-card-actions class="justify-center px-3 pb-3">
<v-btn class="mr-4 px-4" outlined large tile #click="showUnsavedWarning = false">{{ $t('go_back') }}</v-btn>
<v-btn class="ml-4 px-4" large tile depressed color="error" #click="ignoreUnsaved">{{ $t('ignore_changes') }}</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import events, { PAGE_LEAVE } from '#/events';
export default
{
name: 'ConfirmPageLeave',
props:
{
value:
{
// whether the monitored data has been modified
type: Boolean,
default: false
}
},
data()
{
return {
showUnsavedWarning: false,
nextRoute: null,
};
},
watch:
{
showUnsavedWarning(newVal)
{
if (!newVal)
{
this.nextRoute = null;
}
},
},
created()
{
events.$on(PAGE_LEAVE, this.discard);
window.addEventListener('beforeunload', this.pageLeave);
},
beforeDestroy()
{
events.$off(PAGE_LEAVE, this.discard);
window.removeEventListener('beforeunload', this.pageLeave);
},
methods:
{
discard(to, from, next)
{
if (this.value)
{
this.nextRoute = next;
this.showUnsavedWarning = true;
}
else next();
},
pageLeave(e)
{
if (this.value)
{
const confirmationMsg = this.$t('leave_page');
(e || window.event).returnValue = confirmationMsg;
return confirmationMsg;
}
},
ignoreUnsaved()
{
this.showUnsavedWarning = false;
if (this.nextRoute) this.nextRoute();
},
}
};
</script>
<i18n>
{
"en": {
"confirm_page_leave": "Unsaved changes",
"unsaved_changes": "If you leave this page, any unsaved changes will be lost.",
"ignore_changes": "Leave page",
"go_back": "Cancel",
"leave_page": "You're leaving the page but there are unsaved changes.\nPress OK to ignore changes and leave the page or CANCEL to stay on the page."
}
}
</i18n>

I want to add editing functions using Nuxt.js

What I want to come true
I am creating TodoLists.
I tried to implement the following editing features, but it didn't work and I'm having trouble.
Click the edit button to display the edit text in the input field
If you click the save button after entering the changes in the input field, the changes will be reflected in the first position.
Code
<v-row v-for="(todo,index) in todos" :key="index">
<v-text-field
filled
readonly
:value="todo.text"
class="ma-3"
auto-grow
/>
<v-menu
top
rounded
>
<template #activator="{ on, attrs }">
<v-btn
v-bind="attrs"
icon
class="mt-6"
v-on="on"
>
<v-icon>
mdi-dots-vertical
</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item
link
>
<v-list-item-title #click="toEdit(todos)">
<v-icon>mdi-pencil</v-icon>
Edit
</v-list-item-title>
</v-list-item>
</v-list>
<v-list>
<v-list-item
link
>
<v-list-item-title #click="removeTodo(todo)">
<v-icon>mdi-delete</v-icon>
Delete
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-row>
<v-text-field
v-model="itemText"
filled
color="pink lighten-3"
auto-grow
#keyup.enter="addTodo"
/>
<v-btn
:disabled="disabled"
#click="addTodo"
>
Save
</v-btn>
data () {
return {
editIndex: false,
hidden: false,
itemText: '',
items: [
{ title: 'Edit', icon: 'mdi-pencil' },
{ title: 'Delete', icon: 'mdi-delete' }
]
}
},
computed: {
todos () {
return this.$store.state.todos.list
},
disabled () {
return this.itemText.length === 0
}
},
methods: {
addTodo (todo) {
if (this.editIndex === false) {
this.$store.commit('todos/add', this.itemText)
this.itemText = ''
} else {
this.$store.commit('todos/edit', this.itemText, todo)
this.itemText = ''
}
},
toEdit (todo) {
this.editIndex = true
this.itemText = this.todos
},
removeTodo (todo) {
this.$store.commit('todos/remove', todo)
}
}
}
</script>
export const state = () => ({
list: []
})
export const mutations = {
add (state, text) {
state.list.push({
text
})
},
remove (state, todo) {
state.list.splice(state.list.indexOf(todo), 1)
},
edit (state, text, todo) {
state.list.splice(state.list.indexOf(todo), 1, text)
}
}
Error
Click the edit button and it will look like this
What I tried myself
//methods
toEdit (todo) {
this.editIndex = true
this.itemText = this.todos.text //add
},
// Cannot read property 'length' of undefined
For some reason I get an error that I couldn't see before
The properties/data types in your code are a bit mixed up.
Here you're accessing state.todos.list...
todos () {
return this.$store.state.todos.list
},
...but in your store the const state doesn't include todos:
export const state = () => ({
list: []
})
Furthermore, you're writing to itemText the content of todos, which should be a string but actually is an object - which leads to the output of [object Object].
toEdit (todo) {
this.editIndex = true
this.itemText = this.todos
},
Also, please check out kissu's comment about the mutations.

want to use vuetify snackbar as a global custom component in vuejs

i used snackbar to show success messages in vuejs. i want to make a global custom snackbar component.
<template>
<div name="snackbars">
<v-snackbar
v-model="snackbar"
:color="color"
:timeout="timeout"
:top="'top'"
>
{{ text }}
<template v-slot:action="{ attrs }">
<v-btn dark text v-bind="attrs" #click="snackbar = false">
Close
</v-btn>
</template>
</v-snackbar>
</div>
</template>
<script>
export default {
props: {
snackbar: {
type: Boolean,
required: true,
},
color: {
type: String,
required: false,
default: "success",
},
timeout: {
type: Number,
required: false,
default: 3000,
},
text: {
type: String,
required: true,
},
},
};
</script>
then i import this as a component in my every form like this.
<SnackBar :snackbar="snackbar" :color="color" :text="text" />
but my issue is i can't use snackbar as a prop in my child component. it shows me this error.
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "snackbar"
how can i fix this issue. can anyone help me?
I realize this is old, but thanks to google, I am going to add my solution.
I use this, because I don't see the point of using vuex for a snackbar. It's more work then needed.
Create a vue component named vtoast
<template>
<v-snackbar
:color="color"
:timeout="timer"
v-model="showSnackbar"
bottom
right
>
<v-icon left>{{icon}}</v-icon>{{message}}
</v-snackbar>
</template>
<script>
export default {
name: "vtoast",
data() {
return{
showSnackbar: false,
message: '',
color: 'success',
icon: 'mdi-check',
timer: 3000
}
},
methods:{
show(data) {
this.message = data.message || 'missing "message".'
this.color = data.color || 'success'
this.timer = data.timer || 3000
this.icon = data.icon || 'mdi-check'
this.showSnackbar = true
}
}
}
</script>
Somewhere in the root of your main app, add the following. (I usually put mine in App.vue)
<template>
...
<!-- toast -->
<vtoast ref="vtoast"/>
...
</template>
<script>
import vtoast from '#/your/vtoast/directory/vtoast'
export default{
name: 'App', //or whatever your root is
components:{
vtoast
},
mounted() {
this.$root.vtoast = this.$refs.vtoast
},
}
</script>
And access it like so...
this.$root.vtoast.show()
this.$root.vtoast.show({message: 'Ahoy there!'})
i found a way to fix my solution using vuex.
<template>
<div name="snackbars">
<v-snackbar v-model="show" :color="color" :timeout="timeout" :top="'top'">
{{ text }}
<template v-slot:action="{ attrs }">
<v-btn dark text v-bind="attrs" #click="show = false">
Close
</v-btn>
</template>
</v-snackbar>
</div>
</template>
<script>
export default {
created() {
this.$store.subscribe((mutation, state) => {
if (mutation.type === "snackbar/SHOW_MESSAGE") {
this.text = state.snackbar.text;
this.color = state.snackbar.color;
this.timeout = state.snackbar.timeout;
this.show = true;
}
});
},
data() {
return {
show: false,
color: "",
text: "",
timeout: 0,
};
},
};
</script>
in my vuex module i wrote like this
export default {
namespaced: true,
state: {
text: "",
color: "",
timeout: "",
},
mutations: {
SHOW_MESSAGE(state, payload) {
state.text = payload.text;
state.color = payload.color;
state.timeout = payload.timeout;
},
},
actions: {
showSnack({ commit }, payload) {
commit("SHOW_MESSAGE", payload);
},
},
};
then i import snackbar child component into my parent component and send data like this.
...mapActions("snackbar", ["showSnack"]),
saveDetails() {
this.showSnack({
text: "Successfully Saved!",
color: "success",
timeout: 3500,
});
}
Another solution is to use a computed value with getter and setter.
Using options api
<template>
<v-snackbar v-model="show" :color="color">
{{ message }}
<template v-slot:action="{ attrs }">
<v-btn text v-bind="attrs" #click="show = false">Close</v-btn>
</template>
</v-snackbar>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters({
message: 'snackbar/message',
color: 'snackbar/color'
}),
show: {
get() {
return this.$store.state.snackbar.show
},
set(v) {
this.$store.commit('snackbar/SET_SHOW', v)
}
}
}
}
</script>
Using composition api plugin
<template>
<v-snackbar v-model="show" :color="color">
{{ message }}
<template v-slot:action="{ attrs }">
<v-btn text v-bind="attrs" #click="show = false">Close</v-btn>
</template>
</v-snackbar>
</template>
<script>
import { defineComponent, computed } from '#vue/composition-api';
export default defineComponent({
setup(_props, { root }) {
const show = computed({
get: () => root.$store.state.snackbar.show,
set: (v) => root.$store.commit('snackbar/SET_SHOW', v),
});
const message = computed(() => root.$store.state.snackbar.message);
const color = computed(() => root.$store.state.snackbar.color);
return {
show,
message,
color,
};
},
});
</script>
A better implementation using composables here https://gist.github.com/wobsoriano/2f3f0480f24298e150be0c13f93bac20
You are having a prop and the same in data.
remove snackbar from data() as it is available from prop.
<script>
export default {
props: {
snackbar: {
type: Boolean,
required: true,
},
color: {
type: String,
required: false,
default: "success",
},
timeout: {
type: Number,
required: false,
default: 3000,
},
text: {
type: String,
required: true,
},
}
};
</script>
This is what I did with Options API with mere props and events;
Here is the Snackbar.vue component
<template>
<div class="text-center">
<v-snackbar
transition="true"
bottom
right
v-model="show"
:color="snackbar.color"
:timeout="snackbar.timeout"
class="snackbar-shadow"
>
<div class="d-flex align-start alert-notify">
<v-icon size="24" class="text-white mr-5">{{ snackbar.icon }}</v-icon>
<p class="mb-0">
<span class="font-size-root font-weight-600">{{
snackbar.title
}}</span>
<br />
{{ snackbar.message }}
</p>
</div>
<template v-slot:action="{ attrs }">
<v-btn
icon
elevation="0"
max-width="136"
:ripple="false"
height="43"
class="font-weight-600 text-capitalize py-3 px-6 rounded-sm"
color="rgba(255,255,255, .85)"
text
v-bind="attrs"
#click="show = false"
>
<v-icon size="13">fas fa-times</v-icon>
</v-btn>
</template>
</v-snackbar>
</div>
</template>
<script>
export default {
name: "snackbar",
props: {
snackbar: Object,
},
computed: {
show: {
get() {
return this.snackbar.visible;
},
set(value) {
this.$emit("closeSnackbar", value);
},
},
},
};
</script>
Here is the App.vue component
<template>
<!-- Snackbar -->
<snackbar :snackbar="snackbar" #closeSnackbar="SnackbarClose"></snackbar>
</template>
<script>
export default {
name: "app",
data() {
return {
snackbar: {
visible: false,
timeout: 2000,
color: "#11cdef",
title: "Hello",
message: null,
icon: "fas fa-bell",
},
};
},
created: { this.SnackbarShow(); }
methods: {
SnackbarShow() {
this.snackbar.visible = true;
this.snackbar.message = "Hola!👋 I'm a snackbar";
},
SnackbarClose() {
this.snackbar.visible = false;
},
},
};
</script>

VueJS - How to pass function to global component

I have a confirm dialog, which should be shown when users perform delete action. I need to make it works globally (Many pages can use this component by passing confirm message and delete function to it). However, I haven't found a way to pass a function to this component.
Thanks in advance!
ConfirmDialog component:
<template>
<v-dialog
v-model="show"
persistent
max-width="350"
>
<v-card>
<v-card-text class="text-xs-center headline lighten-2" primary-title>
{{ message }}
</v-card-text>
<v-card-actions class="justify-center">
<v-btn color="back" dark #click="close">キャンセル</v-btn>
<v-btn color="primary" dark>削除</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
export default {
data () {
return {
show: false,
message: ''
}
},
created: function () {
this.$store.watch(state => state.confirmDialog.show, () => {
const msg = this.$store.state.confirmDialog.message
if (msg !== '') {
this.show = true
this.message = this.$store.state.confirmDialog.message
} else {
this.show = false
this.message = ''
}
})
},
methods: {
close () {
this.$store.commit('closeDialog')
}
}
}
</script>
ConfirmDialog store:
export default {
state: {
show: false,
message: '',
submitFunction: {}
},
getters: {
},
mutations: {
showDialog (state, { message, submitFunction }) {
state.show = true
state.message = message
state.submitFunction = submitFunction
},
closeDialog (state) {
state.show = false
state.message = ''
}
}
}
you can get and set states easily.
try getting the value of show with ...mapState
ConfirmDialog.vue :
<template>
<v-dialog
v-if="show"
persistent
max-width="350"
>
<v-card>
<v-card-text class="text-xs-center headline lighten-2" primary-title>
{{ message }}
</v-card-text>
<v-card-actions class="justify-center">
<v-btn color="back" dark #click="close">キャンセル</v-btn>
<v-btn color="primary" dark>削除</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import { mapState } from 'vuex';
export default {
data () {
return {
show: false,
message: ''
}
},
methods: {
close () {
this.$store.commit('closeDialog')
}
},
computed: {
...mapState({
show: 'show'
})
}
}
</script>
The store is, as the name says, a store. You have a centralized tree where you save data, not functionalities. Another reason is that functions are not serializable.
You could create this component in a global way by injecting the function as prop or by using emit and handling the functionality in the parent.