Reputation: 1068
I have lodash imported globally with:
window._ = require('lodash'); // app.js
and it works fine when I use it on the code like in methods. But when I try to use it inside templates like:
{{_.get(user, 'address.name')}}
shows undefined error:
Property or method "_" is not defined on the instance but referenced during render
Why happen this? I could refactor creating a new variable and assign the value in code and it will work, but I want to use it directly on template too.
Upvotes: 0
Views: 1626
Reputation: 440
For those who prefer lodash to be available globally in all files, and/or use lodash.mixin
s.
I decided to use the app.provide and inject
it into components where I wanna use lodash in the template
. The only problem I has was that I couldn't use _
, I had to settle on $_
.
file structure
.
├── src
│ ├── components
│ │ └── BaseBtn.vue
│ └── utils
│ ├── global
│ │ └── plugins.js
│ └── plugins
│ └── lodash.js
└── main.js
main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import '@/utils/plugins/lodash'
import App from './App.vue'
import router from './router'
import registerGlobalPlugins from '@/utils/global/plugins'
import './assets/scss/index.scss'
const app = createApp(App)
app.use(createPinia())
app.use(router)
registerGlobalPlugins(app)
app.mount('#app')
src/utils/plugins/lodash.js
import _ from 'lodash'
export const lodashMixin = {
/** Converts obj keys to camelCase */
$camelCaseKeys (object) {
return _.mapKeys(object, (_value, key) => _.camelCase(key))
},
/** Pauses code for x milliseconds */
$pause (milliseconds) {
return new Promise((resolve) => setTimeout(resolve, milliseconds))
},
}
_.mixin(lodashMixin)
window._ = _
export const lodashPlugin = {
install (app) {
app.provide('$_', _)
},
}
src/components/BaseButton.vue
<template>
<button>
{{ $_.sample(['this', 'is', 'an', 'example']) }}
</button>
</template>
<script>
export default {
inject: ['$_'],
methods: {
async handleClick () {
await _.$pause(500) // this will work due to import in main.js
await this.$_.$pause(500) // this should also work via the inject
}
}
}
</script>
Upvotes: 0
Reputation: 66103
Extending on my comment: I usually discourage using third party util/helper methods inside VueJS template. This is, of course, a personal choice, but it is way simpler to let VueJS handle the rendering directly (and also guards against possible reactivity issues down the road). Therefore, you can simply use a computed property (or a method, if you need to pass arguments) to generate the string, which is inserted into the template.
Example:
computed: {
addressName() {
return _.get(this.user, 'address.name');
}
}
Then, in your template, you can simply use {{ addressName }}
to render the string. Should you require more dynamic use with more flexibility and abstraction, you can use methods instead. For example, if your path is going to be dynamic, you can then create a method that retrieves data from this.user
with a provided path
argument:
methods: {
userData(path) {
return _.get(this.user, path);
}
}
In your template you can simply use {{ userData('address.name') }}
.
Upvotes: 2
Reputation: 1242
That's probably because the rendering (so the call of the property "_") is done before his instantiation.
In your case, you may have to set window._
in the created
lifecycle callback that is called before the rendering.
But my recommendation is to set this in a "data" property of your component and even to only import and set the functions you need.
For exemple:
import clone from 'lodash/clone'
Upvotes: 1