Assign refs to child components using VueRouter - Vue - javascript

I have the following code in my main.js file in my Vue webapp:
const routes = {
name: "Main",
path: "/main",
redirect: "/main/home",
component: MainComponent,
children: [
{ path: "home", name: "Main_Home", component: MainHomeComponent },
{ path: "play", name: "Main_Play", component: PlayComponent },
]
}
Vue.config.productionTip = false;
const router = new VueRouter({
mode: 'history',
routes
});
Currently, the routing and component rendering is working really well, however from my MainComponent, I want to trigger a method within a child component. I understand that I can do that with refs in Vue, however I'm not sure how I can create them with VueRouter, as the components are being loaded by VueRouter. Here is my MainComponent.js:
<template>
<div id="main">
<h1>Main Component</h1>
<router-view></router-view>
</div>
</template>

A template ref on the router-view will automatically apply to the view's rendered component. With that template ref, you could access the child's method directly:
<template>
<div id="main">
<h1>Main Component</h1>
<button #click="callChildMethod">Call child method</button>
<router-view ref="view"></router-view>
</div>
</template>
<script>
export default {
methods: {
callChildMethod() {
this.$refs.view.myMethod()
}
}
}
</script>
demo

Related

Quasar Router routes not found

I'm using for the first time quasar router, I already know how to use Vue router and this one should be almost the same, and it quite is but the problem is it doesn't work, I have created a Login Page and tried to insert the route in routes.ts file but now i can't access the main page neither the login one, and when I look in the console I get this error: "Failed to fetch dynamically imported module: http://localhost:9000/src/layouts/MainLayout.vue".
Here's the code:
Routes.ts
import { RouteRecordRaw } from 'vue-router';
const routes: RouteRecordRaw[] = [
{
// Main Page
path: '/',
component: () => import('layouts/MainLayout.vue'),
children: [
{ path: '', component: () => import('pages/QuestionsPage.vue') },
],
},
{
path: '/login',
component: () => import('pages/LoginPage.vue'),
},
{
path: '/:catchAll(.*)*',
component: () => import('pages/ErrorNotFound.vue'),
},
];
export default routes;
In case you need the login page and the main one:
<script setup lang="ts"></script>
<template>
<q-page padding>
<h1>Login</h1>
</q-page>
</template>
<script setup>
console.log('test');
</script>
<template>
<q-page padding>
<h1>Main Page</h1>
</q-page>
</template>
File structure:

Why is my Vue navbar changing the route but not updating the router-view?

I'm using Vue to make a single-page application and I have a navbar and have set up Vue-Router. For some reason, every time after the first time I use the navbar, the route changes but the router-view does not. Here's the code from NavBar.vue:
<template>
<div id="app">
<v-toolbar id="navbar" app color="#330066" dark>
<v-toolbar-side-icon></v-toolbar-side-icon>
<v-toolbar-title id="appname">{{ appname }}</v-toolbar-title>
<v-spacer></v-spacer>
<span :key="item.link" v-for="item in items" class="nav-elt">
<router-link active-class="nav-elt-active" tag="span" :to="item.link">
{{ item.title }}
</router-link>
</span>
</v-toolbar>
</div>
</template>
<script>
export default {
name: "NavBar",
props: {
appname: String,
},
data() {
return {
items: [
{ title: "Home", link: "/" },
{ title: "Search", link: "/search" },
],
};
},
};
</script>
And here's from App.vue:
<template>
<v-app>
<v-main>
<NavBar appname="Newsfacts" />
<router-view />
</v-main>
</v-app>
</template>
<script>
import NavBar from "./components/NavBar";
export default {
name: "App",
components: {
NavBar,
},
data() {
return {};
},
};
</script>
Here's from router/index.js:
import Vue from 'vue';
import Router from 'vue-router';
import Home from '../views/Home.vue';
import Search from '../views/Search.vue';
Vue.use(Router);
export default new Router({
mode: "history",
routes: [
{
path: "/",
name: "Home",
component: Home
},
{
path: "/search",
name: "Search",
component: Search
}
]
});
If you need anything else, the full code is on my github, and a demo is at a netlify site
The link attribute inside the array of items should contain a '/' at the beginning of every route.
So, it should look like this:
data() {
return {
items: [
{ title: "Home", link: "/home" },
{ title: "Search", link: "/search" },
],
};
},
Also, it is probable that the component is not being rendered because you are using <v-btn/> for routing, instead of <router-link/>.
I recommend you use <router-link/> instead of <v-btn/> for navigation in order to support all the features provided by Vue Router like history mode, base, etc.
In case you necessarily need the v-btn, I think you can wrap the <router-link/> inside the button or viceversa.
For more information about Vue Router and <router-link/>, check out this link:
https://router.vuejs.org/api/#router-link
where is your vue router component definitions?
e.g
const FooHome= { template: '<div>Home</div>' }
const Search= { template: '<div>Search</div>' }
const routes = [
{ path: '/', component: Home},
{ path: '/search', component: Search}
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
Turns out I was returning an empty dictionary in a few data() functions, and that caused the app to break. Thanks to #inked6233 on the Vue Land discord for helping me find that!

Can't navigate through my different router-link using VueRouter

I'm working for the first time with a project created using vue-cli. I'm using VueRouter to navigate between multiple views. The problem is that if I visit de route '/workshops', '/categories' or '/machines', it's always the 'Workshops' component that show up...
Here's my router declaration:
import Vue from 'vue'
import VueRouter, { RouteConfig } from 'vue-router'
import Home from '../views/Home.vue'
import Categories from '../views/Categories.vue';
import Machines from '../views/Machines.vue';
import Workshops from '../views/Workshops.vue';
Vue.use(VueRouter)
const routes: Array<RouteConfig> = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/categories',
name: 'Categories',
component: Categories
},
{
path: '/machines',
name: 'Machines',
component: Machines
},
{
path: '/workshops',
name: 'Workshops',
component: Workshops
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
Which is pretty similar to what is declared by default
And here is the declaration of the Workshop component (but Machines and Categories uses the exact same structure)
<template>
<div class="workshops">
<h1>Workshops</h1>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
export default class Workshops extends Vue {
}
</script>
And Categories.vue as an example:
<template>
<div class="categories">
<h1>Catégories</h1>
</div>
</template>
<script lang="ts">
import { Vue } from 'vue-property-decorator';
export default class Categories extends Vue {}
</script>
The main App.vue is declared as following:
<template>
<div id="app">
<header>
<nav>
<h2 class="brand-name">Flexshop</h2>
<hr>
<ul>
<li><router-link to="/workshops">Ateliers</router-link></li>
<li><router-link to="/categories">Catégories</router-link></li>
<li><router-link to="/machines">Machines</router-link></li>
</ul>
<div class="bottom">
<ul>
<router-link to="/settings">Options</router-link>
<router-link to="/credits">Crédits</router-link>
</ul>
</div>
</nav>
</header>
<main>
<transition name="fade">
<router-view></router-view>
</transition>
</main>
</div>
</template>
If I only use one of the three routes in the router declarations, the correct component shows up, it seems like the declaration the latest components overwrite the two others...
Thanks for your help !
You should use component decorator, like this
<template>
<div class="workshops">
<h1>Workshops</h1>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
#Component
export default class Workshops extends Vue {
}
</script>

Vue.js - How to add multiple layout in vuejs?

I'm creating a vuejs app, in which I want to have two different layouts like one for user interface and other for the admin interface.
In the user interface, I have a button named "Admin Panel" on click to this button want to go the admin side and render the new layout. So far I have done this as follows:
I have created a container folder in my src to keep the layout files
UserPanel.vue
AdminPanel.vue
And also a router folder to keep the route files
user.js
admin.js
index.js
###UserPanel.js###
<template>
<v-app>
<h4>User Layout</h4>
<router-view></router-view>
</v-app>
</template>
<script>
export default {
}
</script>
###AdminPanel.js###
<template>
<v-app>
<h4>Admin Layout</h4>
<router-view></router-view>
</v-app>
</template>
<script>
export default {
}
</script>
###user.js###
import UserPanel from 'Container/UserPanel';
const HomeV1 = () => import('Views/HomeV1');
const HomeV2 = () => import('Views/HomeV2');
const HomeV3 = () => import('Views/HomeV3');
export default{
path: '/',
component: UserPanel,
redirect:'/home',
children:[
{
path: '/',
component: HomeV1 ,
meta: {
header: 1
}
},
{
path: '/home',
component: HomeV1 ,
meta: {
header: 1
}
},
{
path: '/home-two',
component: HomeV2 ,
meta: {
header: 2
}
},
{
path: '/home-three',
component: HomeV3 ,
meta: {
header: 3
}
}
]
}
###admin.js###
import Admin from 'Container/Adminpanel.vue';
const Reports = () => import('Views/AdminPanel/Reports.vue');
const Invoice = () => import('Views/AdminPanel/Invoices.vue');
const AdminAccount = () => import('Views/AdminPanel/Account.vue');
export default {
path: '/admin-panel',
component: Admin,
redirect:'/admin-panel/reports',
children:[
{
path: '/admin-panel/reports',
component: Reports,
name:'Reports'
},
{
path: '/admin-panel/invoices',
component: Invoice,
name:'Invoice'
},
{
path: '/admin-panel/products',
component: AdminProducts,
name:'AdminProducts'
}
]
}
###index.js###
import Vue from 'vue'
import Router from 'vue-router'
import userRoutes from './user';
import adminRoutes from './admin';
Vue.use(Router);
export default new Router({
mode: 'history',
routes: [
userRoutes,
adminRoutes
]
})
Now only my user routing is working. To show the pages of admin I have to put its route in user.js and after that, it renders the user's layout not admin's layout.
Thank You.
Put attribute meta in the route like this:
const routes = [
{
path: '/admin',
name: 'admin',
meta: { layout: 'LayoutAdmin' },
component: Dashboard,
},
and in App.vue you can render depends of this condition this.$route.meta.layout here an example:
<template>
<div id="app">
<notifications width="400px" />
<LayoutAdmin v-if="this.$route.meta.layout">
<router-view class="content" />
</LayoutAdmin>
<LayoutDefault v-else :links="links" :headerButtons="headerButtons">
<router-view class="content" />
</LayoutDefault>
</div>
</template>
I have played around with this before and the way I did it was to have alternative layouts that switch depending on a route meta field...
So when you define a route, you can add a meta field:
path: '/admin-panel/reports',
component: Reports,
name:'Reports',
meta: { template: 'admin' }
Then you need to check routes as they change. The easiest way to do this is in a global navigation guard (like the example has on their page). If it detects it's an admin page, it changes a Vuex property which will then switch which template you're using.
I will say that in the end I stopped using this method and wrapped all of my pages with wrapper components (admin/user/etc) so I could control everything from Vue itself. This was mainly due to Vue Router's limitations around waiting for a user to be authenticated though so that may not be an issue for you.

Can't render child component with VueRouter

I'm learning VueJS, created a new Vue app with the vue-cli, and changed it a little bit. This is what I have in my router.js:
import Vue from 'vue'
import Router from 'vue-router'
import Hello from '#/components/Hello'
import Panel from '#/components/Panel'
import Search from '#/components/Search'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Hello',
component: Hello
},
{
path: '/panel',
name: 'Panel',
component: Panel,
children: {
path: 'search',
component: Search
}
}
]
})
My Panel.vue renders properly without a 'children' key in the router object. This is the content:
<template>
<div class="panel">
<h1>Panel</h1>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'panel',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
And Search.vue is very similar
<template>
<div class="search">
<h1>Search</h1>
<p>Lorem ipsum ...</p>
</div>
</template>
<script>
export default {
name: 'search',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
With this configuration, as explained here: https://router.vuejs.org/en/essentials/nested-routes.html
I get this error:
vue-router.common.js?37ec:598Uncaught TypeError: route.children.some is not a function
And a blank page is displayed.
I want, for example, localhost:port/#/panel to display the Panel component only (this is not so important).
And localhost:port/#/panel/search to display the Search component, that is wrapped by Panel component (this is the important part, because nobody would actually go to just /panel).
Could anybody give some help?
It's because children should be array of objects, and some is method that lives on array, so that's why you are getting error.
children: [{
path: 'search',
component: Search
}]

Categories

Resources