VueJS passing router to child component - javascript

How Can I pass router to my child component.
I have this as my router
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
export default function () {
const Router = new VueRouter({
mode: 'history',
routes : [
{
path: '/',
beforeEnter: ifAuthenticated,
component: () => {
return import('./../container/Index.vue')
}
},
{
path: '/login',
beforeEnter: ifNotAuthenticated,
component: () => {
return import('./../container/logn.vue')
}
}
],
})
return Router
}
Now my "/" (index.vue) route have a component Navbar and the Navbar have a logout button which logs out the user and redirect them to login page
Consider this to be my index.vue (with what I have done)
<template>
<q-layout>
<Navbar :thisInfo="routerAndStore"/>
</q-layout>
</template>
<script>
import Navbar from "./../components/navbar.vue";
export default {
name: "PageIndex",
components: {
Navbar
},
data() {
return {
routerAndStore: this
};
}
};
</script>
And then in my navbar.vue I have done something like this
<template>
<div class="nav-pages-main">
<a #click="logoutUser">
<h5>Logout</h5>
</a>
</div>
</template>
<script>
export default {
name: "navbar",
methods: {
logoutUser: () => {
return this.thisInfo.$store.dispatch("GOOGLE_PROFILE_LOGOUT").then(() => {
this.$router.push("/login");
});
}
},
props: {
thisInfo: {
type: Object
}
}
};
</script>
but this doesn't seem to be working (this is coming out to be undefined), So if someone can help me figure out how we can pass this to our child component

Please refer to Vue-Router official documentation here
Basically, in their use case, the main component (index.vue) take a router as argument and provide <router-view> in its template as placeholder for component that would be rendered based on the current route.
In your code, I see that you use it the other way around using router to render the main component.
routes : [
{
path: '/',
beforeEnter: ifAuthenticated,
component: () => {
return import('./../container/Index.vue')
}
},
...
]
Could you try it again using the right way described in the documentation and tell me the result?
Edit: According to the App.vue that you posted (assuming it's the app entry point) then you should provide router to the App component.
<template>
<div id="q-app"> <router-view/> </div>
</template>
<script>
import router from '/path/to/your/router';
export default { name: "App", router };
</script>
<style>
</style>
The full code for this can be found at Vue-Router example

Related

How to get query params in Vue.js 3 setup?

I want to make search page which after I click its button will be redirected to another page. And this page will be like this
http://localhost:8080/search?q=foo
and my router index.js looks like this
const routers = [
{
path: '/search',
name: 'Search',
component: SearchPage,
props: route => ( { query: route.query.q } )
}
]
and the question is how do i get the query value in target page SearchPage, in Vue.js 3?
This Answer is still confusing me, because not using composition API and not in vuejs 3
Using useRoute
You don't need to send the query as a prop. It's better to use useRoute because it's simpler and it can be accessed from any component, not just the page view component.
import { useRoute } from 'vue-router';
export default {
setup() {
const route = useRoute();
console.log(route.query);
}
}
Using a prop
First change the router mapping so that query maps to the query object:
props: route => ({ query: route.query })
In the destination component, SearchPage, create a query prop which will receive the query object from the router:
props: ['query']
And access it in setup via the props argument:
props: ['query'],
setup(props) {
console.log(props.query.q);
console.log(props.query.status);
}
another setup you can try, send propname by url
{ path: '/search/:propname', name: 'Search', component: SearchPage, props: true },
and on searchpage, on created() you can get recive it
this.$route.params.propname
For Vue Router 4 :: Compositon API :: Vue3
Router-link attach params
<router-link
style="width: 100%"
class="btn btn-success btn-block edit"
:to="{ name: 'editUser',params: {id: user.id}}">
<i class="fa-solid fa-user-gear"></i>
</router-link>
In a page you are receiving,
<script>
export default {
props: ["id"],
setup(props, context) {
console.log(props.id);
},
};
</script>
In Your app.js
import { createApp } from 'vue';
...
...
const app = createApp(root);
app.use(router);
router.isReady().then(() => {
app.mount('#app');
})

Vue.js - Component is missing template or render function

In Vue 3, I created the following Home component, 2 other components (Foo and Bar), and passed it to vue-router as shown below. The Home component is created using Vue's component function, whereas Foo and Bar components are created using plain objects.
The error that I get:
Component is missing template or render function.
Here, the Home component is causing the problem. Can't we pass the result of component() to a route object for vue-router?
<div id="app">
<ul>
<li><router-link to="/">Home</router-link></li>
<li><router-link to="/foo">Foo</router-link></li>
<li><router-link to="/bar">Bar</router-link></li>
</ul>
<home></home>
<router-view></router-view>
</div>
<script>
const { createRouter, createWebHistory, createWebHashHistory } = VueRouter
const { createApp } = Vue
const app = createApp({})
var Home = app.component('home', {
template: '<div>home</div>',
})
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: Home },
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar },
],
})
app.use(router)
app.mount('#app')
</script>
See the problem in codesandbox.
FOR vue-cli vue 3
render function missed in createApp.
When setting your app by using createApp function you have to include the render function that include App.
in main.js
update to :
FIRST
change the second line in javascript from:-
const { createApp } = Vue
to the following lines:
import { createApp,h } from 'vue'
import App from './App.vue'
SECOND
Change from :-
const app = createApp({})
to:
const app = createApp({
render: ()=>h(App)
});
app.mount("#app")
When app.component(...) is provided a definition object (the 2nd argument), it returns the application instance (in order to allow chaining calls). To get the component definition, omit the definition object and provide only the name:
app.component('home', { /* definition */ })
const Home = app.component('home')
const router = createRouter({
routes: [
{ path: '/', component: Home },
//...
]
})
demo
Make sure you have added <router-view></router-view> in your #app container.
The solution was simple on my side, I created a component that was empty, after filling in the template and a simple text HTML code, it was fixed.
The solution for me was to upgrade node module vue-loader to version 16.8.1.
I had this issue too. It's a timing issue. I added a v-if to create the component when the page is mounted. That fixed it for me.
<review-info
v-if="initDone"
:review-info="reviewInfo"
/>
// script
onMounted(() => {
initDone = true
})
I was extending a Quasar component in Vue 3, and ran into this problem. I solved it by adding the setup: QInput.setup line last in the component options.
<script>
import { defineComponent } from 'vue'
import { QInput } from 'quasar'
const { props } = QInput
export default defineComponent({
props: {
...props,
outlined: {
type: Boolean,
default: true
},
dense: {
type: Boolean,
default: true
},
uppercase: {
type: Boolean,
default: false
}
},
watch: {
modelValue (v) {
this.uppercase && this.$emit('update:modelValue', v.toUpperCase())
}
},
setup: QInput.setup
})
</script>

How to make the vue router link connect to the vue component?

I am very new to the Vue framework, as well as Javascript, but am currently building a site using Vue and I want to have some links at the top of my site that the user can navigate to. I have tried using the Vue Router (https://router.vuejs.org/guide/#javascript) in order to make these links. At this point, I just want to make a little 'About Us' section that the user can navigate to. But, despite the URL changing accordingly to 'localhost:8080/#/about_us', the Vue component that I have associated with the link will not show up.
I have structured my code in the main.js as such:
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App.vue'
Vue.config.productionTip = false
export const eventBus = new Vue();
Vue.use(VueRouter);
const AboutUs = {template: '<div>about_us</div>'};
const route = [{path:'/about_us', component: AboutUs}];
const router= new VueRouter({route});
new Vue({
render: h => h(App),
router
}).$mount('#app')
And then I have my app.vue designed as (note: I reduced much of the code to its essentials for brevity):
import AboutUs from './components/AboutUs.vue'
import { eventBus } from './main.js'
export default {
data(){
return {
films: []
}
},
components: {
"about-us": AboutUs
},
mounted(){
fetch('https://ghibliapi.herokuapp.com/films')
.then(res => res.json())
.then(films => this.films = films)
.catch(error=> console.log(error))
}
}
</script>
body {
background-color: deepskyblue;
}
<h1>Ghibli Fandom Extravaganza</h1>
<nav>
<li><router-link to="/about_us">About us </router-link></li>
<router-view></router-view>
</nav>
<p>List of Ghibli Movies: <films-list :films="films"/></p>
<film-detail />
At this point, my AboutUs component is only a very basic Vue that shows some information about the site in some simple HTML tags. But although the link is active and does work, the information from the Vue is not displayed, while the other Vue components continue to show, which indicates that maybe they are not connected? I have tried to follow the tutorial in the Vue Router site, but I don't think that I understand the mechanics of how the code actually works. Can anybody recommend me any corrections?
UPDATE:
Here is the code to my AboutUs.vue
<template>
<div>
<h1>This site is for examining the movies of Studio Ghibli</h1>
</div>
</template>
<script>
export default {
name: 'about-us'
}
</script>
<style scoped>
</style>
I think there is no need to import 'aboutus' component. You can just write like this <router-link to="about_us">About us </router-link>
and in the main.js declare the route like this
const route = [{path:'/about_us',name:'about_us', component: () => import("path to about us file")}];
The code samples you provided are a bit confusing, you should simply pass an imported view straight in to the component property of a router entry.
Where you have done:
const AboutUs = {template: '<div>about_us</div>'};
Replace that line with:
import AboutUs from './components/AboutUs.vue'
I can't figure out from your sample, when and what the relevance of components: {"about-us": AboutUs }, it is not needed.
Here is a sample of my setup:
router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'index',
component: () => import('../components/views/welcome')
},
{
path: '/about-us',
name: 'about-us',
component: () => import('../components/views/about-us')
}
]
const router = new VueRouter({
mode: 'history',
routes
})
export default router
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
App.vue
<template>
<v-app v-cloak>
<router-link :to="{ name: 'index' }">Welcome</router-link>
<router-link :to="{ name: 'about-us' }">About Us</router-link>
<router-view></router-view>
</v-app>
</template>
<script>
export default {
name: 'App'
}
</script>
components/views/about-us.vue
<template>
<div>This is the About Us page!</div>
</template>
<script>
export default {
name: 'about-us'
}
</script>
This sample uses History Mode
Other things to note
When routing, mounted is unreliable, instead you should place any fetch logic into it's own method when calling any :
methods: {
fetch () {
// https://github.com/axios/axios
axios.get('https://ghibliapi.herokuapp.com/films').then( ... )
}
}
Call this.fetch method in both beforeRouteUpdate and beforeRouteEnter instead of mounted, you can't even rely on created when it comes to views handled by vue-router.
Axios is suggested instead of native fetch because axios provides more functionality, features and browser compatibility.
In about-us.vue you add these Navigation Guards like so:
<template>
<div>This is the About Us page!</div>
</template>
<script>
export default {
name: 'about-us'
methods: {
fetch () {
axios.get('https://ghibliapi.herokuapp.com/films').then( ... )
}
}
// Will fire if you are already on the view but a parameter changes (dynamic routing)
beforeRouteUpdate(to, from, next) {
this.fetch()
next()
},
// Will fire when you enter the view
beforeRouteEnter(to, from, next) {
this.fetch()
next()
},
}
</script>
Both should be added, understand that they won't fire at the same time, only one of them will execute fetch once when relevant.
This will resolve any issues you would otherwise encounter with Dynamic Routing should you ever use them.
Folder Structure
src/
+ App.vue
+ main.js
+ router.js
+ vue.config.js
+ assets/
+ logo.png
+ components/
+ views/
+ welcome.vue
+ about-us.vue
Hope this clears up the setup requirement for you.

Struggling to transmit data to a child component

I am really new to VueJS, and I'm trying to build some kind of system where I have four pages available with Vue-Router. These pages are "ranked" from 1 to 4, and if the new page has a higher rank than the old one, the transition is set to "transition-left", else, "transition-right".
My problem here is that I can't manage to pass the result of the comparison to the child component. Here is my main.js file:
import Vue from "vue";
import VueRouter from "vue-router";
import Landing from "./components/Landing.vue";
import Bio from "./components/Bio.vue";
import Shop from "./components/Shop.vue";
import Contact from "./components/Contact.vue";
import App from "./components/App.vue";
import "./assets/style.css";
Vue.config.productionTip = false;
Vue.use(VueRouter);
let transitionName = "";
const router = new VueRouter({
mode: "history",
routes: [
{
path: "/",
component: Landing,
meta: { order: 1 }
},
{
path: "/biography",
component: Bio,
meta: { order: 2 }
},
{
path: "/shop",
component: Shop,
meta: { order: 3 }
},
{
path: "/contact",
component: Contact,
meta: { order: 4 }
}
]
});
router.beforeEach((to, from, next) => {
if (to.meta.order > from.meta.order) {
transitionName = "slide-left";
} else {
transitionName = "slide-right";
}
next();
});
let vm = new Vue({
router,
el: "#app",
data: {
transitionName: transitionName
},
render: h => h(App)
});
And here is how I tried to pass the "transitionName" value to "App.vue":
<template>
<div id="app">
<transition :name="name">
<router-view></router-view>
</transition>
</div>
</template>
<script>
export default {
props: ["transitionname"],
data: function() {
return { name: this.transitionname };
}
};
</script>
I'm thinking that maybe I did the new Vue part wrong, and that's not how you pass datas to a child component, but I can't find a working way to pass it correctly.
As a result, everything works, but there aren't any transition, so I guess the :name="name" equals nothing.
How can I fix this?
Thank you in advance
Here's how I might approach what you want to achieve. Basically all you want to do is watch the $route in your App component.
watch:{
$route(to, from){
if (to.meta.order > from.meta.order) {
this.name = "slide-left";
} else {
this.name = "slide-right";
}
}
}
Here is an example of that working (without the actual transitions).

Vue router button not clickable because setup is incorrect

I'm trying to setup Vue router for the first time and I'm running into trouble.
router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import Services from '../components/Services'
import App from '../app'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'App',
component: App
},
{
path: '/services',
name: 'Services',
component: Services
}
]
})
app.vue
<template>
<div id='app'>
<Navigation></Navigation>
<div class="Site-content">
<router-view></router-view>
</div>
<Footer></Footer>
</div>
</template>
<script>
import Services from "../javascript/components/Services";
import Footer from "../javascript/components/Footer";
import Navigation from "../javascript/components/Navigation";
export default {
components: {
Footer,
Navigation,
Services
},
data: function () {
return {
message: "Welcome to Ping Party From Vue!"
}
}
}
</script>
Navigation.vue
<template>
<div id="navigation">
<nav v-bind:class="active" v-on:click>
Home
Projects
<router-link to="/services">Services</router-link>
Contact
</nav>
</div>
</template>
<script>
import Services from './Services'
export default {
data () {
return { active: 'home' }
},
methods: {
makeActive: function(item) {
this.active = item;
}
}
}
</script>
That vue-router option is not working in my navigation. It shows up on the page but it's not clickable and I'm getting this error in the console.
ERROR
Unknown custom element: <router-link> - did you register the component
correctly? For recursive components, make sure to provide the "name"
option.
found in
---> <Navigation> at app/javascript/components/Navigation.vue
<App> at app/javascript/app.vue
<Root>
Unknown custom element: <router-view> - did you register the component
correctly? For recursive components, make sure to provide the "name"
option.
found in
---> <App> at app/javascript/app.vue
Make sure to register your router with your Vue instance.
So in your
import router from './router'
new Vue({
el: '#some-element'
router, // This line is important
render: h => h(App)
})

Categories

Resources