Home > Mobile >  How to create a reusable Vuetify Snackbar?
How to create a reusable Vuetify Snackbar?

Time:02-25

I'm trying to create a reusable alert/snackbar component. I declared them like this:

Snackbar.vue

<template>
    <v-snackbar transition="true" timeout="2000" :show="`${show}`" :color="`${color}`" absolute top outlined right>
        <strong>
            {{ message }}
        </strong>
    </v-snackbar>
</template>

<script>
export default {
    name: 'Snackbar',
    props: {
        show: String,
        color: String,
        message: String
    }
}
</script>
<template>
    <v-snackbar transition="true" timeout="2000" :show="`${show}`" :color="`${color}`" absolute top outlined right>
        <strong>
            {{ message }}
        </strong>
    </v-snackbar>
</template>

<script>
export default {
    name: 'Snackbar',
    props: {
        show: String,
        color: String,
        message: String
    }
}
</script>

I imported, and pass probs to them like so :

import Snackbar from '../../../components/Snackbar'

<Snackbar v-if="alert" color="alertColor" message="alertMessage" />
<Snackbar show="alert" color="alertColor" message="alertMessage" />

I've tried the 2 lines above, and these are the value of those 3 variables

  • alert = true
  • alertColor = green
  • alertMessage = create.vue?f4fe:631 DB error - insert_marketing_campaign: Duplicate entry 'TEST' for key 'MARKETING_CAMPAIGN_AK'

Result

I see no error in console, but see no snackbar either. pls help

CodePudding user response:

8!

You aren't passing props values correctly, you have to do this instead:

ps. for illustration, i added an event listener(update) to deal with a close button(remove if you dont want to use)

<Snackbar :show="alert" :color="alertColor" :message="alertMessage" v-on:update="alert = $event" />

Snackbar.vue

I changed a few things here too:

  • the way you are using props in the attributes works, but if dont need to concatenate other values, keep it simple
  • prop show must be Boolean
  • added a beautiful button if you want to use
  • v-model controls snackbar exhibition, but you can't use the prop show directly on v-model, that's why we have a computed property "show2"(very creative) that read(get) the value of prop show and emit a custom event "update" if you want to change it(set)
<template>
    <v-snackbar transition="true" timeout="2000" v-model="show2" :color="color" absolute top outlined right>
        <strong>
            {{ message }}
        </strong>
        <v-btn color="red" text @click="show2 = false">Close</v-btn>
    </v-snackbar>
</template>

<script>
export default {
  props: {
    show: Boolean,
    color: String,
    message: String,
  },
  computed: {
    show2: {
      get() {
        return this.show;
      },
      set(value) {
        this.$emit("update", value);
      },
    },
  },
};
</script>

Hope it helps! ;)

CodePudding user response:

Check this codesandbox I made: https://codesandbox.io/s/stack-71244492-vuex-snackbar-klfunf?file=/src/store/index.js

You can set up a global snackbar in your App.vue file and update it with Vuex. In your vuex store you set up an snackbar object and create a simple update mutation and show action.

// store/index.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    snackbar: { active: false, color: "", message: "", timer: 4000 }
  },
  mutations: {
    UPDATE_SNACKBAR(state, snackbar) {
      state.snackbar = snackbar;
    }
  },
  actions: {
    showSnack({ commit }, { message, color, timer }) {
      commit("UPDATE_SNACKBAR", {
        active: true,
        color: color,
        message: message,
        timer: timer
      });
    }
  }
});

Then in your App.vue you set it up like this

<v-snackbar
   v-model="snackbar.active"
   :color="snackbar.color"
   :right="true"
   :bottom="true"
   :timeout="snackbar.timer"
>
   {{ snackbar.message }}
   <template #action="{ attrs }">
      <v-btn
         color="white"
         text
         v-bind="attrs"
         @click="snackbar.active = false"
      >
         Close
      </v-btn>
   </template>
</v-snackbar>
<script>
import { mapState } from "vuex";
export default {
   name: 'App',
   data: () => ({
      drawer: false,
   }),
   computed: {        
    ...mapState(["snackbar"])    
   }
}
</script>

Then you can trigger your snackbar from any component simply by doing this

// views/Home.vue
this.$store.dispatch('showSnack', {
   message: 'Testing, main page.',
   color: 'green darken-1'
})

// views/About.vue
this.$store.dispatch('showSnack', {
   message: 'Hello from about!',
   color: 'red darken-1',
   timer: 2000
})
  • Related