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.
Related
I am using VueClipboard in my nuxt project.
https://www.npmjs.com/package/vue-clipboard2
I have a plugin file vue-clipboard.js
import Vue from "vue";
import VueClipboard from 'vue-clipboard2';
Vue.use(VueClipboard);
It is imported into nuxt.config
plugins: ['#/plugins/vue-clipboard'],
This sets up a global variable $copyText and in nuxt without the composition API I can do something like
methods: {
async onCopyCodeToClipboard() {
const code = 'code'
await this.$copyText(code)
},
},
However inside the setup using the composition API (#nuxtjs/composition-api) when I write a function I do not have access to this.$copyText
const onCopyCodeToClipboard = async () => {
const code = context.slots.default()[0].elm.outerHTML
// -> Can't use this here - await this.$copyText(code)
}
So how do I make $copyText available to use inside the composition API?
I was able to get this to work via the Nuxt useContext() method:
import { useContext } from '#nuxtjs/composition-api'
export default function () {
const { $copyText } = useContext();
$copyText('code');
}
I have an external api file for api calls. My axios instance is bound to the main nuxt (or vue) instance.
If setup() was in my component I could get access to it with setup(props, context)
but how can I access this in an external composition function?
import { reactive} from '#vue/composition-api'
export default function api() {
//do some axios stuff ```
In your setup() function in where you are importing/using it pass it into your function.
import api from '#/use/api'
setup(_, { root }) {
const { api } = api(root)
and in your composition function
export default function api(root) {
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()
I'm re-writing my old app using Quasar Framework which is based on Vue, and I have a piece of code (class) which encapsulates websocket functionality.
It is a fairly simple concept: user travels from page to page in the app, but if he receives a message he can see a toast message/reply or a counter of unread messages increments.
I'm a little bit lost in the Quasar (Vue) architecture and here is my question:
Where would I store a global object which communicates with outside world, exists as long as the application exists and accessible from anywhere?
I read documentation of Quasar (Vue) but I still don't know where to put it. Vuex doesn't look right since it is not a state of the app. It is more like a faceless component.
Does it mean that I should use a plugin or Vue.prototype or a global mixin or something else?
I appreciate if someone can share their experience and a piece of code describing how to initialize and access this object's methods.
in my opinion:
Method 1. Use quasar plugin base on Vue prototype (sure you knew it):
plugins/foo.js
const fooModule = {
a: 1,
doTest() { console.log('doTest') }
};
export default ({Vue}) => {
Vue.prototype.$foo = fooModule;
}
quasar.conf.js
plugins: [
'i18n',
'axios',
'foo',
],
component bar.vue:
methods: {
test () { this.$foo.doTest() }
}
Method 2. Just use js module
Because js module is singleton. Wherever you import a js module, it all points to the same pointer.
So just have GlobalTest.js:
export default {
a: 1,
inc() { this.a = this.a + 1 }
}
And test1.js:
import GlobalTest from '/path/to/GlobalTest'
console.log(GlobalTest.a); // output 1
console.log(GlobalTest.inc()); // inc
And test2.js:
import GlobalTest from '/path/to/GlobalTest'
console.log(GlobalTest.a); // Assuming this was called after test1.js: output 2
I used quasar cli but I just consider quasar as a UI lib.
--- Updated ---
It is a fairly simple concept: user travels from page to page in the app, but if he receives a message he can see a toast message/reply or a counter of unread messages increments.
Depend on the requirements, If you need "reactive" you should use Vuex (best built-in reactive lib) + split the app state into modules,
but I only use Vuex when I need "reactive" and avoid it when I just need to read & write the value.
// ~/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
let store
export default function (/* { ssrContext } */) {
/* eslint-disable no-return-assign */
return store = new Vuex.Store({
modules: {...},
strict: process.env.DEV
})
}
export function ensureClientStoreExists () {
if (process.env.SERVER) {
return new Promise(() => { /* won't resolve */ })
}
if (process.env.CLIENT) {
if (store) {
return Promise.resolve(store)
}
return new Promise(resolve => {
setTimeout(resolve) // Avoid 'Maximum call stack size exceeded'
}).then(ensureClientStoreExists)
}
}
// Anywhere
import { ensureClientStoreExists } from '~/store/'
ensureClientStoreExists().then(store => {
console.log(store.state)
store.dispatch('XXX/YYY')
})
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.