I am trying to replace loading v-tooltip's VPopper component from standard loading to asynchronous loading.
Standard loading - component loaded and working normally
import { VPopover } from 'v-tooltip'
export default {
components: {
VPopover
}
}
Asynchronous load - component not loaded correctly
export default {
components: {
VPopover: () => import('v-tooltip')
},
}
For some reason above is not working and component is not loaded correctly. Maybe because it’s not a default export but named export in the v-tooltip Vue component?
I am using Webpack in-behind.
If I load my custom component asynchronously then it works as expected. For example this is working for me:
export default {
components: {
MyCustomComponent: () => import('#/components/MyCustomComponent.vue')
}
}
Like #gugadev has noted above
The lazy module import returns a Promise with the module export, in
your case an object containing the named export. Vue don't know what
of the named exports should import, so, simply does nothing.
I found this solution that works
export default {
components: {
VPopover: () => import('v-tooltip').then(m => m.VPopover)
}
}
Related
The Ionic documentation describes how to use the Ionic lifecycle methods like ionViewWillEnter, ionViewDidEnter etc. inside Vue method.
https://ionicframework.com/docs/vue/lifecycle
I'm looking for a way to access them inside the new Vue 3 setup() method so that I can able to access the properties defined there. Is it something possible?
export default defineComponent({
...
setup(){
const list = ref([]);
// I need something like this
const ionViewDidEnter = () => {
list.value.push(...['some', 'array', 'here']);
},
return {
list,
ionViewDidEnter
};
}
});
This is now possible in a composition API style since this PR was merged
https://github.com/ionic-team/ionic-framework/pull/22970
export default defineComponent({
...,
components: { IonPage },
setup() {
onIonViewDidEnter(() => {
console.log('ionViewDidEnter!');
});
}
});
Unfortunately no, at least not yet, since the code firing the events is specifically looking for the lifecycle events to be registered as part of the component methods. Luckily I've submitted a PR which is going to fix this and allow you to define them the same way you would define mounted or any other Vue hooks.
I will make sure to add tests that cover the composition API scenario as well.
https://github.com/ionic-team/ionic-framework/pull/22241
Meaning that you'd be able to do it this way:
export default defineComponent({
...
ionViewDidEnter() {
...
},
setup(){
...
}
});
Just to add to what Mark Beech said, you will have to import onIonViewDidEnter
import { onIonViewDidEnter } from '#ionic/vue';
export default defineComponent({
...
ionViewDidEnter() {
console.log('Hompage');
},
setup(){
...
}
});
I have the problem with correctly understood the flow elements, method calling in vue js. It is the standard idea - fetching some data from rest api, and render it on the browser.
The getting method I wrote into mounted(). Also I added there calling renderHomePageMethod(). This method was written in methods:
mounted() {
axios.get("http://localhost:3000/api/test").then(response => {
this.testData= response.data
this.renderHomePageMethod();
});
}
In renderHomePageMethod() I used this.refs$ and $el. And probably there is the problem, everything is working fine, but in the browser I got warning about:
Uncaught (in promise) TypeError: Cannot read property '$el' of undefined
Probably I should calling
this.renderHomePageMethod()
in another place. But where?
It seems like your referenced component is not rendered before the main component renders, so it gives a reference error.
A hackish way would be something like this:
mounted() {
axios.get("http://localhost:3000/api/test").then(response => {
this.testData= response.data
setTimeout(() => {
this.renderHomePageMethod();
}, 1000); // or any other minimum delay before the subcomponent is rendered
});
}
or the better and harder way, create an event-bus.js file which contains:
import Vue from 'vue';
export const EventBus = new Vue();
in your main and sub components:
import { EventBus } from "./event-bus.js";
in your sub component, this will send the notification to the main component when it's ready to roll:
mounted(){
EventBus.$emit("subcomponent:is-mounted");
}
in your main component:
data(){
return {
testData: null
}
},
mounted(){
axios.get("http://localhost:3000/api/test").then(response => {
this.testData= response.data
});
EventBus.$on("subcomponent:is-mounted", () =>{
this.renderHomePageMethod();
});
},
beforeDestroy(){
EventBus.$off("subcomponent:is-mounted");
// don't forget to remove the listeners because of duplicate listeners may occur
// if your component refreshes (remounts)
}
I'm new to VueJS and I haven't found a possibility to load components based on route. For example:
page/:pageid
page/one
page/two
I have a component Page.vue
Within that component, I watch route changes. If the route is $pageid, then import and load component $pageid.
I've read this documentation: https://v2.vuejs.org/v2/guide/components-dynamic-async.html. But that's more focussed on lazy-loading. I don't see an example for dynamic importing and loading.
Regards, Peter
According to Dynamic Route Matching of vue router, you can access the url parameters via the params property of the $route object. In your case it would be $route.params.pageid so you can use it to dynamically change the content base on the pageid parameter in the url. Also note that on url change from say in your case page/one to page/two the same component would be used, so you would have to watch the $route object change and change your content dynamically.
watch: {
'$route' (to, from) {
// react to route changes...
}
}
Vue allows you to define your component as a factory function that
asynchronously resolves your component definition.
Since import() returns a promise, so you can register your async component by using:
export default {
components: {
'Alfa': () => import('#/components/Alfa'),
'Bravo': () => import('#/components/Bravo'),
'Charlie': () => import('#/components/Charlie')
}
}
Vue will only trigger the factory function when the component needs to
be rendered and will cache the result for future re-renders.
So your component will be load only when it need to be render.
And you can use dynamic component to render it by using:
<component :is='page'/>
and
export default {
computed: {
page () {
return 'Alfa'
}
}
}
If you already using vue-router you can directly use this in routes definition. See more in document here.
const router = new VueRouter({
routes: [{
path: '/alfa',
component: () => import('#/components/Alfa')
}, {
path: '/bravo',
component: () => import('#/components/Bravo')
}, {
path: '/charlie',
component: () => import('#/components/Charlie')
}]
})
As you can see this is dynamic importing but static registration (you have to provide the path to component.) which fit mostly in many situations. But if you want to use dynamic registration, you can return component directly instead of name see document here.
export default {
computed: {
page () {
return () => import('#/components/Alfa')
}
}
}
I am using nuxt.js. I have a helper.js script inside plugins folder which has a simple Test() function. Now how can I can call the Test() method inside pages which is in helper.js file.
helper.js file:
export default function Test() {
return 'This is test'
}
to access your global methods entire application:
1-create ./plugins/helpers.js .
2-edit ./plugins/helpers.js :
import Vue from 'vue'
Vue.mixin({
methods:{
mySpecialMethod(value){
console.log(value)
},
}
})
3-edit ./nuxt.config.js :
plugins: [
...
{ src: '~/plugins/helpers' },
...
],
now you can access your global method by:
this.mySpecialMethod()
Using the inject method
There is actually an easy way to do this by using the 'inject' method.
As described in the docs...
The plugins directory contains JavaScript plugins that you want to run before instantiating the root Vue.js Application. This is the place to add Vue plugins and to inject functions or constants. Every time you need to use Vue.use(), you should create a file in plugins/ and add its path to plugins in nuxt.config.js.
in your plugin simply use inject like this:
export default ({ app }, inject) => {
inject('myInjectedFunction', (string) => console.log('That was easy!', string))
}
and in your components you can use it as follows:
export default {
mounted(){
this.$myInjectedFunction('works in mounted')
},
asyncData(context){
context.app.$myInjectedFunction('works with context')
}
}
"Manual" injection
If you plan on injecting something yourself check out the Vue Docs on Adding Instance properties
There may be data/utilities you’d like to use in many components, but you don’t want to pollute the global scope. In these cases, you can make them available to each Vue instance by defining them on the prototype
Vue.prototype.$appName = 'My App'
And prefix these injected properties with '$'...
$ is a convention Vue uses for properties that are available to all instances. This avoids conflicts with any defined data, computed properties, or methods.
If you just want to use the code in your components (pages), you only need to import and use the method:
TestPage.vue
<template>
<div>
<h1>{{ getTest }}</h1>
</div>
</template>
<script>
import test from '~/plugins/helper.js'
export default {
computed: {
getTest () {
return test()
}
}
}
</script>
Hello you can inject the function globally into Vue doing the following:
./plugins/myPluging.js
import Vue from 'vue'
Vue.prototype.$nameOfMyPlugin = (args) => {
// Code here
}
Them in all your components you can access it this way:
./components/myComponent.vue
<script>
export default {
name: 'c',
mounted () {
this.$nameOfMyPlugin('something useful')
}
}
</script>
And that's it :) hope this helps.
-- Reference: https://nuxtjs.org/guide/plugins/#inject-in-root-amp-context
Below is a a custom js plugin that I have used in one of my nuxt projects.
create your file inside the plugins folder, and make your own function as below
export default (context, inject) => {
const formatDate = (dateTime) => {
if (typeof(dateTime) === 'undefined' || dateTime === null) {
return null;
}
let tempDate = new Date(dateTime);
tempDate.setMinutes(tempDate.getMinutes() -
tempDate.getTimezoneOffset());
tempDate = tempDate.toISOString().slice(0, 16);
return tempDate;
}
// Inject $hello(msg) in Vue, context and store.
inject('formatDate', formatDate)
// For Nuxt <= 2.12, also add 👇
context.$formatDate = formatDate
}
Add the plugin to nuxt.config.js and you will be able to use it globally.
myPlugin.js
export default (_, inject) => {
const myFuncA = value => return value;
const myFuncB = value => return myFuncA(1) + value;
inject('myPlugin', { myFuncA, myFuncB }
)
nuxt.config.js
plugins[
'#/plugin/myPlugin.js'
]
myComponent.vue
created(){
console.log( this.$myPlugin.funcA(2) );
}
in myPlugin.js, instead of "_" can use some public nuxt variables like {$config}
Been reading the docs and googling around for best practice to handle api calls in bigger projects without luck (or ateast not what Im searching for).
I want to create a service / facade for the backend that I can load in every component that needs it. For exampel.
I want to fetch historical data for weather in a service so in every component I need this I can just load the weather-serivce and use a getter to fetch the wanted data. I would like to end up with something like below. But I dosent get it to work. So I wonder, what is best practice for this in vue.js?
import WeatherFacade from './data/WeatherFacade.vue'
export default {
name: 'Chart',
created () {
console.log(WeatherFacade.getWeather())
},
components: {
WeatherFacade
}
}
ps. using vue 2.1.10
It could be easily done by creating some external object that will hold those data and module bundling.What I usually do in my projects is that I create services directory and group them in order I want.
Let's break it down - services/WeatherFascade.js (using VueResource)
import Vue from 'vue'
export default {
getWeather() {
return Vue.http.get('api/weather')
}
}
If you have to pass some dynamic data such as ID, pass it as just parameter
import Vue from 'vue'
export default {
getWeather(id) {
return Vue.http.get(`api/weather/${id}`)
}
}
Then in your component you can import this service, pass parameters (if you have them) and got data back.
import WeatherFascade from '../services/WeatherFascade'
export default {
data() {
return {
weatherItems: []
}
},
created() {
this.getWeatherData()
},
methods: {
getWeatherData() {
WeatherFascade.getWather(// you can pass params here)
.then(response => this.weatherItems = response.data)
.catch(error => console.log(error))
}
}
}
You can use any library for that you like, for instance axios is cool.