Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue/Nuxt: How to define a global method accessible to all components?

I just want to be able to call

{{ globalThing(0) }}

in templates, without needing to define globalThing in each .vue file.

I've tried all manner of plugin configurations (or mixins? not sure if Nuxt uses that terminology.), all to no avail. It seems no matter what I do, globalThing and this.globalThing remain undefined.

In some cases, I can even debug in Chrome and see this this.globalThing is indeed defined... but the code crashes anyway, which I find very hard to explain.

Here is one of my many attempts, this time using a plugin:

nuxt.config.js:

plugins: [
    {
        src: '~/plugins/global.js',
        mode: 'client'
    },
],

global.js:

import Vue from 'vue';
Vue.prototype.globalFunction = arg => {
    console.log('arg', arg);
    return arg;
};

and in the template in the .vue file:

        <div>gloabal test {{globalFunction('toto')}}</div>

and... the result:

TypeError _vm.globalFunction is not a function


Here's a different idea, using Vuex store.

store/index.js:

export const actions = {
    globalThing(p) {
        return p + ' test';
    }
};

.vue file template: test result: {{test('fafa')}}

.vue file script:

import { mapActions } from 'vuex';

export default {

    methods: {
        ...mapActions({
            test: 'globalThing'
        }),
    }
};

aaaaaaaaand the result is.........

test result: [object Promise]

OK, so at least the method exists this time. I would much prefer not to be forced to do this "import mapActions" dance etc. in each component... but if that's really the only way, whatever.

However, all I get is a Promise, since this call is async. When it completes, the promise does indeed contain the returned value, but that is of no use here, since I need it to be returned from the method.


EDIT

On the client, "this" is undefined, except that..... it isn't! That is to say,

console.log('this', this); 

says "undefined", but Chrome's debugger claims that, right after this console log, "this" is exactly what it is supposed to be (the component instance), and so is this.$store!

I'm adding a screenshot here as proof, since I don't even believe my own eyes.

just plain not possible

like image 294
Marc Avatar asked Aug 26 '19 13:08

Marc


People also ask

Is NUXT faster than Vue?

Nuxt offers better SEO improvement with its server-side rendering feature, faster development with an auto-generic router, public share features, and management with great configuration options and meta tags methods, automatic code splitting with pre-rendered pages — all of this is impossible or extremely complex to ...

What is NuxtLink?

<NuxtLink> is a drop-in replacement for both Vue Router's <RouterLink> component and HTML's <a> tag. It intelligently determines whether the link is internal or external and renders it accordingly with available optimizations (prefetching, default attributes, etc.)

What is emit in NUXT?

What is emit in Nuxt? In NUXT any component in a page can emit an event and any other component can listen to it. To emit an event from any component use, $nuxt. $ emit ('my-custom-event') this.


2 Answers

  1. Use Nuxt's inject to get the method available everywhere
export default ({ app }, inject) => {
  inject('myInjectedFunction', (string) => console.log('That was easy!', string))
}
  1. Make sure you access that function as $myInjectedFunction (note $)
  2. Make sure you added it in nuxt.config.js plugins section

If all else fails, wrap the function in an object and inject object so you'd have something like $myWrapper.myFunction() in your templates - we use objects injected from plugins all over the place and it works (e.g. in v-if in template, so pretty sure it would work from {{ }} too).

for example, our analytics.js plugin looks more less:

import Vue from 'vue';
const analytics = {
    setAnalyticsUsersData(store) {...}
    ...
}

//this is to help Webstorm with autocomplete
Vue.prototype.$analytics = analytics;

export default ({app}, inject) => {
    inject('analytics', analytics);
}

Which is then called as $analytics.setAnalyticsUsersData(...)

P.S. Just noticed something. You have your plugin in client mode. If you're running in universal, you have to make sure that this plugin (and the function) is not used anywhere during SSR. If it's in template, it's likely it actually is used during SSR and thus is undefined. Change your plugin to run in both modes as well.

like image 21
Lili Avatar answered Sep 18 '22 15:09

Lili


https://nuxtjs.org/guide/plugins/

Nuxt explain this in Inject in $root & context section.

you must inject your global methods to Vue instance and context.

for example we have a hello.js file.

in plugins/hello.js:

export default (context, inject) => {
  const hello = (msg) => console.log(`Hello ${msg}!`)
  // Inject $hello(msg) in Vue, context and store.
  inject('hello', hello)
  // For Nuxt <= 2.12, also add 👇
  context.$hello = hello
}

and then add this file in nuxt.config.js:

export default {
  plugins: ['~/plugins/hello.js']
}
like image 71
Amin Avatar answered Sep 16 '22 15:09

Amin