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
}]
Related
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:
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
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!
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.
In a SPA, I have made a header component which changes slightly on each page.
export default {
name: 'header',
//add some stuff based on user data
data: function (router) {
return {
//some data
}
},
}
And here are my routes:
export default [
{path:'/', component: showJokesAll },
{path:'/hot', component: showJokesHotAll },
{path:'/add', component: addJoke } ,
{path: '/login', component: webLogin},
{path: '/profile', component: webProfile},
{path: '/auth', component: webProfile},
]
I'm wondering what is the correct way to inject the header component into all routes?
Update: When I try to import the header component into app's main.js:
import Header from './components/header.vue'
Vue.component('page-header', Header);
I get this error:
Failed to mount component: template or render function not defined.
If you want to have the same header component in all routes. place it before router-view and change your css layout.
If you wan't to change the content of the header component depending on each route. You can place another <router-view name="header"> inside your header component. And then in your array of routes
<template>
<div>
<app-header><../>
<router-view><../>
</div>
</template>
Otherwise:
export default [
{
path:'/',
components: {
default: defaultComponentForThisRoute,
header: yourRouteHeaderComponent,
}
},
]