Navigation tabs reload page - vue.js

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'

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 Router Child showing

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',
}
];

Vue3 Router duplicated component

I'm creating an app using Vue3js and vue-router.
When the app is created, I get my first component duplicated.
My App.vue component is this:
<template>
<div class="container-fluid">
<nav class="navbar navbar-expand-md fixed-top">
<div class="menu-izq">
<router-link id="logo" class="menu-item" to="/">COVELESS</router-link>
<router-link class="menu-item" v-if="!this.userLogged" to="/login">Login</router-link>
<router-link class="menu-item" v-if="this.userLogged" to="/canvas">Canvas</router-link>
<router-link class="menu-item" v-if="this.userLogged" to="/dashboard">Dashboard</router-link>
</div>
<div class="menu-dcha">
<router-link class="menu-item" v-if="this.userLogged" v-on:click="vaciarStorage()" to="/login">Logout
</router-link>
</div>
</nav>
<router-view></router-view>
</div>
My router.js file is this
import { createRouter, createWebHistory } from
'vue-router'
import LoginMenu from './components/LoginMenu.vue'
import AllElement from './components/AllElement.vue'
import Dashboard from './components/Dashboard.vue'
import App from './App.vue'
const routes = [
{
path: '/',
name: 'Home',
component: App
},
{
path: '/login',
name: 'Login',
component: LoginMenu
},
{
path: '/canvas',
name: 'Canvas',
component: AllElement
},
{
path: '/dashboard',
name: 'Dashboard',
component: Dashboard
}
]
const history = createWebHistory();
const router = createRouter({
history,
routes,
});
export default router
And my app.js file is this
import './bootstrap';
import { createApp } from 'vue/dist/vue.esm-bundler'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app');
So when the App component is mounted on #app, the navbar gets duplicated because it is mounting another App component at "/" path (I guess because it is defined at router.js like that). But if I remove the
{
path: '/',
name: 'Home',
component: App
}
route, then I'm never navigating to the index.
Here you can see both the App components.

How to proper use vue-router?

I want to exclude the h1 tag every time I go to different route in my Vue application.
Here's my app.vue:
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<h1>LANDING PAGE</h1>
<router-view></router-view>
<!--Path for login.vue-->
<button #click="$router.push('/login')">LOGIN</button>
</div>
</template>
<script>
export default {
name: 'app',
}
</script>
And here's my login page, where I want only to display my design for login page only:
<template>
<div>
<h1>Login Page</h1>
</div>
</template>
<script>
export default {
name: "Login"
}
</script>
My route.js:
import Login from './components/LandingPage/Login';
import Register from './components/LandingPage/Register';
export default [
{
path: '/login', component: Login
},
{
path: '/register', component: Register
}
]
and lastly my main.js:
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import Routes from './routes';
import VueResource from 'vue-resource'
Vue.config.productionTip = false;
Vue.use(VueRouter);
Vue.use(VueResource);
const router = new VueRouter({
routes: Routes,
/* To remove # in the URL */
mode: 'history'
});
new Vue({
render: h => h(App),
router: router
}).$mount('#app');
I didn't include the register.vue because it's just the same with login.vue.
Conditional rendering based on the landing page url:
<h1 v-if="$route.path === '/landing-page-url'">LANDING PAGE</h1>
Actually, there are three approaches to solve your problem:
Just drop your <h1></h1> into your landing page component.
You can use conditional rendering, like Psidom answered (just changed path to name):
<h1 v-if="$route.name === 'Landing'">Landing page</h1>
You can have only one <h1></h1> in your main layout, and render current page title dynamically. Route Meta Fields come in rescue.
import Login from './components/LandingPage/Login'
import Register from './components/LandingPage/Register'
export default [
{
path: '/login',
component: Login,
meta: {
title: 'Login',
},
},
{
path: '/register',
component: Register,
meta: {
title: 'Register',
},
},
]
And then in your template:
<h1>{{ $route.meta.title }}</h1>
P.S. To navigate to another route in your template use <router-link></router-link> instead of button with click event.

placing a router-view in template as a sub template this isn't working

When I place a route view in a template my vue router doesn't load the content, how can I load this?
In my homepage I've got
<router-view name="homepage"></router-view>
The code gets loaded perfectly from my vue router but the contained in the homepage template doesn't get loaded.
...
routes:
[
{
path: '/',
name: 'homepage',
components: {
homepage: HomepageTemplate,
subPart: subPartTemplate
}
}
]
...
homepageTemplate:
<template>
<div>
<router-view name="subPartTemplate"/>
</div>
</template>
You named the component subPart but are referencing to it as subPartTemplate;
<template>
<div>
<router-view name="subPart"/>
</div>
</template>
Edit: I see you edited your post; what's going wrong is you are using a child <router-view> without defining children in your routes;
You should define children in your path:
{
path: '/',
name: 'homepage',
component: HomepageTemplate,
children: [
{ path: '/', component: subPartTemplate }
]
}
Now the <router-view> in the homepageTemplate should be the subPartTemplate. No need to use named components for this. Named components are useful when you need multiple <router-view>'s in one template.
Checkout the documentation for more details.