The page loads twice in vue - javascript

I'm having trouble writing vue. I am using vue and vuetify.
There are A andB pages. There is no problem with entering the A orB page only once.
However, when the page is entered as below, the created function of A is called twice.
A -> B -> A
menuselector.vue
<template>
<v-list>
<template v-for='(eachmenu) in menu'>
<v-list-item
:to='eachmenu.path'
>
<v-list-item-title>
{{eachmenu.title}}
</v-list-item-title>
</v-list-item>
</template>
</v-list>
</template>
<script>
export default {
name: 'selector',
data() {
return {
menu: [
{
title: 'A',
path: '/A',
}
{
title: 'B',
path: '/B',
}
]
}
}
}
</script>
router.vue
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
redirect: '/A',
component: TestComponent,
children: [
{
path: 'A',
component: () => import('#/component/A.vue'),
name: 'Acomponent',
},
{
path: 'B',
component: () => import('#/component/B.vue'),
name: 'Bcomponent',
}
]
}
]
})
A.vue&B.vue
<template>
test
</template>
<script>
export default {
beforeCreate() {
console.log('beforeCreate');
}
created() {
console.log('created');
}
}
</script>
Console output is below.
what was problem???

I don't think "loading" is correct word here. Code needed for component is loaded from server only once as you can check in Dev Tools Network tab
When switching routes, component for old route is destroyed and component for new route is created. Its default behavior of Vue dynamic component (it is what <router-view> uses for switching components). You can change that by using <keep-alive>. Be sure to check documentation and understand implications - your app will use more memory
<keep-alive>
<router-view :key="$route.fullPath"></router-view>
</keep-alive>

Related

Why does every component in my page appears twice?

I have created a sort of First page for my project, but I don't know why it renders everything twice on my page:
here is my First.vue component that is used by the router as the first page:
<template>
<h1>Bienvenue</h1>
<router-view></router-view>
<div class="routing" v-if="this.$route.path == '/'">
<router-link to='/app'>Go to application</router-link>
<br>
<router-link to='/test'>Go to test</router-link>
</div>
</template>
and here is what I get on the page when I npm run serve
Does anyone knows where it comes from?
UPDATE
When I delete the router-view element, the components appear once but when I click on one of the links, it changes the URL of the page but the page in itself is not showing the component.
And when I try to put everything in my router-view, like this:
<template>
<router-view>
<div class="routing" v-if="this.$route.path == '/'">
<h1>Bienvenue</h1>
<router-link to='/app'>Go to application</router-link>
<br>
<router-link to='/test'>Go to test</router-link>
</div>
</router-view>
</template>
it appears once, but like the other case, when I click on a link, it is just changing the URL and not the page.
Here is my index.js to show you how my routes are defined:
import {createRouter, createWebHistory} from 'vue-router'
import App from '../App.vue'
import Test from '../Views/Test.vue'
import First from '../Views/First.vue'
export const router = createRouter({
history: createWebHistory(),
routes: [
{
path:'/',
name: 'First',
component: First,
},
{
path:'/test',
name: 'Test',
component: Test
},
{
path:'/app',
name: 'App',
component: App
}
]
})
Just to clarify what results I expect from my app:
When I run the project, I want to launch on a page with just a header saying 'Hello' at the top of the page and two links where I can either click on 'Go to the application' or 'Go to test'.
Then, when I click on one of the links, I want to see the content of the component (so either test or the app), but I don't want to see the header and the links anymore.
I am not sure but try this:
{
path: "/app",
component: () => import("../App.vue"),
name: "App"
},
{
path: "/test",
component: () => import("../Views/Test.vue"),
name: "Test"
},
{
path: "/",
component: () => import("../Views/First.vue"),
name: "First"
}
Update with sample code or you can refer to live code here.
// App.vue
const First = {
template: `<div class = "container" id="app">
<h1>Hi from First</h1>
<hr>
<router-link to="/foo">Foo</router-link>
<router-link to="/bar">Bar</router-link>
</div>
`
}
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const routes = [
{
path:'/',
name: 'First',
component: First,
default: First
},
{
path:'/foo',
name: 'Foo',
component: Foo
},
{
path:'/bar',
name: 'Bar',
component: Bar
}
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
// main.js
<div id="app">
<!-- route outlet -->
<!-- component matched by the route will render here -->
<router-view></router-view>
</div>

True or False to show route-item in navbar

im building a website and using vvue with vue-router.
My Navbar component iterates through the routes element and gets all routes to show in the navbar, so i can simply add and remove routes without changing the navbar component.
Now i want for example the Data protection notice or the legal notice not to show up.
I tried to solve this with a boolean and a v-if. Do you have any idea how to solve this problem?
My code looks as following:
Navbar component:
<template>
<div>
<div class="mdheader"></div>
<div class="md-layout-item">
<md-tabs md-sync-route class="md-primary" md-alignment="centered">
<div
v-for="r in this.$router.options.routes"
:key="r.name"
:v-if="r.showOnBar"
>
<md-tab :md-label="r.name" :to="r.path" exact></md-tab>
</div>
</md-tabs>
</div>
</div>
</template>
<script>
export default {
name: "navbar"
};
</script>
router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "#/views/Home.vue";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "Home",
component: Home,
showOnBar: true
},
{
path: "/about",
name: "About",
showOnBar: true,
component: () => import("#/views/About.vue")
},
{
path: "/aktuelles",
name: "Aktuelles",
showOnBar: true,
component: () => import("#/views/Aktuelles.vue")
},
{
path: "/datenschutz",
name: "Datenschutz",
showOnBar: false,
component: () => import("#/views/Datenschutz.vue")
}
];
const router = new VueRouter({
routes
});
export default router;
Thanks in advance
Youa re very close, but you need to wrap your custom property in meta option:
const routes = [
{
path: "/",
name: "Home",
component: Home,
meta: { showOnBar: true }
},
{
path: "/about",
name: "About",
meta: { showOnBar: true }
component: () => import("#/views/About.vue")
},
{
path: "/aktuelles",
name: "Aktuelles",
meta: { showOnBar: true },
component: () => import("#/views/Aktuelles.vue")
},
{
path: "/datenschutz",
name: "Datenschutz",
meta: { showOnBar: false }
component: () => import("#/views/Datenschutz.vue")
}
];
and access it via route.meta.showOnBar. Keep in mind that you only need to define it for routes you want to show on your navbar.
You need to wrap your custom route properties into meta as stated in BroiSatse's answer.
However, another issue is that you used :v-if (i.e. you bound the v-if attribute) instead of just using v-if. v-if already evaluates the condition in the value as per the docs.
Here's a sandbox to play around with: https://codesandbox.io/s/stack-overflow-q-62409392-6zovw?file=/src/router/index.js

How to pass data to vue router router-view?

Im using Vue Router. In my code I used to have:
<div v-bind:is="page.component_name" v-bind:page="page"></div>
Which worked, and the page data was passed to the component. But how do I do the same with a router-view? This doesn't seem to work:
<router-view v-bind:page="page"></router-view>
js:
var vm = new Vue({
...,
router : new VueRouter({
routes : [
{ path: '/foo', component: { template: '<div>foo</div>', created:function(){alert(1);} } },
//{ path: '/bar', component: { template: '<div>bar</div>', created:function(){alert(2);} } },
{ path: '/bar', component: Vue.component("ti-page-report") }
]
}),
...
});
vue-router has a dedicated page in docs on how to pass props to router-view.
Passing Props to Route Components
Example snippet from docs:
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, props: true },
// for routes with named views, you have to define the `props` option for each named view:
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
})
If you are looking for simplified usage, props can still be passed the same way they are passed to any component. But component that is used for rendering the route (the one that is specified in route definition) should expect to receive the props.
Here is simple usage example of passing props to router-view:
I personally decided to use provide/inject feature: preserving reactivity with minimal overhead.
The component ("ti-page-report") that needs to access the props being sent just needs to add it:
<template>
<div>
<h1>Now you can access page: {{ page }}</h1>
</div>
</template>
export default {
name: "TiPageReport",
props: ['page'], // can now be accessed with this.page
...
};
See https://v2.vuejs.org/v2/guide/components-props.html for how to use props properly.

Vue Router: hide parent template when child is open

Im trying to install Vue.js with the router and im running into some view issues. I have a router.js with child routes. I want to use this method for simple breadcrumbs and generate a clear overview so i know which route belongs where.
Opening each route works like a charm, everything shows up. When i open /apps I get a nice view from my Apps.vue that displays App overview</h1>. But now im opening /apps/app-one and then I see the Apps.vue and AppOne.vue template. How can I prevent that both templates are displayed?
The vue components looks like this:
Router.js
import Router from 'vue-router';
import AppsPage from './components/Apps.vue'
import AppOne from './components/AppOne.vue'
import AppTwo from './components/AppTwo.vue'
export default new Router({
// mode: 'history',
routes: [
{
path: '/apps',
component: AppsPage,
children: [
{
path: '/apps/app-one',
component: AppOne,
},
{
path: '/apps/app-two',
component: AppTwo,
},
]
},
]
});
Apps.vue
<template>
<div id="app-overview">
<h1>App overview</h1>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'app_page'
}
</script>
App1.vue
<template>
<div>
<h1>App 1</h1>
</div>
</template>
<script>
export default {
name: 'app_one'
}
</script>
App2.vue
<template>
<div>
<h1>App 2</h1>
</div>
</template>
<script>
export default {
name: 'app_two'
}
</script>
Having your routes in a parent-child relationship means that the child component will be rendered inside the parent component (at the <router-view>). This is expected behavior.
If you do not want the parent component to be visible when the child route is active, then the routes should be siblings, not nested:
[
{
path: '/apps',
component: AppsPage,
},
{
path: '/apps/app-one',
component: AppOne,
},
{
path: '/apps/app-two',
component: AppTwo,
},
]
The structure of the routes reflects the way they are rendered on the page.
It's possible and pretty easy too.You can achieve this by followings:
<template>
<div>
<div v-show="isExactActive">
Parent component contents will be here
</div>
<router-view ref="rv"></router-view>
</div>
</template>
<script>
export default {
data() {
return {
isExactActive: true,
}
},
updated() {
this.isExactActive = typeof this.$refs.rv === 'undefined';
},
mounted() {
this.isExactActive = typeof this.$refs.rv === 'undefined';
}
}
</script>
Hope, this will be helpful.

Passing dynamic data to Vue params/routes

I'm fairly new to Vue and am struggling to get something to work. Not entirely sure if this is possible but I'll ask and we'll see what the Stack Overflow gods have to conjure.
I wanted to know if it is possible to store component data/props for lots of IDs inside the data () portion of the default export.
So the {{$route.params.id}} manages to capture the id from the end of the url, but I want to know whether I can then have the View return other data stored somewhere in a component. So essentially is it possible for me to store data for let's say 5 different IDs all inside the Project.Vue file, or do I simply have to make 5 different files (Project1.Vue, Project2.Vue etc) and then set them all up as separate routes?
So far I have tried adding addings bits to the data () element such as
data () {
return {
msg: 'Projects',
id: [{ 1: 'hi'}, {2: 'hey'}],
two: 'project two',
three: 'project three',
}
}
And then referencing id inside the <template> but that didn't work as it simply returned the whole object. I also tried decoupling as mentioned here: https://router.vuejs.org/en/essentials/passing-props.html but had no joy with that either.
Apologies for my poor explanation but I hope somebody can help to shed light on whether this is possible. Code used below:
index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '#/components/Home'
import Contact from '#/components/Contact'
import About from '#/components/About'
import Projects from '#/components/Projects'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/contact',
name: 'Contact',
component: Contact
},
{
path: '/about',
name: 'About',
component: About
},
{
path: '/projects',
name: 'Projects',
component: Projects
},
{
path: '/projects/:id',
name: 'Projects',
component: Projects,
props: {default: true}
},
]
})
Projects.Vue
<template>
<div id="projects">
<h1>{{ header }} {{ $route.params.id }}</h1>
{{id}}
</div>
</template>
<script>
export default {
name: 'Projects',
watch: {
'$route'(to, from) {
// react to route changes...
}
},
data () {
return {
header: 'Projects',
}
}
}
</script>
<style scoped>
</style>
I have managed to figure it out.
In order to dynamically pass data based on the id passed in to the url, you need to create a data object and then inside of the of the <template>, you can pass in the object you have created but then pass the $route.params.id inside of the square brackets. However, it's worth noting that because the object created inside of your data() will use the zero index, it is worth adding a -1 inside of the template. See the below code to understand how it all works:
<template>
<div id="projects">
<h1>{{ msg }} {{ projects[$route.params.id - 1] }}</h1>
</div>
</template>
<script>
export default {
name: 'Projects',
watch: {
'$route'(to, from) {
// react to route changes...
}
},
data () {
return {
projects: [
{ id: 1,
name: 'Project numero uno'
},
{ id: 2,
name: 'Project secundo'
},
{ id: 3,
name: 'Project three'
},
]
}
}
}
</script>
<style scoped>
</style>

Categories