eolant / vuetify-toast-snackbar

Basic Vue toast service that uses Vuetify Snackbar component.
MIT License
127 stars 36 forks source link

In nuxt, `$toast` is not available in context inside another plugins like axios #19

Open jralison opened 5 years ago

jralison commented 5 years ago

I have the $toast property working just fine in my components and in the store, but when I try to call it from a plugin (axios in this case), the property isn't available.

I tried this in ~/plugins/vuetify-toast-snackbar.js:

import Vue from 'vue'
import VuetifyToast from 'vuetify-toast-snackbar'

Vue.use(VuetifyToast)

export default ({ app }, inject) => {
  inject('toast', Vue.prototype.$toast)
}

And in ~/plugins/axios.js, with:

export default function ({ $axios, $toast }) {
  $axios.onError((error) => {
    if (process.client && !!$toast) {
      if (error.response) {
        $toast.error(`${error.response.status} ${error.response.statusText}`)
      } else if (error.request) {
        $toast.error('A aplicação não foi capaz de completar a requisição.')
      } else {
        $toast.error(`Algo deu errado! ${error.message}`)
      }
    }
  })
}

neither app.$toast nor ctx.$toast is available.

Can you help me to identify what might be wrong in my code? All the workaround I have tried up to here are being unsuccessful.

eolant commented 5 years ago

@jralison yes, that is an interesting one. I've spent some time to figure out how to do it and here is the workaround

You should be able to access Vue.prototype.$toast. It will definitely work with Vuetify 1.5. I'll take a look at Nuxt.js + Vuetify 2 later.

jralison commented 5 years ago

@eolant I think I found out what was my mistake.

$toast property is not available in the context object at first run of the plugin script, but it is available in ctx.app later on. So, when using object destructuring in the function argument { $axios, $toast } to extract the $toast reference, I ended up assigning $toast to a undefined.

Thus, I have to extract the app property and later then I can use that variable to access the $toast callables.

Also, instead of combining ctx.$toast = Vue.prototype.$toast and inject('toast', Vue.prototype.$toast) during vuetify-toast-snackbar initialization, I can stand with the latter statement and that's enough to make it work.

Btw, I am currently using Vuetify 2.0.4 and Nuxt 2.8.1.

Thank you for this awesome helper library and for your support.

eolant commented 5 years ago

@jralison that's great, I didn't have a chance to look at Vuetify 2 just yet, but I can say that $toast doesn't seem to be available anywhere on Vuetify 1.5 and Nuxt 2.4 and the workaround I suggested is the only way to access it.

I'll leave this open for now and maybe look at updating Readme with all of this information.

ChrisKader commented 5 years ago

Below is my configuration. I am using electron nuxt with no issues.

import Vue from 'vue'
import VuetifyToast from 'vuetify-toast-snackbar'

Vue.use(VuetifyToast, {
    x: 'right', // default
    y: 'bottom', // default
    color: 'info', // default
    icon: 'info',
    iconColor: '', // default
    classes: [
        'body-2'
    ],
    timeout: 3000, // default
    dismissable: true, // default
    multiLine: false, // default
    vertical: false, // default
    queueable: false, // default
    showClose: false, // default
    closeText: '', // default
    closeIcon: 'close', // default
    closeColor: '', // default
    slot: [], //default
    shorts: {
        custom: {
            color: 'purple'
        }
    },
    property: '$toast' // default
})
import('roboto-fontface/css/roboto/roboto-fontface.css');
import('roboto-fontface/fonts/roboto/Roboto-Thin.woff2') //100
import('roboto-fontface/fonts/roboto/Roboto-Light.woff2') //300
import('roboto-fontface/fonts/roboto/Roboto-Regular.woff2') //400
import('roboto-fontface/fonts/roboto/Roboto-Medium.woff2') //500
import('roboto-fontface/fonts/roboto/Roboto-Bold.woff2') //700
import('roboto-fontface/fonts/roboto/Roboto-Black.woff2') //900
import Vue from 'vue'
import Vuetify, { VSnackbar, VBtn, VIcon } from 'vuetify/lib'
import VuetifyToast from 'vuetify-toast-snackbar'

Vue.use(Vuetify, {
  components: {
    VSnackbar,
    VBtn,
    VIcon
  }
})
Vue.use(VuetifyToast)
module.exports = {
  mode: 'spa', // or 'universal'
  head: {
    title: 'StackThemSnacks'
  },
  loading: false,
  plugins: [
    {ssr: true, src: '@/plugins/icons.js'},
    {ssr: true, src: '@/plugins/snackstack.js'}

  ],
  modules: [
    '@nuxt/typescript-build',
    '@nuxtjs/vuetify',
  ],
          vuetify: {
            theme: {
              themes: {
                light: {
                  primary: '#1867c0',
                  secondary: '#b0bec5',
                  accent: '#8c9eff',
                  error: '#b71c1c',
                },
              },
            }
          }
};
ChrisKader commented 5 years ago

My goal over the next few days is to get this connected to Vuex so that I can do a commit to an array and produce an alert.

eolant commented 5 years ago

@ChrisKader you can use:

import Vue from 'vue'
Vue.prototype.$toast('Message from the store')
paulrad commented 5 years ago

My fix in plugins/toast.js :

import Vue from 'vue'
import VuetifyToast from 'vuetify-toast-snackbar'

Vue.use(VuetifyToast, {
  timeout: 5000,
  queuable: true
})

export default (context, inject) => {
  inject('toast', Vue.prototype.$toast)
}
hamzamihaidanielx commented 4 years ago

This does not work either "Cannot read property '$options'". No matter what. Seems pointless...

easy-ms commented 3 years ago

I'm using toast with own plugin to handle errors from API. Here's my solution that work.

plugins/axios.js

export default function ({ $axios, $toast }) {
  $axios.onError((error) => {
    $toast.error(error.response.data)
  })
}

nuxt.config.js

...
plugins: ['~/plugins/axios.js'],

modules: [
    '@nuxtjs/axios',
    '@nuxtjs/auth-next',
    '@nuxtjs/toast',
], ...