I am using vue 2.6.14 + composition-api 1.6.2
I want to upgrade the app as vue 2.7 (surely, remove composition-api)
I am using two repositories,
one is the main and the other is UMD library.
(both use vue, vue-cli)
The problem is, it looks like there is no active instance at UMD library.
Please look below codes
// repo B(the UMD library) > someComponent.vue
<template>
...
</template>
<script>
import { getCurrentInstance } from 'vue';
export default {
...
setup() {
const vm = getCurrentInstance();
console.log(vm); // <- null
...
onMounted(...); // <- [Vue warn] onMounted is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup().
}
}
// repo A(the main) > somePage.vue
<template>
...
<someComponent>...</someComponent>
</template>
<script>
import { getCurrentInstance } from 'vue';
import { someComponent } from '#some-company/design-system';
...
export default {
...
components: {
someComponent
},
setup() {
const vm = getCurrentInstance();
console.log(vm); // <- VueComponent (It works well!)
...
onMounted(...); // No warning has logged (It works well!)
}
}
Thanks for your answer.
Related
I just migrated my project created in vue 3 to nuxt 3. Previously I used the vue-toastification module but now I don't know how to import it correctly. My code using this module.
import { useToast, POSITION } from 'vue-toastification'
const toast = useToast()
export default {
methods: {
copy(text) {
toast.success('Copied!', {
timeout: 2000,
position: POSITION.BOTTOM_CENTER,
})
navigator.clipboard.writeText(text)
}
}
}
In Vue I had to do app.use(Toast) but Nuxt does not have an index.js file. Adding modules: ['vue-toastification/nuxt'] in nuxt.config.js does not work because I get an error.
Answers suggested by kissu and Ricardo de Paula worked for me while I was using development server (npm run dev).
After building and running the project I encountered error 500:
Named export 'useToast' not found. The requested module 'vue-toastification' is a CommonJS module, which may not support all module.exports as named exports. CommonJS modules can always be imported via the default export, for example using: import pkg from 'vue-toastification';
To fix this, I registered toast as plugin helper (I'm using Nuxt 3.1.1 with Nitro 2.1.1):
Inside vue-toastificaton.client.js:
import { defineNuxtPlugin } from '#app'
import * as vt from 'vue-toastification'
import '#/assets/css/toast.scss'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(vt.default)
return {
provide: {
toast: vt.useToast()
}
}
})
Then in my component script setup:
//throws an error after production build
//import { useToast } from 'vue-toastification'
//const toast = useToast()
//toast.success('Yay!!!')
//works after production build
const { $toast } = useNuxtApp()
$toast.success('Yay!!!')
If you want it to be available globally, you can install it as a Nuxt plugin as explained in the official docs or in this other answer.
vue-toastification is probably a client-side only plugin, hence you would probably want to use it as
/plugins/vue-toastificaton.client.js like this
import { defineNuxtPlugin } from '#app'
import Toast from "vue-toastification"
import "vue-toastification/dist/index.css" // if needed
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.use(Toast)
})
Then, you should be able to use it in your components with either Composition API or Options API (I think).
I was wanting to do the same thing. I read kissu's answer and did the following:
1 - I created a folder for the puglin - plugins
2 - Inside the plugins folder I created a file called vue-toastificaton.client.js
Inside vue-toastificaton.client.js:
import { defineNuxtPlugin } from '#app'
import Toast from 'vue-toastification'
import 'vue-toastification/dist/index.css' // if needed
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(Toast)
})
And I used it that way:
<script setup>
import { useToast } from 'vue-toastification'
const toast = useToast()
const onSubmit = () => {
// use the toast notification plugin to show a success message
toast.success('Hello world!')
}
</script>
I am finally starting to play around with Vue 3 and am migrating an app from Vue 2 + Buefy to Vue 3 + Oruga.
In the Oruga docs it looks like every example for importing a component or programatic component uses the composition API.
The Notification component for example imports the programatic component into the app/components/view's setup function which is using the composition API
import { defineComponent } from 'vue'
import { useProgrammatic } from '#oruga-ui/oruga-next'
import NotificationForm from './_notification-form.vue'
export default defineComponent({
setup() {
const { oruga } = useProgrammatic()
function toast() {
oruga.notification.open({
message: 'Something happened correctly!',
rootClass: 'toast-notification',
position: 'top'
})
}
The other examples show the Vue app importing either all of Oruga, or each component at a root level:
import { createApp } from 'vue'
import Oruga from '#oruga-ui/oruga-next'
import '#oruga-ui/oruga-next/dist/oruga.css'
createApp(...).use(Oruga);
------------------
import { createApp } from 'vue'
import { OAutocomplete, OSidebar } from '#oruga-ui/oruga-next'
import '#oruga-ui/oruga-next/dist/oruga.css'
createApp(...)
.component(OAutocomplete)
.component(OSidebar)
I however, would like to import components into my components/views which are using the options API (which I prefer), how would I do that?
I tried to import things as I would in in Vue2, but I get warnings like: 'Failed to resolve component: o-button'
import { OButton } from '#oruga-ui/oruga-next';
export default {
components: {
OButton
}
}
Or in the case of the programmatic notification I get 'Uncaught TypeError: Cannot read properties of undefined (reading 'open')':
import { useProgrammatic } from '#oruga-ui/oruga-next';
const { oruga } = useProgrammatic()
export default {
methods: {
onAlert() {
oruga.notification.open({
message: 'Something happened correctly!',
rootClass: 'toast-notification',
position: 'top'
})
},
},
}
Vue composables should be called inside the setup function or setup script only, so calling useProgrammatic under the script tag is wrong, what you should do instead is something like this:
import { useProgrammatic } from '#oruga-ui/oruga-next';
export default {
setup() {
const { oruga } = useProgrammatic()
return {
oruga
}
},
methods: {
onAlert() {
this.oruga.notification.open({
message: 'Something happened correctly!',
rootClass: 'toast-notification',
position: 'top'
})
},
},
}
and about calling the components, I tested what you did and it works fine, I think you need to re-install the package because maybe something went wrong
Please check this sample for more details: stackblitz
I'm working with typescript and vue.
In my app there is a service which is a global for every sub component.
I found this native vue solution on vue JS to inject this property on the child components.
on main.ts
const service = new MyService(...);
new Vue({
router,
provide() { return { service }; } // provide the service to be injected
render: h => h(App),
}).$mount("#app");
on any typescript vue component
import Vue from "vue";
export default Vue.extend({
inject: ["service"], // inject the service
mounted() {
console.log(this.service); // this.service does exists
},
});
This way I'm able to get the injected service on my Child components.
However I'm getting the fallowing error
Property 'service' does not exist on type 'CombinedVueInstance < Vue, {}, {}, {}, Readonly < Record < never, any > > >'.
How can I solve this typescript compilation error?
You don't need to use class components in order to get this. For object component declaration you have two ways of doing it:
Patching data return type
export default {
inject: ['myInjection'],
data(): { myInjection?: MyInjection } {
return {}
},
}
The downside is that you'll have to mark it as optional to be able to add it do data return.
Extending Vue context
declare module 'vue/types/vue' {
interface Vue {
myInjection: MyInjection
}
}
export default {
inject: ['myInjection'],
}
Using plugins
If you whant to use some service in all Vue components, you can try to use plugins.
In main.ts you just import it:
import Vue from "vue";
import "#/plugins/myService";
In plugins/myService.ts you must write someting like this:
import _Vue from "vue";
import MyService from "#/services/MyService";
export default function MyServicePlugin(Vue: typeof _Vue, options?: any): void {
Vue.prototype.$myService = new MyService(...); // you can import 'service' from other place
}
_Vue.use(MyServicePlugin);
And in any vue component you can use this:
<template>
<div> {{ $myService.name }}</div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
#Component
export default class MyComponent extends Vue {
private created() {
const some = this.$myService.getStuff();
}
}
</script>
Don't forget to declare $myService on d.ts file. Somewhere in your project add file myService.d.ts with the following content:
import MyService from "#/services/MyService";
declare module "vue/types/vue" {
interface Vue {
$myService: MyService;
}
}
Using Vue property decorator
Vue-property-decorator, which internally re-exports decorators from vue-class-component, expose a series of typescript decorators that give really good intellisense. You must use the class api though.
#Inject and #Provide are two of such decorators:
In the provider:
import {Vue, Component, Provide} from 'vue-property-decorator';
#Component
export default class MyClass {
#Provide('service') service: Service = new MyServiceImpl(); // or whatever this is
}
In the provided component:
import {Vue, Component, Inject} from 'vue-property-decorator';
#Component
export default class MyClass {
#inject('service') service!: Service; // or whatever type this service has
mounted() {
console.log(this.service); // no typescript error here
},
}
This I think is the optimal solution, in the sense it gives the better intellisense available when working with Vue.
Now, however, you may don't want to change the definition of all your components or simply cannot due to external constraints. In such case you can do the next trick:
Casting this
You can cast this to any whenever you're about to use this.service. Not probably the best thing, but it works:
mounted() {
console.log((this as any).service);
},
There must be other ways, but I'm not used to Vue.extends api anymore. If you have the time and the opportunity, I strongly suggest you to switch to the class API and start using the vue-property-decorators, they really give the best intellisense.
Extend Vue for injected components only
Create an interface for the injection and extend Vue for the specific components where it is needed:
main.ts:
const service = new MyService(...);
export interface ServiceInjection {
service: MyService;
}
new Vue({
router,
provide(): ServiceInjection { return { service }; } // provide the service to be injected
render: h => h(App),
}).$mount("#app");
A components that uses your interface
import Vue from "vue";
import { ServiceInjection } from 'main.ts';
export default ( Vue as VueConstructor<Vue & ServiceInjection> ).extend({
inject: ["service"], // inject the service
mounted() {
console.log(this.service); // this.service does exists
},
});
I am trying to use VueRangedatePicker and I can't seem to figure out how to use this on the template of some other vue component. I am using Webpack.
I have registered the component/plugin on my main.js file like this:
import Vue from 'vue'
import App from './App'
import router from './router'
import { store } from './store/store'
import firebase from './firebase-config'
import vuefire from 'vuefire'
//////////////// HERE
import VueRangedatePicker from 'vue-rangedate-picker' // importing the plugin here
Vue.use(VueRangedatePicker) // using it
Vue.component('VueRangedatePicker', { }) // creating the component globally (if I don't add this line the app complains the component is not registered
////////////////
Vue.config.productionTip = false
let app;
Vue.use(vuefire)
firebase.auth().onAuthStateChanged(function(user){
if (!app) {
/* eslint-disable no-new */
app = new Vue({
el: '#app',
template: '<App/>',
components: { App, VueRangedatePicker },
router,
store,
VueRangedatePicker
})
}
})
Then on my component component_A.vue I am again importing the VueRangedatePicker plugin in the following manner:
<template>
<div>
<vue-rangedate-picker #selected="onDateSelected" i18n="EN" />
</div>
</template>
<script>
import firebase,{ itemRef } from '../firebase-config';
import VueRangedatePicker from 'vue-rangedate-picker'
export default {
firebase() {
return {
items: itemsRef,
}
},
name: 'component_A',
data () {
return {
}
},
created() {
console.log(VueRangedatePicker);
},
methods: {
onDateSelected: function (daterange) {
this.selectedDate = daterange
},
}
</script>
I know the plugin/component is registered because when I log the Vue Rangedate Picker on the console I can see the object
However I am getting the an error message like this
I have read the complete readme.md file on the project's github but I am still puzzled. What is Vue_Daterange_picker? Is it a plugin? Is it a component? Is it a plugin that allows me to build a component? I am quite confused. Can you clarify this for me a little better? How can I make this work?
This is because you have registered the component with an empty name.
In main.js :
Vue.component('DatePicker', VueRangedatePicker)
Then in your component use the component as :
<date-picker></date-picker>
I am a beginner in Vue.js and so this question might be duplicate or naive. I want to call functions defined in a custom javascript file within a Vue component. I did something like this.
custom.js
class API{
function testCall(){
alert("test ok");
}
}
export {API}
App.vue
<template>
<div id="app">
<img src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<testcomponent :on-click="getData">
</testcomponent>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue';
import TestComponent from './components/TestComponent.vue';
import API from './js/custom.js';
export default {
name: 'app',
components: {
HelloWorld,
TestComponent,
API
},
methods: {
getData(){
const apiObj = new API();
apiObj.testCall();
}
}
}
</script>
When I build using npm run build, I get below error.
Any help with this please?
1: To define methods in a class you do not need function keyword.
class API{
testCall(){
alert("test ok");
}
}
2: Since you are doing a named export using export {API}, your import statement should be
import {API} from './js/custom.js';
3:components options is for registering vue components locally. Since API is not a vue component remove it from the components option.
API is not a Vue component - you should not include it inside the components branch. Also, if this is just a bunch of utility functions you can either export them one by one or as a containing object
// util.js - individual functions
export function testCall (call) {};
export function testUser (user) {};
// Vue app
import { testCall, testUser } from 'util.js';
// util.js - object group
function testCall (call)
{
}
function testUser (user)
{
}
export default
{
testCall,
testUser
}
// Vue app
import API from 'util.js';