Using lodash in all of vue component template - javascript

Can I use lodash _ in all of my vue component?
for example:
I have components organized like below:
App.vue > Parent.vue > Child.vue
I would like all of my component to access _ lodash without defined in every component vm data
===
I am also trying using Mixins. it works. but the result not expected like this _().isEmpty() instead of _.isEmpty()

Some of the current answers may work in your scenario, but they have downsides:
Adding to the window object means your Vue project can't be server rendered, because servers don't have access to the window object.
Importing in every file works fine, but it can be a pain if you have to remember to do it in every file.
An alternative approach is to add your library to the Vue prototype. All components inherit from this so they will now all be able to access your library from the this keyword.
import _ from 'lodash';
Object.defineProperty(Vue.prototype, '$_', { value: _ });
Now lodash is available as an instance method for all components. In a .vue file you can do this without importing anything:
export default {
created() {
console.log(this.$_.isEmpty(null));
}
}
The advantage of using Object.defineProperty rather than a normal property assignment is that you can define a descriptor which allows you to make the property read-only, which it will be by default. This stops consuming components from overwriting it.
This is more thoroughly explained in this blog post (which I wrote).
Note: The downside to this approach is that you get the entire Lodash library, even if you only need one or two functions. If that's a problem, best to use import { reduce, whatever } from "lodash"; at the top of the file requiring it.

You could import the lodash into each component:
<script>
import _ from 'lodash'
export default {
methods: {
test (value) {
return _.isEmpty(value)
}
}
}
</script>

For inline templates separated from the js module code it should work with:
Vue.component('some-tag', {
computed: {
_() {
return _;
}
}
});
And then you can use it in template in "native" way - _.isEmpty(value).

import _ from 'lodash'
Vue.prototype._ = _
Insert these lines in your main.js file and it will work all over your app.

You could import lodash globally like this
window._ = require('lodash');
Once that has been imported, you will have access to _ from anywhere.

A simple approach that worked for me:
Vue.set(Vue.prototype, '_', _);
This should allow you to use _ in all component templates and vue instances.

You can use plugin/mixin like this.
import _ from 'lodash';
exports default {
install : function(Vue, options){
Vue.mixin({
computed : {
"_" : function(){
return _;
}
}
});
}
}

Bit late to the party but through my research of finding a way to import lodash and other libraries into all my .vue files, I encountered the webpack ProvidePlugin, which achieves everything the OP requested with almost no fuss. To implement this solution, following this fantastic tutorial.
I would note that in the tutorial, he left import "jquery" in his app.js file, which is not required. The plugin with import it automatically.

Check out vue-lodash!!
It's a new wrapper for using lodash in vue.
You can call it using
Vue._.random(20) // for getting random number between 20
this._.random(20) //or other method you want to use
in any of the component file :)

The proper way is to use provide / inject as such:
import _ from 'lodash';
const app = createApp({
provide: {
$_: _,
}
});
Then in аnоthег component:
<script>
export default {
name: 'аnоthег-component',
inject: [
'$_'
]
}
</script>

You can also create a base component and make all of your components extend it.
// base-component
import _ from 'lodash';
export default Vue.extend({
computed: {
_() {
return _;
},
},
});
// my-component
import BaseComponent from 'path/to/base-vue';
export default BaseComponent.extend({
template: '<p>Lodash is available: {{!!_}}</p>'
methods: {
doSomehting() {
// `this._` should be available
},
},
});
The pro of this approach is it's not intrusive, so no possible conflict with Vue in the future. Also, you can add even more things to the BaseComponent, like other libraries and external services, and they will be available to all other components.
The con is it's more verbose and you have to remember to inherit from the base component.

For vue users
Go to main.js
import _ from 'lodash'
Vue.set(Vue.prototype, '$_', _)
For nuxt.js users
create main.js inside plugin folder
plugin/main.js
import _ from 'lodash'
Vue.set(Vue.prototype, '$_', _)
Then add into
nuxt.config.js
plugins: ['~plugins/main.js'],
usage are same in both vue and nuxt js
then use in component
this.$_.map(arra,(x)=>{})

Related

Add global variable in Vue.js 3

Anybody know how to do add a global variable in Vue 3 ?
in Vue 2 we use this in the main.js file:
Vue.prototype.$myGlobalVariable = globalVariable
The most direct replacement is app.config.globalProperties. See:
https://vuejs.org/api/application.html#app-config-globalproperties
So:
Vue.prototype.$myGlobalVariable = globalVariable
becomes:
const app = createApp(RootComponent)
app.config.globalProperties.$myGlobalVariable = globalVariable
This is scoped to a particular application rather than being global as it was with Vue.prototype. This is by design, all 'global' configuration options are now scoped to an application.
The relevant RFC is here:
https://github.com/vuejs/rfcs/blob/master/active-rfcs/0009-global-api-change.md
Properties added to globalProperties will be available via the component instance for all components within the application. So if you're using the Options API you'll be able to access them using this.$myGlobalVariable, just like you could with Vue.prototype. They'll also be available in the template without the this., e.g. {{ $myGlobalVariable }}.
If you're using the Composition API then you'll still be able to use these properties within the template, but you won't have access to the component instance within setup, so these properties won't be accessible there.
While hacks involving getCurrentInstance() can be used to access globalProperties within setup, those hacks involve using undocumented APIs and are not the recommended approach.
Instead, application-level provide/inject (also discussed in that RFC) can be used as an alternative to Vue.prototype:
const app = createApp(RootComponent)
app.provide('myGlobalVariable', globalVariable)
In the descendant component this can then be accessed using inject. e.g. With <script setup>:
<script setup>
import { inject } from 'vue'
const myGlobalVariable = inject('myGlobalVariable')
</script>
Or with an explicit setup function:
import { inject } from 'vue'
export default {
setup() {
const myGlobalVariable = inject('myGlobalVariable')
// Expose it to the template, if required
return {
myGlobalVariable
}
}
}
Or with the Options API:
export default {
inject: ['myGlobalVariable']
}
Docs: https://vuejs.org/api/application.html#app-provide
The idea here is that the component can explicitly declare the property rather than inheriting it by magic. That avoids problems like name collisions, so there's no need to use a $ prefix. It can also help to make it clearer where exactly a property is coming from.
It is common for the inject function to be wrapped in a composable. For example, the useRoute composable exposed by Vue Router is just a wrapper around inject.
In addition to globalProperties and provide/inject, there are various other techniques that might be used to solve the same problems as Vue.prototype. For example, ES modules, stores, or even global mixins. These aren't necessarily direct answers to the specific question posted here, but I've gone into more detail describing the various approaches at:
https://skirtles-code.github.io/vue-examples/patterns/global-properties.html
Which approach you prefer will depend on your circumstances.
How to add a global variable using Vue 3 and vue-cli (or Vite)
Note: You can drop the dollar sign from your $globalVariable and just use globalVariable, just like in the documentation.
Initially your main.js file looks something like this (adding router for common use case):
import { createApp } from 'vue'
import { App } from './App.vue'
import { router } from './router'
createApp(App).use(router).mount('#app')
To use add the global variable using Vue 3 and the vue-cli or Vite:
import { createApp } from 'vue'
import { App } from './App.vue'
import { router } from './router'
// 1. Assign app to a variable
let app = createApp(App)
// 2. Assign the global variable before mounting
app.config.globalProperties.globalVar = 'globalVar'
// 3. Use router and mount app
app.use(router).mount('#app')
Then to access the variables in components like this:
<script>
export default {
data() {
return {
myVar: this.globalVar
}
}
}
</script>
like in the template like this:
<template>
<h1>{{ globalVar }}</h1>
</template>
And that's it. Happy coding!
About Global Variables and Composition API
According to the very bottom of samayo's answer on this post, global variables are only available on the Options API.
Quoting the bottom of his answer:
Note: This is only for the Options API. Evan You (Vue creator) says: "config.globalProperties are meant as an escape hatch for replicating the behavior of Vue.prototype. In setup functions, simply import what you need or explicitly use provide/inject to expose properties to app.
I recommend to use provide/inject approach as follows :
in main.js :
import {createApp} from 'vue'
let app=createApp({
provide:{
globalVariable:123
}
}).$mount('#app')
in some child or grand-child component do :
export default{
name:'some-compo',
inject:['globalVariable'],
//then access this.globalVariable as property in you component
...
}
for composition api and script setup :
import { inject } from 'vue'
let globalVar=inject('globalVariable')
If possible you should use imports or provide/inject. Another way to define global variables/functions and use them would be using globalProperties (although this seems to be considered more of an anti-pattern). But if a library you use uses globalProperties then you can use it like this. This also works with global functions.
const app = Vue.createApp({})
app.config.globalProperties.$http = () => {} // global function
app.config.globalProperties.$globalVariable = 'Jimmy' // global variable
1. Using options API
mounted() {
console.log(this.$globalVariable)
}
2. Using setup method
<script setup>
import { getCurrentInstance } from 'vue'
const app = getCurrentInstance()
const progressBar = app.appContext.config.globalProperties.$globalVariable
console.log(this.$globalVariable)
</script>
For those of you who are confused about how to access globalProperties in the setup() method, you can use getCurrentInstance() as in the following documentation.
https://v3.vuejs.org/api/composition-api.html#getcurrentinstance
In my case I had to create a global var and get the data from a script.
Used provide and inject:
In main.js:
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App);
app.provide('message',document.querySelector('script[name="nameSCRIPT"]').innerHTML.split('=').slice(1).join('=').slice(1,-1));
app.mount('#app')
In index.html:
<script name="nameSCRIPT">nameSCRIPT="HELLO"</script>
In child component:
inject:['message'],
mounted(){
console.log(this.message)
},

using vuejs mixins in js file

i have a system in which i have to set up some reusable functions to be used all over my application, now i have created a vue mixin in my main main.js file now when i call that function from vue components it works just fine but when i try to call the same function inside a js file i get an error of undefined here's my code
main.js
Vue.mixin({
methods: {
test: function () {
return 1;
},
}
});
Vue Components
//this works
async created() {
alert(this.test());
}
services.js
import { API } from 'aws-amplify';
import { Auth } from "aws-amplify";
import axios from 'axios'
export default {
somefunction(){
//this doesnot work
alert(this.test());
}
}
can someone tell me how can i use vue mixins in regular js files, i looked on the internet but couldn't find anything related to this
// mixin.js
export myMixin = { computed: { foo(): 'hi' } }
Simply create an object (and likely mark it as an export) besides adding it to vue.
It's just an object. It has special names like computed, data etc. in it, but it's just an object.
// usage.vue
import { myMixin } from './path/to/myMixin.js'
console.log( myMixin.computed.foo ) // hi
export default {
mixins: [ myMixin ],
computed: { bar(): { this.foo } // hi
}
In the above example, I'm not using a global mixin, because, to quote vue docs
Use global mixins sparsely and carefully, because it affects every single Vue instance created, including third party components.
Now, if you really need a global mixin, that's why it's for, but note that to use myMixin outside of vue export default, you'd need to access it via global scope, like window, or import it like above. For more info refer to queries like these: global functions in js.
My preference:
// in a file at /path/to/index.js
export { myMixin1 } from './myMixin1' // ...
// usage.vue
import { myMixin1, myMixin2 } from './path/to'
export default { mixins: [ ... ] }
or alternatively where needed, (because mixins can include other mixins ;) though I find it harder to use them in other JS then
export myMixin1 = { ... }
export myMixin2 = {
mixins: [ myMixin1 ]
// ...
}
// usage.vue
import { myMixin2 } from 'path/to/myMixins'
export default {
mixins: [ myMixin2 ] // contains both 1 and 2
}
Note you can also declare in Vue files (single file components), and then import from them just as they were Javascript.
Also, you (obviously) don't need to export them - they're already useful for separating concerns.
// example.vue
<script>
export myMixin = { ... }
// all mixins can interact with each other
// because in the end, they will be parts of the same object
myToggle = { ... }
mySuperComplicatedBit = { ... }
// so B can call this.A
export default {
mixins: [
myMixin,
myToggle,
mySuperComplicatedBit
],
...
}
</script>
<template> ...
// other.vue or other.js
import { myMixin } from 'path/to/example.vue'
Cheers and good luck
If your mixin is generic you could use a global mixin and access it via the main application. But I don‘t really see the point, then why have a mixin in the first place?
main.js
export default new Vue({
mixins: [YourMixin]
...
})
somecode.js
import vue from ‚./main.js‘
vue.method()
Edit: suggestion
To be honest, I‘d rather turn your implementation around and have a service expose a functionality, which is then integrated to the Vue components via a mixin.
You can call methods in mixins only in Vue components. The role of the mixin is to extend the vue component. I would extract the logic from your mixin in a separate service or utility js and then use it in the mixin and service.js

Import, rename, and export a function in JavaScript?

With JavaScript what's the shortest way to import a named export, rename it, and export it again?
This code works but it feels more verbose than it should be
import { mock as myFunctionMock } from 'context/myFunction';
export const myFunction = myFunctionMock;
You can combine the import and export like so:
export { mock as myFunctionMock } from 'context/myFunction';
See MDN Docs
Note that you won't actually be able to use myFunctionMock within your code file since you haven't imported it. Neither mock nor myFunctionMock will be defined within this module.
This is a useful shorthand when you're building a library that will be used by other modules or by your end-user.
For example, if you had a utils library that you wanted to export, but you wanted to organize your util functions across several smaller files, such as stringUtils, objectUtils, dataUtils, etc, you can export the contents of those modules within your utils module to create a single, monolithic access point:
stringUtils.js
export function toLower(){}
export function toUpper(){}
objectUtils.js
export function propertyMap(){}
utils.js
export {
toLower as stringToLower,
toUpper as stringToUpper,
} from "stringUtils.js";
export {
propertyMap as objectPropertyMap
} from "objectUtils.js";
I wouldn't generally recommend this approach for internal code as it can make your dependency trees a bit wonky in some cases. It can, however, be extremely useful in situations where you want to import from a common interface but the implementation is dependent on the build (prod vs dev, web vs node, etc)
import { mock as myFunction } from 'context/myFunction';
export { myFunction };
in your original exporter, do:
module.exports = { mock: function () {...}}
When importing, do:
const myFunctionMock = require('file path of exporter');
then to reexport in the same file:
module.exports = {renamedMock: myFunctionMock};
Now any changes to mock will propagate to the other modules where it's referenced (side note, this is node.js in a nutshell).

Should I use both `import 'rxjs/Rx'` and `import { Observable } from '#rxjs/Observable'`

import { Injectable } from '#angular/core';
import { Headers, Http, Response } from '#angular/http';
import { Observable } from '#rxjs/Observable';
import 'rxjs/Rx';
import 'rxjs/add/observable/throw';
#Component({});
export shellModule{}
This is a piece of code form my Angular app that I copied from somewhere (I have removed the definitions in the exported module. I am using it to make a service to call APIs.
In the imports in this particular file, why is it that Observable is imported separately even though the entire rxjshas been imported. If a particular module is being imported in its entirety, why is a particular object from it imported separately? I tried asking this question at the forum from where I took it, but there was no answer. I want to understand if this somehow helps with optimization of code.
In general:
In Typescript, the way modules are handled would require you to either load in the entire library with the import * as rx from 'rxjs/Rx', or a specific exported module within the library to use it, so the the compiler loads in the types.
Reducing your imports to only the specific modules you need sets up your app to use tree shaking from Angular's AOT compilation. This is not done by the typescript compiler, but by a tool called rollup. So, it can help with optimizing code later, but it doesn't automatically do so.
As far as compilation overhead, bringing in the whole library might slow down the compiler a bit... but this isn't a very strong point except for massively complex libraries.
I, personally, prefer importing in specific modules because it makes the calling code a little cleaner since I don't need to use that global name to get to the specific name. rx.Observable vs Observable. A good example of this is the lodash library (rxjs is a bit more complex...)
Honestly, importing entire libraries like the line you have there: import 'rxjs/Rx' doesn't make sense to me. You should only import specific exported modules. Try removing it, seeing what errors you get, and then using the * as rx syntax instead.
As far as rxjs goes - it is a little wonky when you want to import specific operators like this question does - so the way to get specific operators is with: import 'rxjs/add/observable/from' - but that also requires a tinkering with your webpack set up as outlined in the referenced question's answer.
Let's see what the rxjs/Rx module exports:
export { Subject, AnonymousSubject } from './Subject';
export { Observable } from './Observable';
export { Operator } from './Operator';
export { Observer } from './Observer';
export { Subscription } from './Subscription';
export { Subscriber } from './Subscriber';
export { AsyncSubject } from './AsyncSubject';
export { ReplaySubject } from './ReplaySubject';
export { BehaviorSubject } from './BehaviorSubject';
...
import './add/observable/bindCallback';
import './add/observable/bindNodeCallback';
import './add/observable/combineLatest';
...
So it exports RxJs classes and also imports operators from the add folder. So as you can see it loads everything in the library. It doesn't export any global object though. So you need to use named export like this:
import * as Rx from 'rxjs/Rx'
to be able to use an exported class:
Rx.Observable.of(12, 3);
This emulates what you would have if you loaded the library using the bundle - a global Rx object:
<script src="rxjs/bundles/Rx.js">
If you want to use Observable without Rx global object, you need to import it separately:
import { Observable } from '#rxjs/Observable';
Observable.of(1);
Importing both
import { Observable } from '#rxjs/Observable';
import 'rxjs/Rx';
is not a good practice, but may be used if you don't want to import every operator separately.
Also see How to correctly import operators from the rxjs package.

Cleanest way to import/require a Vue.js directive?

I'm trying to organize my plugins into custom Vue Directives that could be a simple as:
Vue.directive('popout', {
bind() {
$(this.el).popOut();
}
});
And save these in separate files, to be imported in either the main JS file or the Vue(ify) components with something like:
require('./directives/popout.js');
I've tried a number of export default setups, but I can't seem to get it to work. What would be the cleanest (i.e. best-practice) way to do this?
I got the solution,below is the code
import Vue from 'vue';
export const global= {
bind(el, binding, vnode) {
console.log('you code');
}
};
this code goes in lets say directive/global.js file.
Then in you app.js or entry point file use this
import { global } from './directive/global.js';
Vue.directive('global', global);
first line will import the directive as we are using same name to only used global, second line to make you directive global. Hope it help.

Categories

Resources