Is it possible to use route.meta property outside of the component? - javascript

I am using Vue 3 in my project and I used route.meta property inside the Vue component but when I moved that into .ts file it doesn't work anymore and in-browser appeared an error.
My .ts file:
import { useRoute } from "vue-router";
import { computed } from "vue";
const route = useRoute();
export const myfunction = computed(() => {
return route.meta.somedata;
});
Error from the browser:
Uncaught (in promise) TypeError: Cannot read property 'meta' of undefined
The same code works fine in .vue files.
Is there any way to use meta property outside of the .vue file?

I found a solution, firstly need to import the router file.
import router from "#/router/index";
Then using the router object we can get currentRoute.value and then access meta properties.
router.currentRoute.value.meta.someData
The final code should look like this:
import { computed } from "vue";
import router from "#/router/index";
export const myfunction = computed(() => {
return router.currentRoute.value.meta.someData;
});

Related

Vue - Property '$router' does not exist on type 'App'

Given the code below, I have a squiggle line underneath $router which says Property '$router' does not exist on type 'App'
async handleUserActions(item: TODO) {
this.menuItem = item.title;
if (item.title === 'Logout') {
await userModule.logout();
}
this.$router.push(item.link);
}
I read this answer but it doesn't seem to work. I already have a file called shims-vue.d.ts in the project that looks like this by default:
declare module "*.vue" { import Vue from "vue"; export default Vue; }
I am not sure how I should add the code suggested in the linked SO question above. I currently have it configured like this, which is taken from the most popular answer on the linked question:
import VueRouter, { Route } from 'vue-router'
declare module "*.vue" {
import Vue from "vue";
export default Vue;
interface Vue {
$router: VueRouter
}
}
But in this case the line import Vue from "vue"; has a red squiggle line below "vue" which says Cannot find module 'vue' or its corresponding type declarations when hovered.
Not sure what is going on here. I know that an app can run with some of these warnings, but I am having some issues with the router and think this may be causing the problem.
Any help much appreciated.

How do I access Vue instance inside a js file in Vue3?

In Vue2, I was able to access my Vue instance to make use of components registered with Vue.
test.js
import Vue from 'vue'
export function renderLogin () {
Vue.toasted.show('Please login again', { type: 'error', duration: 2000 })
}
In the above code, I am able to access the toasted package as I have already registered it with Vue in my main.js. However, in Vue3 I'm unable to use the toasted package as I'm unable to access the Vue instance inside a js file.
Need help on how to access Vue instance('this') inside a js file.
After a day of searching, I was able to access the toasted component from the vue instance inside a js file.
First, we would have to export the app instance to be able to read it in a js file
main.js
export const app = createApp({
render() {
return h(AppWrapper);
},
});
Next, we would have to register our component in our globalProperties of our app's instance.
app.config.globalProperties.$toast = toast;
We can now import the app instance in our js file and access toast component
test.js
import { app } from '#/main.js'
app.config.globalProperties.$toast('Toast working fine', {
type: 'success',
duration: 2000,
})
Hope this helps someone out. Please let me know if there are other/better ways. Thank you
// Vue 3 Composition API
<script>
import { getCurrentInstance } from 'vue';
export default {
setup() {
const _instance = getCurrentInstance();
const vueInstance = _instance.appContext;
},
};
</script>
It's not exactly the way as in Vue2, but this will probably expose what you are looking for.
If you want to make a package globally available in Vue3 you probably need to add the following code to a plugin:
//* This will help for accessing the toasted instance in other files (plugins)
app.config.globalProperties.$toasted = toasted;
//* This will expose the toasted instance in components with this.$toasted
app.provide('$toasted', toasted);
With this you are able to get the toasted instance in the options api with: this.$toasted
And with the composition api:
const { $toasted } = _instance.appContext.app.config.globalProperties;
And in another plugin with:
constructor(app) { app.config.globalProperties; }
You can use provider/inject.
For example if you want to use axios across my components, provide axios in your main.js
import { createApp } from "vue";
import App from "./App.vue";
import axios from "axios";
const app = createApp(App);
app.provide("http", axios);
app.mount("#app");
Then in SFC component you could access by 2 ways:
// Composition API
<script>
import { inject } from 'vue'
export default {
setup() {
const http = inject("http");
http.get("https://jsonplaceholder.typicode.com/todos/1").then((response) => {
console.log(response.data);
});
}
}
</script>
// Vue 2 options API
<script>
export default {
inject: ["http"],
}
</script>
Original answer here.

Javascript working before page rendering in Gatsby

I try to convert a HTML template (Bootstrap 5) to Gatsby template. CSS and pages working expected but in HTML template there is a main.js file and it need to load after page rendered.
I modify the main.js file like that;
import { Swiper } from "swiper/swiper-react.cjs.js";
import GLightbox from "glightbox/dist/js/glightbox.min.js";
import AOS from "aos";
AOS.init();
export const onClientEntry = () => {
window.onload = () => {
console.log("deneme");
/*rest of code*/
};
};
In here I try two way. One of them, I create main.js file inside src->components->assets->js folder. Then in layout.js I try to import that file.
import React from "react";
import PropTypes from "prop-types";
import { Breadcrumb } from "gatsby-plugin-breadcrumb";
import Header from "./partials/header";
import { Helmet } from "react-helmet";
import useSiteMetadata from "./hooks/siteMetadata";
import "./assets/css/style.css";
import "./assets/js/main.js"
However in here in debug not hit the any method inside onClientEntry. So I decide to change my way.
Secondly, I try to add code inside main.js to gatsby-browser.js. That's time again getting Cannot read property 'addEventListener' of null because of html is not ready yet.
My file structure:
window (and other global objects like document) are not available during the SSR (Server-Side Rendering) because this action is performed by the Node server (where for obvious reasons there's no window, yet) so you can't access directly to onload function. In addition, accessing these global objects outside the scope of React (without hooks) can potentially break React's hydration process.
That said, you have a few approaches:
Using React hooks. Specifically, useEffect with empty dependencies ([]) fits your specifications, since the effect will be fired once the DOM tree is loaded (that's what empty deps means):
const Layout = ({children}) => {
useEffect(()=>{
mainJs();
}, [])
return <main>{children}</main>
}
Assuming that your ./assets/js/main.js file has a mainJs() function exported, this approach will load it when the DOM tree is loaded. For example:
const mainJs= ()=> console.log("deneme");
The console.log() will be triggered when the HTML tree is built by the browser. Tweak it to adapt it to your needs.
Adding a window-availability condition like:
export const onClientEntry = () => {
if(typeof window !== 'undefined'){
window.onload = () => {
console.log("deneme");
/*rest of code*/
};
}
};
Alternatively, you can output the console.log directly in your onClientEntry, depending on your needs:
export const onClientEntry = () => {
console.log("deneme");
/*rest of code*/
};
You can even combine both approaches by adding a useEffect in your gatsby-browser if it works for you.

How do I access the Vue object within a Vuex module?

In Vue components, I can easily use imported libraries, such as vue-router. I can access the route parameter I need with this.$route.params.myVar. However, if I try to do the same within a Vuex module, I get the error: TypeError: Cannot read property 'myVar' of undefined. How can I extend the Vue object I defined in my main.js to my modules?
Here's my main.js:
import router from './router'
import Vuex from 'vuex'
import myModule from './my.module';
Vue.use(Vuex)
// Register VueX modules
const store = new Vuex.Store({
modules: {
myModule
}
})
new Vue({
router,
render: h => h(App),
store
}).$mount('#app')
And my.module.js:
export default {
namespaced: true,
state: {
...
},
mutations: {
...
},
actions: {
someAction() {
console.log(this.$route.params.myVar)
}
}
}
Obviously, this isn't defined. I tried instantiating a new Vue object at the top of my module like so:
var vm = new Vue()
And changing this to vm, but I get a similar Cannot read property 'myVar' of undefined error. I also tried re-instantiating the route class at the the module:
import route from 'vue-router'
And changing my failing code to route.params.myVar, but I still get the Cannot read property 'myVar' of undefined error.
The way I see it, you have two options.
Pass param.myvar from outside inside vuex action
Import router into vuex module and use it
For the second option make sure to import your router declaration and not the library. For example.
import router from '#/router'
router.currentRoute.params.myVar

Cannot read property 'ref' of undefined

I'm building a simple web app with Vue + Firebase + Vuefire and I get "Uncaught TypeError: Cannot read property 'ref' of undefined" when I try to use my Firebase db variable inside a component.
In main.js
Vue.use(VueFire)
const firebaseApp = Firebase.initializeApp({ //setting })
// Export the database for components to use.
export const db = firebaseApp.database()
And in my component
// in Recipes.vue
import {db} from '../main.js'
export default {
recipe: {
source: db.ref('recipes')
// Console says: "Uncaught TypeError: Cannot read property 'ref' of undefined"
}
}
I followed the steps in this tutorial https://alligator.io/vuejs/vuefire-firebase/
This code db.ref('recipes') works if used inside main.js, but it never works once I import it inside my component.
The problem was my Firebase code (including db variable) was inside main.js but it needed to be in it's own component. I created a firebase.js file :
import Firebase from 'firebase'
const firebaseApp = Firebase.initializeApp({
# configuration
})
// Export the database for components to use.
export const db = firebaseApp.database()
Then in my component I simply imported my database variable :
import {db} from '../firebase'
Why didn't it work inside main.js? I'm not sure, maybe someone more knowledgeable can answer that.
.ref is a firebase function, you need to import it. try
import Firebase from 'firebase'
or
import * from 'firebase'

Categories