Vue router not recognizing child component of View - vue.js

The router does not load the components inside my view...
this is the structure:
the view: (test works, finMain does not)
<template>
<div>
<finMain></finMain>
<p>test</p>
</div>
</template>
<script>
export default {
name: 'FinView',
component: {
finMain: () => import("../components/finance/finMain"),
}
};
</script>
the router:
export default new Router({
routes: [
{
path: "/financial",
name: "financial",
component: () => import("#/views/finView")
}
],
});
if i put component: () => import("../components/finance/finMain") in my router it works... but not if I wrap the component inside the View..
This is the error i get:
Unknown custom element: <finMain> - did you register the component correctly?
For recursive components, make sure to provide the "name" option.
found in
---> <FinView>
<VApp>
<App> at src/App.vue
<Root>

I think that it's just misspelling, change component: { to components: {.

Related

this.$route.name is undefined inside the app.vue when console it inside created()

I am using vue3 and I am a newcomer to this. With the use of vue-router I created the routes. But I want to get the this.$route.name inside the app.vue. Therefore tried to get the value inside the created method. But at the beginning that value is undefined.
You get null because $route.name is not intialized yet in the created method.
You can instead use a computed variable, so this way $route.name will be initialized.
<template>
<div class="main-view">
<Navigation v-if="enableNavigation" />
<router-view />
<Footer />
</template>
export default {
name: 'App',
computed: {
enableNavigation() {
const disabledNavRoutes = ['login', 'register', 'resetPassword'];
return disabledNavRoutes.indexOf(this.$route.name) === -1;
}
}
}
In your case you want to display the Navigation component but only in some routes (the route when the user is not authenticated i assume). Here some alternatives:
Method 1: nested routes
router.js
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/login',
name: 'login',
component: LoginView,
},
{
path: '/home',
name: 'home-shell',
component: HomeShell,
children: [
{
path: 'home',
name: 'home',
component: HomeView
},
]
},
],
});
Remove the Navigation from App.js to remove it from login / register component
App.js
<template>
<div class="main-view">
<router-view></router-view>
</div>
</template>
Put the navigation and footer component in the HomeShell
HomeShell.js
<template>
<Navigation />
<--! Nested router. In our case HomeView !-->
<router-view />
<Footer />
</template>
And the HomeView component will be injected in the router-view of the HomeShell
Method 2: v-if
An other way would be to have a variable isAuthenticated in the store and conditionally show the Navigation component in the App component
App.js
<template>
<Navigation v-if="isAuthenticated" />
<router-view />
<Footer v-if="isAuthenticated" />
</template>
...
computed: {
isAuthenticated() {
return this.$store.getters.isAuthenticated
}
The limitation here is that if later you want to disable the navigation for routes where the user can authenticated (i.e. error 404 route). This won't work anymore.
I recommend you to check out this SO question for more info

How to pass state and events handlers as props to children components with Vue.js's Router?

Before using routing, I had the following Dashboard component:
<template>
<div>
<RegistrationForm v-on:add-employee="addEmployee" />
<EmployeeTable
v-bind:employees="employees"
v-on:delete-employee="deleteEmployee"
/>
</div>
</template>
<script>
...
export default {
components: {
EmployeeTable,
RegistrationForm
},
data() {
return {
employees: []
};
},
methods:{
deleteEmployee() {...}
addEmployee() {...}
}
}
</script>
I want to have to separate routes one for registering a new employee and one for listing all employees, so what I did first is updating the above template:
<template>
<div>
<router-view/>
</div>
</template>
Then I defined a router object:
export default new Router({
mode: 'history',
routes: [
{
path: "/dashboard",
name: "dashboard",
component: Dashboard,
children: [
{
path: 'add-employee',
component: RegistrationForm,
},
{
path: 'list-employees',
component: EmployeeTable,
}
]
}
]
});
My question is how to pass the employees state variable and deleteEmployee, addEmployee methods from the Dashboard component to its children components?
Update:
I do not know why I did not receive any response on this question, although this is a common and trivial task to do in other frameworks, for instance in React:
...
export default function BasicExample() {
const [x, setX] = useState("World");
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
</ul>
<Switch>
<Route exact path="/">
<Home x={x}/>
</Route>
</Switch>
</div>
</Router>
);
}
function Home({x}) {
return (
<div>
<h2>Hello {x}</h2>
</div>
);
}
After using Vue-router for a short period of time, I concluded that this is not a limitation, but more like a design decision:
React-router: is more like a condional renderer, e.i from within the parent component and based on the current path, render the apporopriate child.
Vue-router: is more like a wiring solution.
Also I have to say: a similar behavior to React-router can be achieved using Vue-router. This by combining the router's currentRoute property with the v-if directive, which truly insert/remove a component from the DOM (not hiding it using css as v-show do).
Finally: seprating routes configuration is advantegeous, as it yield more modular project and better SPA. Of-course this separation can be done in both Vue-router and React-router (look here for React-router).

Vue is there a way to pass data from route to component?

I am using Vue.js 2.0, and I have this exact same code in 2 differents files, so I decided to build only one component and redirect the 2 routes on it, then I just need to pass the ID to the route, this way my 2 components can display differents resultats.
Note: the only thing that changes is the ID dsgh151rhj12t1j5j I would like that each route can send it own ID to my PageContentfulView component
EDIT: I just want to pass data from Route to the component
<template>
<div>
<div class="container">
<hp-row>
<hp-column>
<component v-for="component in content.column" :data="component" :key="component.id" :is="getComponentIdentifier(component.is)"></component>
</hp-column>
</hp-row>
</div>
</div>
</template>
<script>
import ModularView from '#/views/ModularView'
export default {
name: 'PageContentfulView',
mixins: [ModularView],
created () {
this.fetch('blocks/dsgh151rhj12t1j5j')
},
}
</script>
Routes:
{
path: '/satisfaction-guarantee',
name: 'SatisfactionView',
component: load('PageContentfulView'),
},
{
path: '/about-us',
name: 'AboutUsView',
component: load('PageContentfulView'),
},
'props' can solve your problem.
<template>
<div>
<div class="container">
<hp-row>
<hp-column>
<component v-for="component in content.column" :data="component" :key="component.id" :is="getComponentIdentifier(component.is)"></component>
</hp-column>
</hp-row>
</div>
</div>
</template>
<script>
import ModularView from '#/views/ModularView'
export default {
name: 'PageContentfulView',
mixins: [ModularView],
props: ['id'],
created () {
this.fetch('blocks/' + this.id)
},
}
</script>
route
{
path: '/satisfaction-guarantee',
name: 'SatisfactionView',
component: load('PageContentfulView'),
props: { id: 'dsgh151rhj12t1j5j' },
},
{
path: '/about-us',
name: 'AboutUsView',
component: load('PageContentfulView'),
props: { id: 'blablablabla' },
},
You can do it using Dynamic Route Matching. You just need to include the parameter on the definition of the route, like below:
{
path: '/satisfaction-guarantee/:ID',
name: 'SatisfactionView',
component: load('PageContentfulView'),
}
Inside you component, to access the ID, you just need to use the this.$route.params.ID.
Passing props to route component allows an object mode.
Example from the documentation:
const router = new VueRouter({
routes: [
{ path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }
]
})
Route meta fields
Also you always can use the meta property to pass extra data (like a requireAuth flag)
const router = new VueRouter({
routes: [
{ path: '/test', component: TestComponent, meta: { someBoolean: false } }
]
})
And you can access it within your component
created() {
let meta = this.$route.meta;
}
Set the props in your route to true and place /:id at the end of your path
const router = new VueRouter({
routes: [
{ path: '/promotion/from-newsletter/:id',
component: Promotion,
props: true
}
]
})
You can now extract the param id of your route from the props in the corresponding component
<template>
<div>
<div class="container">
<hp-row>
<hp-column>
<component v-for="component in content.column" :data="component" :key="component.id" :is="getComponentIdentifier(component.is)"></component>
</hp-column>
</hp-row>
</div>
</div>
</template>
<script>
import ModularView from '#/views/ModularView'
export default {
name: 'PageContentfulView',
mixins: [ModularView],
props: ['id'],
created () {
this.fetch('blocks/'+id)
},
}
</script>

Issue rendering child views in Vue with Vue Router

I'm having trouble getting my child views to render in Vue.
My main.js file looks like this
import DashboardProducts from './components/Dashboard/DashboardProducts'
import DashboardSettings from './components/Dashboard/DashboardSettings'
Vue.use(VueRouter)
Vue.use(Vuex)
const routes = [
{ path: '/activate', component: Activate },
{ path: '/dashboard/:view', component: Dashboard,
children: [
{ path: 'products', component: DashboardProducts },
{ path: 'settings', component: DashboardSettings }
]
},
{ path: '/login', component: Login },
{ path: '/account', component: UserAccount }
];
const router = new VueRouter({
routes // short for routes: routes
});
export default router;
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
render: h => h(App)
});
As you can see I have imported the components and get no errors. I have also added them as children of Dashboard and set their paths.
In my Dashboard.vue view I do this
<template>
<div>
<dashboard-nav></dashboard-nav>
<!-- Will display product and settings components -->
<router-view></router-view>
</div>
</template>
<script>
import DashboardNav from '../components/Dashboard/DashboardNav'
export default {
name: 'Dashboard',
components: {
DashboardNav
}
};
</script>
<style>
</style>
Urls are matching but no components are rendering. What am I missing?
Here is a JSFiddle of pretty much what I'm going for https://jsfiddle.net/dtac5m11/
It seems to be working fine there but I'm also using single file components in my app so it may be a little different?
Again, the issue is getting the child components to render when their routes match. Currently no components are being mounted.
UPDATE:
I am getting the DashboardProducts component to render but can't get DashboardSettings to render.
Thanks!
{ path: '/dashboard/:view', component: Dashboard,
At first, for what purpose do you add :view after dashboard path? If you are using this one for children path as a parameter, it is an issue. It is the reason, why your children component are not rendering. Because, :view is for dynamic routes. /dashboard/:view is equivalent to /dashboard/* and it means that after /dashboard there can be any route and this route will render Dashboard component. And your children paths /dashboard/products and /dashboard/settings will always match /dashboard/:view and render parent component-Dashboard.
So, in your case, your routes for children components are known. So you do not need to use :view.
More, https://router.vuejs.org/en/essentials/dynamic-matching.html.

Failed to mount component: template or render function not defined

I'm trying to use vue-router to display routed components below my navbar component but I get an error specified in the title.
Here is my code:
main.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import app from './app';
Vue.use(VueRouter);
const foo = {
template: '<div>foo</div>',
};
const bar = {
template: '<div>bar</div>',
};
const routes = [
{
path: '/',
component: foo,
},
{
path: '/bar',
component: bar,
},
];
const router = new VueRouter({
mode: 'history',
routes,
});
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
render: h => h(app),
});
app.vue
<template>
<div id="app">
<fs-navbar/>
<main>
<router-view/>
</main>
</div>
</template>
<style scoped lang="scss">
</style>
<script>
import fsNavbar from './components/fs-navbar';
export default {
components: {
fsNavbar,
},
};
</script>
components/fs-navbar.vue
<template>
<nav>...</nav>
</template>
<style scoped lang="scss">
</style>
<script>
import Vue from 'vue';
export default Vue.component('fs-navbar', {
// logic
});
</script>
This app causes an error:
vue.js?3de6:2574[Vue warn]: Failed to mount component: template or render function not defined. (found in component <fs-navbar>)
If I add fs-navbar template directly into app.vue's template everything is working as intended. Without router app is working as well.
I'm using vue-cli with this template(vuejs2)
Smilar problem, when I write:
let routes = [{
path: '/',
component: require('./components/member.vue')
}]
it failed:[Vue warn]: Failed to mount component: template or render function not defined.
add ".default", it works!
let routes = [{
path: '/',
component: require('./components/member.vue').default
}]
PS:"vue": "^2.5.2","vue-router": "^3.0.1""vue-loader": "^13.3.0",
https://github.com/vuejs/vue-loader/releases/tag/v13.0.0
Turns out, that Vue.component() return value isn't working with the router.
When changed:
export default Vue.component('component-name', {})
to:
export default {}
Everything is working fine.