I developed a plugin to centralize HTTP calls and need to access its function ($api) from an imported module in a component.
The following works fine:
The plugin (http-transport.js)
export default {
install: function (Vue) { ...
Vue.prototype.$api = (...)
main.js
import HTTPTransport from './http-transport/http-transport'
Vue.use (HTTPTransport);
Usage from any component.vue
methods: {
someMethod() {
this.$api(...)
}}
All the above works.
Now, I have a SFC component that imports a module
component.vue
import logic from "./LogicService.js";
The question: how can I call $api from a function within LogicService.js?
The real case is that LogicService.js imports DataService.js from which I need to call the $api function, but I guess the solution to the question solves this as well.
Thanks so much!
(vue 2.6.11)
there are couple ways to do that.
the most easy way is just import vue and call the function. but for that case you must add the plugin function as global to vue
for example. in http-transport.js
export default function (Vue) {
//add global method or property
Vue.api= function () {
// some logic ...
api();
}
//add an instance method
Vue.prototype.$api= function () {
// some logic ...
api();
}
}
function api(){
//code goes here
}
and then in your js files just import Vue and call Vue.api().
for example in LogicService.js
import Vue from "vue";
export default function(){
//call api
Vue.api();
}
the problem with this way is that you can access Vue.api only when vue finish installize (most cases that the case so no problem).
a second way you can do that is to write the plugin like that
export default function (Vue) {
//add global method or property
Vue.api= function () {
// some logic ...
api();
}
//add an instance method
Vue.prototype.$api= function () {
// some logic ...
api();
}
}
export function api(){
//code goes here
}
now the plugin is actually indepent of vue and can work by itself without vue. for example now you can do that in LogicService.js
import {api} from './http-transport.js'
api()
Related
How to access to current instance of application inside a component?
Option 1: Create a plugin
// define a plugin
const key = "__CURRENT_APP__"
export const ProvideAppPlugin = {
install(app, options) {
app.provide(key, app)
}
}
export function useCurrentApp() {
return inject(key)
}
// when create app use the plugin
createApp().use(ProvideAppPlugin)
// get app instance in Component.vue
const app = useCurrentApp()
return () => h(app.version)
Option 2: use the internal api getCurrentInstance
import { getCurrentInstance } from "vue"
export function useCurrentApp() {
return getCurrentInstance().appContext.app
}
// in Component.vue
const app = useCurrentApp()
In Vue.js version 3, you can access the current instance of an application inside a component using the getCurrentInstance() function provided by the Composition API.
Here's an example:
import { getCurrentInstance } from 'vue'
export default {
mounted() {
const app = getCurrentInstance()
console.log(app.appContext.app) // This will log the current instance of the application
}
}
Note that getCurrentInstance() should only be used in very specific situations where it's necessary to access the instance. In general, it's recommended to use the Composition API's reactive properties and methods to manage state and actions inside a component.
OK, i have a web page with some steps for the user and a mixin that handle those steps properties and logic, like current/next step value, checks to enable user advancing from each step to the next, etc.
Now i have to add a new functionality to be executed only after a certain step, so what i would like to be able to do is to call the original mixin method that is called everytime the user advance to the next step to add this functionality.
To be more clear, the mixin is (obviously) used in many pages of the webapp, so i would like to override the culprit mixin method in the component extending it, call the original mixin method to reuse its logic and then call oher methods for the new functionality.
Is it possibile?
sure you can, try it so:
// MyMixin.js
export default {
methods: {
myMethod() {
//...
}
}
}
// Component.vue
<script>
import MyMixin from 'path-to-mixins/MyMixin'
export default {
//...
mixins: [MyMixin],
methods: {
// there is overrinding you mixin method called myMethod
myMethod() {
// then some logic before to use your mixin method
// and call your mixin method as below
MyMixin.methods.myMethod()
}
}
//...
}
</script>
The previous answer does not work, in many cases...
you can directly access the function from the import but you need to bind the scope to this so the function uses your component data and/or other overriden functions
// Mixin.js
export default {
methods: {
aMethod() {
//...
}
}
}
// Component.vue
import Mixin from './Mixin'
export default {
//...
mixins: [Mixin],
methods: {
aMethod() {
// you need to bind the method to `this` when running so that the mixin uses your component data.
Mixin.methods.aMethod.call(this);
}
}
//...
}
if the mixin you are importing is already a vue constructor, this can happend if you used Vue.extend to create the mixin, in this case you need to use the options to access your method
You can access the mixin function using the options of the mixin
// Mixin.js
export default Vue.extend({
extends: OtherComponent
methods: {
aMethod() {
//...
}
}
})
// Component.vue
import Mixin from './Mixin'
export default {
//...
mixins: [Mixin],
methods: {
aMethod() {
// you need to bind the method to `this` when running so that the mixin uses your component data.
Mixin.options.methods.aMethod.call(this);
}
}
//...
}
Can I call mixin function from asyncData() method of the page component with Nuxt.js?
My code:
<template>
...
</template>
<script>
import api from "#/plugins/api/api.js"
...
export default {
...
async asyncData(context) {
...
context.apiMethodName()
...
}
...
}
...
</script>
api.js
import Vue from 'vue'
import API from '#/assets/js/api'
Vue.mixin({
methods: {
apiMethodName() { ... }
}
})
You cant call vue methods from withing asyncData, because asyncData executed before vue have an instance.
You can extract method into simple js function and call it both in asyncData and your vue method, but keep in mind that in asyncData you wont be able to access vue instance properties and other methods
You can inject mixin into app, see https://nuxtjs.org/guide/plugins#inject-in-root-amp-context
I see it is quite late for the answer, but it is possible.
template.vue
<template>
...
</template>
<script>
import api from "~/mixins/api/api"
...
export default {
...
async asyncData({context}) {
...
// You don't need to use context
// You have to use "api" like this:
const collection = await api.methods.apiMethodName()
...
// bear in mind you should return data from this function
return {
collection,
...
}
}
...
}
...
</script>
~/mixins/api/api.js
const api = {
...
methods: {
async apiMethodName() {
...
// better use here try / catch or Promise with then / catch
const data = await do_something()
...
return data
}
...
}
...
}
export api
A similar approach was tested with stack VueJS + NuxtJS and it is working on the live website https://elfinforce.com.
you can access global mixin methods like this:
app.router.app.gloablMethod()
so simple!
You need to abandon using mixins and inject your methods instead.
First; Replace your mixin method to be
export default ({ app }, inject) => {
inject('apiMethodName', () => {
return 'some data!';
})
}
Then, inside asyncData() method, call apiMethodName() function like so
async asyncData(context) {
context.app.$apiMethodName();
})
I have a vue-cli project. It means, I have 1 .vue file and main.js.
I want to call method from .vue file in main.js
But I get error that function is not defined.
How can I call inside .vue file method in main.js?
Method should be defined in .vue file NOT in main.js in new Vue{}.
I don't believe you can do it exactly the way you are asking as the .vue component is child of the parent instance defined in the main.js file and is out of scope. What you can do is define the function or functions you want to use in this way as a mix-in.
Create a separate js file to define your mixin like follows
var myMixin = {
data: function () {
return {
//
},
methods:{
myAwesomeMethod(){...}
}
}
Then import it in your main js like so:
import myMixin from '/mixins/myMixin.js';
Then reference it in your Vue instance
new Vue({
mixins: [myMixin],
})
After than you can call the method in your main.js using this.myAwesomeMethod
Alternatively you can define your mixin like follows and only import it with no need to reference it.
Vue.mixin({
methods:{
myAwesomeMethod(){
//...
}
}
});
I don't recommend it, however, if you absolutely cant make any modification to the main.js file, then you could simply define your mixin using the latter method directly in your .vue file outside of the definition for your component.
<script>
// define your mixin
Vue.mixin({
methods:{
myAwesomeMethod(){
//..
}
}
});
// define your component
export default {
data: function () {
return {
}
}
}
</script>
Then the mixin should be available to be called anywhere.
Am from Angular2 whereby i was used to services and injection of services hence reusing functions how do i achieve the same in vuejs
eg:
I would like to create only one function to set and retrieve localstorage data.
so am doing it this way:
In my Login Component
this.$axios.post('login')
.then((res)=>{
localstorage.setItem('access-token', res.data.access_token);
})
Now in another component when sending a post request
export default{
methods:{
getvals(){
localstorage.getItem('access-token') //do stuff after retrieve
}
}
}
Thats just one example, Imagine what could happen when setting multiple localstorage items when retrieving one can type the wrong key.
How can i centralize functionality eg: setting token(in angular2 would be services)
There are a few different ways to share functionality between components in Vue, but I believe the most commonly used are either mixins or custom modules.
Mixins
Mixins are a way to define reusable functionality that can be injected into the component utilizing the mixin. Below is a simple example from the official Vue documentation:
// define a mixin object
var myMixin = {
created: function () {
this.hello()
},
methods: {
hello: function () {
console.log('hello from mixin!')
}
}
}
// define a component that uses this mixin
var Component = Vue.extend({
mixins: [myMixin]
})
var component = new Component() // => "hello from mixin!"
Custom module
If there are a lot of shared functionality with a logical grouping it might make sense to instead create a custom module, and import that where you need it (like how you inject a service in angular).
// localStorageHandler.js
const localStorageHandler = {
setToken (token) {
localStorage.setItem('access-token', token)
},
getToken () {
localstorage.getItem('access-token')
}
}
export default localStorageHandler
And then in your component:
// yourcomponent.vue
import localStorageHandler from 'localStorageHandler'
export default{
methods:{
getvals(){
const token = localStorageHandler.getToken()
}
}
}
Modules are using the more modern syntax of JavaScript, which is not supported in all browsers, hence require you to preprocess your code. If you are using the vue-cli webpack template it should work out of the box.