148

I have a Vue 2 project that has many (50+) single-file components. I use Vue-Router for routing and Vuex for state.

There is a file, called helpers.js, that contains a bunch of general-purpose functions, such as capitalizing the first letter of a string. This file looks like this:

export default {
  capitalizeFirstLetter(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }
}

My main.js file initializes the app:

import Vue from 'vue'
import VueResource from "vue-resource"
import store from "./store"
import Router from "./router"
import App from "./components/App.vue"

Vue.use(VueResource)

const app = new Vue({
  router: Router,
  store,
  template: '<app></app>',
  components: { App },
}).$mount('#app')

My App.vue file contains the template:

<template>
  <navbar></navbar>
  <div class="container">
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // stuff
    }
  }
}
</script>

I then have a bunch of single-file components, which Vue-Router handles navigating to inside the <router-view> tag in the App.vue template.

Now let's say that I need to use the capitalizeFirstLetter() function inside a component that is defined in SomeComponent.vue. In order to do this, I first need to import it:

<template>Some Component</template>

<script>
import {capitalizeFirstLetter} from '../helpers.js'
export default {
  data() {
    return {
      myString = "test"
    }
  },
  created() {
    var newString = this.capitalizeFirstLetter(this.myString)
  }
}
</script>

This becomes a problem quickly because I end up importing the function into many different components, if not all of them. This seems repetitive and also makes the project harder to maintain. For example if I want to rename helpers.js, or the functions inside it, I then need to go into every single component that imports it and modify the import statement.

Long story short: how do I make the functions inside helpers.js globally available so that I can call them inside any component without having to first import them and then prepend this to the function name? I basically want to be able to do this:

<script>
export default {
  data() {
    return {
      myString = "test"
    }
  },
  created() {
    var newString = capitalizeFirstLetter(this.myString)
  }
}
</script>
tony19
  • 125,647
  • 18
  • 229
  • 307
Ege Ersoz
  • 6,461
  • 8
  • 34
  • 53
  • 1
    You could use a global mixin, but you would have to use `this`. – Bert Mar 05 '17 at 19:46
  • 2
    Have you considered exposing your helpers as [filters](https://vuejs.org/v2/guide/syntax.html#Filters) so they can be used directly in your templates without needing to import them? That's the strategy I'm taking and it's working out well so far. – David Weldon Mar 06 '17 at 04:18

8 Answers8

213

inside any component without having to first import them and then prepend this to the function name

What you described is mixin.

Vue.mixin({
  methods: {
    capitalizeFirstLetter: str => str.charAt(0).toUpperCase() + str.slice(1);
  }
})

This is a global mixin. with this ALL your components will have a capitalizeFirstLetter method, so you can call this.capitalizeFirstLetter(...) from component methods or you can call it directly as capitalizeFirstLetter(...) in component template.

Working example: http://codepen.io/CodinCat/pen/LWRVGQ?editors=1010

See the documentation here: https://v2.vuejs.org/v2/guide/mixins.html

tony19
  • 125,647
  • 18
  • 229
  • 307
CodinCat
  • 15,530
  • 5
  • 49
  • 60
  • 33
    It would be nice to have more details in this answer like how do you store the mixin function in its own dedicated file and how do you import it in main.js? – Alexis.Rolland Jan 26 '19 at 06:25
  • How can I use `capitalizeFirstLetter` from a `const vm = new Vue()` instance? Because `vm.capitalizeFirstLetter` doesn't works. – Marcelo Rodovalho Feb 15 '19 at 19:25
  • Will all components be referencing the `capitalizeFirstLetter` function in the mixin or will they have their own copy of it? I'm looking for a place to store a function which should be accessible to every component, but otherwise be unrelated to them (fetch data from a server to store in a vuex storage) – Daniel F Jul 11 '19 at 14:33
  • Thanks ! It works well in components but not in "store.js". I have a mixin who customise the "console.log" : "log: str => console.log('%c ' + str + ' ', 'background:#aaa; color:#fff; padding: 5px; border-radius: 5px')". How can I use it in store.js please ? – bArraxas Jan 08 '20 at 09:26
  • Who don't understand how to call: need added Vue.mixin in your main.js, not .vue file ;) – falselight Jan 17 '20 at 11:23
78

Otherwise, you could try to make your helpers function a plugin:

import Vue from 'vue'
import helpers from './helpers'

const plugin = {
  install () {
    Vue.helpers = helpers
    Vue.prototype.$helpers = helpers
  }
}

Vue.use(plugin)

In your helper.js export your functions, this way:

const capFirstLetter = (val) => val.charAt(0).toUpperCase() + val.slice(1);
const img2xUrl = (val) => `${val.replace(/(\.[\w\d_-]+)$/i, '@2x$1')} 2x`;

export default { capFirstLetter, img2xUrl };

or

export default { 
  capFirstLetter(val) {
    return val.charAt(0).toUpperCase() + val.slice(1);
  },
  img2xUrl(val) {
    return `${val.replace(/(\.[\w\d_-]+)$/i, '@2x$1')} 2x`;
  },
};

You should then be able to use them anywhere in your components using:

this.$helpers.capitalizeFirstLetter()

or anywhere in your application using:

Vue.helpers.capitalizeFirstLetter()

You can learn more about this in the documentation: https://v2.vuejs.org/v2/guide/plugins.html

tony19
  • 125,647
  • 18
  • 229
  • 307
Hammerbot
  • 15,696
  • 9
  • 61
  • 103
  • 1
    Hey, I tried your method but why I can't seem to access Vue.helpers ? this.$helpers is accessible. I need to access from outside component. Anyone can help me would be appreciated. Thanks – Rifqi Sep 21 '20 at 06:42
27

Create a new mixin:

"src/mixins/generalMixin.js"

Vue.mixin({
  methods: {
    capitalizeFirstLetter(str) {
        return str.charAt(0).toUpperCase() + str.slice(1);
    }    
  }
})

Then import it into your main.js like:

import '@/mixins/generalMixin'

From now on you will be able to use the function like this.capitalizeFirstLetter(str) within your component script or without this in a template. i.e.:

<template>
    <div>{{ capitalizeFirstLetter('hello') }}</div>
</template>

You have to use this because you mixed a method into the main Vue instance. If there are ways of removing this it will probably involve something unconventional, this at least is a documented way of sharing functions which will be easy to understand for any future Vue devs to your project.

tony19
  • 125,647
  • 18
  • 229
  • 307
digout
  • 4,041
  • 1
  • 31
  • 38
7

Using Webpack v4

Create a separate file for readability (just dropped mine in plugins folder). Reproduced from @CodinCat and @digout responses.

//resources/js/plugins/mixin.js
import Vue from 'vue';
    
Vue.mixin({
  methods: {
    capitalizeFirstLetter: str => str.charAt(0).toUpperCase() + str.slice(1),
    sampleFunction() {
      alert('Global Functions');
    },
  }
});

Then, import in your main.js or app.js file.

//app.js
import mixin from './plugins/mixin';

USAGE:

Call this.sampleFunction() or this.capitalizeFirstLetter().

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
DAVID AJAYI
  • 1,912
  • 20
  • 13
3

Use a global filter if it only concerns how data is formatted when rendered. This is the first example in the docs:

{{ message | capitalize }}
Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})
tony19
  • 125,647
  • 18
  • 229
  • 307
ellisdod
  • 1,644
  • 10
  • 11
  • Just a note (as I'm learning), Vue 3 has dropped the filter. Just in case anyone sees this and is on Vue 3 :) – cbloss793 Aug 08 '23 at 14:47
0

Great question. In my research I found vue-inject can handle this in the best way. I have many function libraries (services) kept separate from standard vue component logic handling methods. My choice is to have component methods just be delegators that call the service functions.

https://github.com/jackmellis/vue-inject

user3525949
  • 189
  • 1
  • 2
  • 10
0

Here is another way to do so, the way I use global helpers. First, I create a src/utils/ directory and create helpers.js file that includes the following:

import Vue from 'vue'
const { t } = require('typy')

export function range(start, end) {
    if (!t(start).isNumber || !t(end).isNumber) return

    return Math.floor(Math.random() * (end - start + 1)) + start
}

export function testHelper() {
    console.log('helper called ---')
    return
}

Object.defineProperties(Vue.prototype, {
    $help: {
        get() {
            return {
                range,
                testHelper
            }
        }
    }
})

Then, this file should be inserted into the main.js file as follows:

import 'utils/helpers'

Then, in any component you can access is like:

this.$help.testHelper() and this.$help.range(start, end)

For me, this is a convenient way to so. To be honest, have not try out with mixin, but it also looks like proper and easy way to use helpers globally.

Hope that helps. Cheers!

Vitomir
  • 335
  • 2
  • 15
-6

Import it in the main.js file just like 'store' and you can access it in all the components.

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  store,
  router,
  render: h => h(App)
})
Tom
  • 16,842
  • 17
  • 45
  • 54