Vue Router Child showing - vue.js

I'm trying to make a router with Vue, it works very well, but there is a point in my mind.
Component Child is loaded with "click" at the start of vue, but,
In the Address Bar
When I type "http://127.0.0.1:8000/contact/new" it is displayed that the main component is not started. what is the reason for this?
app.vue
<template>
<router-link :to="{ name: 'home'}">Home</router-link>
<router-link :to="{ name: 'contact'}">Contact</router-link>
<div>
<router-view/>
</div>
</template>
contact.vue
<template>
<div>
Contact Page
<router-link :to="{ name: 'contactNew'}">New Add Contact</router-link>
<div>
<router-view/>
</div>
</div>
</template>
contactAdd.vue
<template>
<div>
Contact New Add
</div>
</template>
router
import Contact from "../Views/contact/Contact.vue";
import Home from "../Views/Home.vue";
import ContactNew from "../Views/contact/ContactNew.vue";
export default [
{
path: '/home',
component: Home,
name: 'home',
},
{
path: '/contact',
component: Contact,
name: 'contact',
children: [
{
path: 'new',
component: ContactNew,
name: 'contactNew',
},
]
},
{
path: '/:pathMatch(.*)*',
redirect: '/home',
}
];

Related

How can I change the view for one part of the page in VueJs 3

I have three main sections inside my page, and I want to switch the view for one section only:
<template>
<div id="main">
<div id="scene">
<scene/>
</div>
<div id="plan">
<Plan/>
</div>
<div id="titleControl">
<router-link to="/controls"> Controls </router-link>
<router-link to="/logs"> Logs </router-link>
</div>
<div id="controlPannel">
<div id="controls">
<Controls/>
</div>
<router-view/>
</div>
</div>
</template>
router
import { createWebHistory, createRouter } from "vue-router";
import MainInterface from '../views/MainInterface.vue'
import Logs from '../views/Logs.vue'
import Scene from '../views/Scene.vue'
import Plan from '../views/Plan.vue'
import Controls from '../views/Controls.vue'
import PageNotFound from '../views/PageNotFound.vue'
const routes = [
{
path: '/',
name: 'main',
component: MainInterface
},
{
path: '/scene',
name: 'scene',
component: Scene
},
{
path: '/plan',
name: 'plan',
component: Plan
},
{
path: '/logs',
name: 'logs',
component: Logs
},
{
path: '/controls',
name: 'controls',
component: Controls
},
{
path: '/:catchAll(.*)*',
name: "PageNotFound",
component: PageNotFound,
},
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
I want to parse the controls as a default, and I want the user to navigate between the Logs and the Controls only, but when I click on any of the routing links it takes me to another page completely!
Can you please tell me how can I solve that? thanks in advance.
Instead of having all routes at one level, you can use Nested Routes
Change your App.vue to
<template>
<div id="main">
<div id="scene">
<ScenePage />
</div>
<div id="plan">
<PlanPage />
</div>
<div id="titleControl">
<router-link to="/controls"> Controls </router-link>
<router-link to="/logs"> Logs </router-link>
</div>
<router-view />
</div>
</template>
<script>
import PlanPage from "./Views/Plan.vue";
import ScenePage from "./Views/Scene.vue";
export default {
name: "App",
components: {
PlanPage,
ScenePage,
},
};
</script>
Add another file in view to handle nested routing such as Sub.vue with the following content
<template>
<router-view />
</template>
<script>
export default {
name: "SubPageForRouting",
};
</script>
and finally, update your router.js file as
import { createWebHistory, createRouter } from "vue-router";
import SubPageForRouting from "../Views/Sub.vue";
import LogPage from "../Views/Log.vue";
import ControlPage from "../Views/Controls.vue";
const routes = [
{
path: "/",
component: SubPageForRouting,
children: [
{
path: "",
alias: "controls",
component: ControlPage
},
{
path: "logs",
component: LogPage
}
]
}
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;
You can find a working code sandbox Here

VUE JS: How to keep same structure in whole project but different header and footer for each page

I am using router-view. In App.vue I want this structure so in every other pages I can have different header, footer but overall structure:
<router-view>
<template>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
</router-view>
In home page component I want to do something like this:
<slot name="header">header content</slot>
<slot name="footer">footer content</slot>
Othercontent here....
In about us page component I want to do something like this:
<slot name="header">about header content</slot>
<slot name="footer">about footer content</slot>
Othercontent here....
how can I achive this?
The solution goes around layouts and sub-pages where layouts are parents and related pages placed as children.
Consider these two layouts:
// src/layouts/PublicLayout.vue
<template>
<section class="public-layout">
<router-view/>
</section>
</template>
<script>
export default {
name: 'PublicLayout',
};
</script>
and
// src/layouts/MainLayout.vue
<template>
<section class="main-layout">
<!-- header -->
<router-view/>
<!-- footer -->
</section>
</template>
<script>
export default {
name: 'MainLayout',
};
</script>
Now, you can tune routes in your flavor:
// src/router/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
const publicRoutes = [
{
path: '/public',
component: () => import('layouts/PublicLayout.vue'),
children: [
{
path: 'login',
name: 'Login',
component: () => import('pages/ULogin.vue'),
},
{
path: 'sign-up',
name: 'SignUp',
component: () => import('pages/USignUp.vue'),
},
],
},
];
const mainRoutes = [
{
path: '/',
component: () => import('layouts/MainLayout.vue'),
children: [
{
path: '',
name: 'Home',
component: () => import('pages/UHome.vue'),
},
{
path: 'profile',
name: 'Profile',
component: () => import('pages/Profile.vue'),
},
],
},
];
const Router = new VueRouter({
routes: mainRoutes.concat(publicRoutes),
});
// snippet skipped
Here, MainLayout and PublicLayout play the structural role while other pages are placed as their children. By navigating to each page (e.g. from /login to /profile) the proper layout will get loaded as well.
<your-base-layout>
<slot #header>about header content</slot>
<slot #footer>about footer content</slot>
</your-base-layout>
its called "Named Slot"

How to pass Dynamic Props through Routes in Vue 3?

I can send static props via <router-link> like so:
parent-component:
<router-link :to="{name: 'child-component'}"></router-link>
child-component:
<template>
<h1>{{ test }}</h1>
</template>
<script setup>
import {defineProps} from "vue";
const props = defineProps({
test: String
})
</script>
router.js:
const router = createRouter({
routes: [
{path: "/child-component", name: "child-component", component: ChildComponent, props: {test: 'hello world'}},
]
});
This correctly displays hello world in the h1 element in child-component. But how do I pass a dynamic element, say a state or prop (parent) through the route?
I've tried:
<router-link :to="{name: 'child-component'}" :props="{test: 'did this come through?'}"></router-link>
or
<router-link :to="{name: 'child-component'}" :test="'did this come through?'"></router-link>
But I don't know what to put instead of hello world:
const router = createRouter({
routes: [
{path: "/child-component", name: "child-component", component: ChildComponent, props: {test: 'hello world'}},
]
});
Here it is,
Router link
<router-link
:to="{
name: 'child-component',
params: { id: id, name: name },
}" >test
</router-link>
// Id and name are dynamic value
route.js file
const router = createRouter({
routes: [
{path: "/child-component/:id/:name", name: "child-component", component: ChildComponent},
]
})
You can access the params at the child component
<span>Name: {{ $route.params.name }} Id: {{ $route.params.id }}
</span>

Navigation tabs reload page

I am playing with fundamentals and when I click on a routing link in the navigation it reloads the page and doesn't load the page content but renders the correct URL. I uploaded the project to git.
Here is the entry point src -> App.vue
<template>
<navigation></navigation>
</template>
<script lang="ts">
import Navigation from "#/views/navigation/Navigation.vue";
export default({
name: 'App',
components: {
Navigation
}
});
</script>
Product structure
In navigation I have:
<b-navbar-nav>
<b-nav-item href="#">Home</b-nav-item>
<b-nav-item href="/about">About</b-nav-item>
<b-nav-item href="/contact">Contact</b-nav-item>
</b-navbar-nav>
and in the router.ts file
import Vue from 'vue'
import Router from 'vue-router'
import Contact from '#/views/contact/Contact.vue'
import About from '#/views/about/About.vue'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/about',
name: 'about',
component: About
},
{
path: '/contact',
name: 'contact',
component: Contact
},
]
})
I have read the doc's and it looks like I am doing correctly but I am wrong somewhere.
github link https://github.com/drewjocham/firstVue
What I am trying to do it make App.vue the parent and the views children. If this is not a good project structure please correct me. I am more of a backend guy (java-spring) and trying learn more frontend technologies.
-----update 1----
<b-navbar-nav>
<b-nav-item :to="{name: 'about'}">About</b-nav-item>
<b-nav-item :to="{contact: 'contact'}">Contact</b-nav-item>
</b-navbar-nav>
First of all, you have to understand that a single page website (No Reloads) made in VueJs will only work if your URLs are managed through Vue-Router Library. The routes you have made are correct but there is no place for the component to load. So, in your App.js i.e where you want all your components to load you write this-
<template>
<div id="app">
<Navigation></Navigation>
<router-view/>
</div>
</template>
Focus on the router-view, it is a vue component used by the Vue-Router to load your components.
Then considering you already have names for your routes, just use the :to bind instead of the href in your navigation navs.
That means,
<b-navbar-nav>
<b-nav-item :to="{name: 'home'}">Home</b-nav-item>
<b-nav-item :to="{name: 'about'}">About</b-nav-item>
<b-nav-item :to="{name: 'contact'}">Contact</b-nav-item>
</b-navbar-nav>
for all your nav items.
Your routes need to be-
export default new Router({
name: 'Navigation',
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
component: About
},
{
path: '/contact',
name: 'contact',
component: Contact
},
]
})
Make sure your component imports co-relate with your components-
<template>
<Navigation></Navigation>
</template>
<script lang="ts">
import Navigation from "#/views/navigation/Navigation.vue";
export default({
name: 'App',
components: {
Navigation
}
});
</script>
Focus on the 'Navigation' rather than the 'navigation'

VueJS - passing data from a v-for to a component, and then to another component

I have a <header-row> component which I put at the top of all pages to show a title and a subtitle. This is what I'm wanting to do:
Show a list of objects from an array, with each item "clickable" to show that item's detail on a separate page (this part is easy)
Pass a field of the item (like item.display) from the list to the next page as a prop
In the new page, use that prop in my <header-row> component to show the title for that page.
Seems simple, but I can't get the last two steps working:
Header Component:
<template>
<div>
<h3 class='text-primary'>{{ title }}</h3>
<h5 class='text-muted'>{{ subTitle }}</h5>
</div>
</template>
<script>
export default {
props: [
'title',
'subTitle'
]
}
</script>
List items:
<router-link v-for="item in items" :to="{ name: 'some-page' } myProp="item.name">
{{ item.display }}
</router-link>
Child Component
<template>
<div>
<header-row title="myProp"></header-row>
<div class='container-fluid'>
<div class='row'>
<div class='col-4'>
... stuff here....
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'child-stuff',
props: [
'myProp'
]
}
</script>
Routing Code:
import Vue from 'vue'
import Router from 'vue-router'
import Dashboard from '#/views/Dashboard'
... more here ....
import AROverview from '#/views/ar/Overview'
import Invoice from '#/views/ar/Invoice'
import APOverview from '#/views/ap/Overview'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'dashboard',
component: Dashboard
},
{
path: '/receivables/:id',
name: 'ar',
component: AROverview
},
{
path: '/invoice/:id',
name: 'invoice',
component: Invoice
},
... more ...
{
path: '/payables/:id',
name: 'ap',
component: APOverview
}
]
})