In my application I had three components that I used to show with router.
export const routing = RouterModule.forRoot([
{ path: '', component: HomeListComponent },
{ path: 'badge', component: BadgeListComponent},
{ path: 'badge-form', component: BadgeFormComponent },
{ path: 'badge-form/:id', component: BadgeFormComponent }
]);
Because I wanted to have something like this /badge/badge-form in url instead of /badge-form when I go to the form I changed my routing config to :
{ path: '', component: HomeListComponent },
{
path: 'badge',
component: BadgeListComponent,
children: [
{ path: 'badge-form', component: BadgeFormComponent },
{ path: 'badge-form/:id', component: BadgeFormComponent }
]
}
Unfortunately it's not working and I can't manage to find why, it's always loading the BadgeListComponent even if I go to the /badge/badge-form url.
HTML code for BadgeListComponent :
<div class="material-card-wide mdl-card mdl-shadow--2dp">
<div class="mdl-card__title mdl-card--border">
<h2 class="mdl-card__title-text">{{ title }}</h2>
</div>
<div class="list-card-body">
<table class="data-table-format">
<thead>
<tr>
<th>badgeNumber</th>
<th>authorizationLevel</th>
<th>endOfValidity</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let badge of pagedItems" (click)="editBadge(badge.badge_badgeNumber)">
<th>{{ badge.badge_badgeNumber }}</th>
<th>{{ badge.badge_authorizationLevel }}</th>
<th>{{ badge.badge_endOfValidity }}</th>
<td width="5%" (click)="deleteConfirmation(badge.badge_badgeNumber); $event.stopPropagation();">
<i class="material-icons delete-data-icon">delete_forever</i>
</td>
</tr>
</tbody>
</table>
</div>
<!-- pager -->
<div class="mdl-paging" *ngIf="pager.pages && pager.pages.length">
<button [disabled]="pager.currentPage === 1"
class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon"
(click)="setPage(pager.currentPage - 1)">
<i class="material-icons">keyboard_arrow_left</i>
</button>
<a *ngFor="let page of pager.pages"
[class.selected]="pager.currentPage === page"
class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon"
(click)="setPage(page)">
{{ page }}
</a>
<button [disabled]="pager.currentPage === pager.totalPages"
class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon"
(click)="setPage(pager.currentPage + 1)">
<i class="material-icons">keyboard_arrow_right</i>
</button>
<br />
<span class="paginationStats">Pages {{ pager.startPage }}-{{ this.pager.endPage }} of {{ pager.totalPages }}</span>
</div>
<div class="mdl-card__actions mdl-card--border">
<div class="buttonHolder">
<button routerLink="../badge-form" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--primary" *ngIf="!editing">
Add
</button>
</div>
</div>
</div>
When you navigate to /badge/badge-form, your current configuration tells Angular Router to render the BadgeListComponent by matching /badge, then render BadgeFormComponent within BadgeListComponent's <router-outlet>.
You need a componentless route to only render the children.
{ path: '', component: HomeListComponent },
{
path: 'badge',
children: [
{ path: '', component: BadgeListComponent },
{ path: 'badge-form', component: BadgeFormComponent },
{ path: 'badge-form/:id', component: BadgeFormComponent }
]
}
Is there any errors in your BadgeFormComponent? It may be blocking the transition between components and let you stick in the parent component BadgeListComponent.
By the way, I suggest you to switch the children routes like this:
...
children: [
{ path: 'badge-form/:id', component: BadgeFormComponent },
{ path: 'badge-form', component: BadgeFormComponent }
]
...
Because Angular Router takes the first route that matches one of the paths. Since you have paths with and without parameter, I guess parameter is optional.
Let me know if you have some issues in your BadgeFormComponent.
Related
WORKAROUND FOUND, SEE EDIT4
my router is acting a bit funny.
It works perfectly for the first link you click, however It doesn't apply the active class after the first time, if I refresh the page it will apply. you can see in the gif here:
Here is my navigation bar code:
<template>
<div class="nav">
<div class="nav__logo-box">
<img src="/logo-no-text-morning.png" :class="$mq" alt />
</div>
<div class="nav__nav-list">
<div class="nav__link">
<router-link to="/" exact-active-class="active-page">
<i class="fas fa-horse-head fa-3x"></i>
<p>Home</p>
</router-link>
</div>
<div class="nav__link">
<router-link to="/about" exact-active-class="active-page">
<i class="fas fa-info-circle fa-3x"></i>
<p>About</p>
</router-link>
</div>
<div class="nav__link">
<router-link to="/gallery" exact-active-class="active-page">
<i class="fas fa-images fa-3x"></i>
<p>Gallery</p>
</router-link>
</div>
<div class="nav__link">
<router-link to="/contact" exact-active-class="active-page">
<i class="fas fa-envelope-open-text fa-3x"></i>
<p>Contact</p>
</router-link>
</div>
</div>
</div>
</template>
Here is my router index.ts
import Vue from "vue"; import VueRouter, { RouteConfig } from "vue-router"; import Home from "../views/Home.vue"; Vue.use(VueRouter); const routes: Array<RouteConfig> = [ {
path: "/",
name: "Home",
component: Home }, {
path: "/about",
name: "About",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import("#/views/About.vue") }, {
path: "/contact",
name: "Contact",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import("#/views/Contact.vue") }, {
path: "/gallery",
name: "Gallery",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import("#/views/Gallery.vue") } ]; const router = new VueRouter({ routes }); export default router;
EDIT:
here's the a look at the web browser debugger:
It for some reason is adding an router-link-active to the home page (probably because its path is just "/").
And then it will add the exact-active just once, but then clicking on another page it will not change. it will stay on the page you was on before, only way to make it change is to refresh the page.
EDIT2:
So now I have decided to store the current page using the following code:
methods: {
getCurrentPage: function() {
this.currentPage = this.$router.currentRoute.name;
}
},
However you can see the behaivour here, it again doesn't update properly and lags behind, it's maybe one or two pages behind where I actaully am.
EDIT3:
I have tried to use a computed method to watch instead but it does not update, it just gets the first page its on and doesnt update again.
data: function() {
return {
currentPage: ""
};
},
computed: {
getCurrentPage: function() {
return this.$router.currentRoute.name;
}
},
mounted() {
console.log(this.$router.currentRoute.name);
this.currentPage === this.getCurrentPage;
}
EDIT4: (WORKAROUND FOUND)
So with the help of the comments, I've got a workaround that will work for now. it's this:
computed: {
getCurrentPage: function() {
return this.$route.name;
}
}
On the links I then bind the active page class:
<div class="nav__nav-list">
<div class="nav__link">
<router-link to="/" :class="{ currentpage: getCurrentPage === 'Home' }">
<i class="fas fa-horse-head fa-3x"></i>
<p ref="homeLink">Home</p>
</router-link>
</div>
<div class="nav__link">
<router-link to="/about" :class="{ currentpage: getCurrentPage === 'About' }">
<i class="fas fa-info-circle fa-3x"></i>
<p ref="aboutLink">About</p>
</router-link>
</div>
<div class="nav__link">
<router-link to="/gallery" :class="{ currentpage: getCurrentPage === 'Gallery' }">
<i class="fas fa-images fa-3x"></i>
<p ref="galleryLink">Gallery</p>
</router-link>
</div>
<div class="nav__link">
<router-link to="/contact" :class="{ currentpage: getCurrentPage === 'Contact' }">
<i class="fas fa-envelope-open-text fa-3x"></i>
<p ref="contactLink">Contact</p>
</router-link>
</div>
</div>
I hava a Angular 8 application and I try to get lazy loading working.
Googled a lot.
So it seems that everything works. but not on the correct way. Because I have a page and on that page you have icons where you will be redirected to that seperated page with that id.
So the html template looks like this:
<app-topbar header="Hulpbronnen overzicht">
</app-topbar>
<!-- <app-vital10-page header="Hulpbronnen overzicht">
</app-vital10-page> -->
<div class="inner-body">
<app-is-loading *ngIf="!resourcesLoaded" message="Hulpbronnen worden geladen"></app-is-loading>
<app-no-entries
*ngIf="!hasResources && resourcesLoaded"
type="hulpbronnen"
[loads]="resourcesLoaded"
></app-no-entries>
<div class="mobile-resource-filter" (click)="showFilterForMobile = true" *ngIf="allResourceThemesKeys.length > 0">
<span class="fa fa-filter"></span>
</div>
<div class="resources">
<div class="resources-main">
<div class="resource-row" *ngFor="let key of resourceThemesKeys" [#fade]>
<h3 class="resource-row-title">{{ key }}</h3>
<div class="resource-items">
<app-resource-item *ngFor="let item of resourceThemes[key]" [resource]="item">
</app-resource-item>
</div>
</div>
</div>
<div
class="resources-side"
*ngIf="allResourceThemesKeys.length > 0"
[ngClass]="{'stuck-to-top': showFilterForMobile}"
>
<div class="resources-filter resource-row">
<h3 class="resources-header resources-header-filter resource-row-title">Thema Filter</h3>
<div class="resources-filter-body">
<div class="resource-filter-item">
<label for="filter-all" class="resources-filter-label">
<input
type="checkbox"
class="resources-filter-input resources-filter-input-all"
id="filter-all"
(change)="filterAll(allOn)"
[checked]="!allOn"
/>
Filter alles
</label>
<div class="resource-filter-close" *ngIf="showFilterForMobile">
<button type="button" class="button" (click)="showFilterForMobile = false">Sluit</button>
</div>
</div>
<div class="resources-filter-item">
<label for="{{ theme }}" class="resources-filter-label" *ngFor="let theme of allResourceThemesKeys">
<input
type="checkbox"
id="{{ theme }}"
class="resources-filter-input"
[checked]="resourceThemesKeys.indexOf(theme) !== -1"
(change)="handleFilterChange(theme)"
/>
{{ theme }}
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<router-outlet></router-outlet>
And the router module looks like this:
const ResourceRouters: Routes = [
{
path: '',
component: ResourcePageComponent,
children: [
{path: '', pathMatch: 'full', canActivate: [AuthGuard] },
{path: 'detail/:hulpbronId', component: ResourceDetailComponent, canActivate: [AuthGuard]}
]
}
];
#NgModule({
imports: [
RouterModule.forChild(ResourceRouters)
],
exports: [RouterModule]
})
and the main url looks like this:
http://localhost:4200/hulpbronnen
and then for example you have the id of:
http://localhost:4200/hulpbronnen/detail/6688089b-9794-4169-8569-260d427bed03
But now the content of that id will be rendered on the main page and not on his own component.
what it has to be
and in app.routes.ts I have it like this:
{path: 'hulpbronnen', loadChildren: () => import('./resource/resource.module').then(m => m.ResourceModule)},
So my question is:where I have to put the
<router-outlet></router-outlet>
Thank you
So that the child page will be show correct
You can try following approach if it suits you:
Create a new component ResourceIndexComponent- put the <router-outlet></router-outlet> into the html template there.
Restructure ResourceRoutes this way:
const ResourceRouters: Routes = [
{
path: '',
component: ResourceIndexComponent,
children: [
{ path: '', pathMatch: 'full', component: ResourcePageComponent, canActivate: [AuthGuard] },
{ path: 'detail/:hulpbronId', component: ResourceDetailComponent, canActivate: [AuthGuard] },
],
},
];
I am traversing a json data inside a table in vue and passing some of it to a different page using router link.
Projects.vue
<tbody class>
<tr v-for="project in projects" aria-rowindex="1" class>
<td aria-colindex="1" class>{{project.name}}</td>
<td aria-colindex="2" class>{{project.date}}</td>
<td aria-colindex="3" style="width: 100px">
<router-link to={name: 'Performance', params: {{project.Line_base}} }>
<i class="fa fa-eye"></i>
</router-link>
<i class="fa fa-edit"></i>
<i class="fa fa-remove icons" style="color: red"></i>
<i class="fa fa-share-alt"></i>
</td>
<!-- <td aria-colindex="4" class>{{project.short_description}}</td> -->
</tr>
import axios from 'axios';
import Performance from "./Performance";
export default {
components: {
Performance
},
name: "builder-basic",
data() {
return {
projects: []
};
},
mounted () {
axios
.get('http://some.api.net/v1/projects/')
.then(response => (this. projects = response.data.entities))
},
};
</script>
This project.Line_base is an array of integers, that I want to pass to
Performance.vue
<template>
<div class="animated fadeIn">
<b-card header-tag="header" footer-tag="footer">
<div slot="header">Performance - Models vs Baseline</div>
<div class="card-body" >
<div class="chart-wrapper" >
<b-card header="Lift Chart" >
<div class="chart-wrapper">
<line-example chartId="chart-line-01" :styles="chartStyle" />
</div>
</b-card>
</div>
</div>
<div class="card-body" >
<div class="chart-wrapper">
<b-card header="Accuracy & Sensitivity" >
<bar-example chartId="chart-bar-01" :styles="chartStyle" />
</b-card>
</div>
</div>
</b-card>
</div>
</template>
<script>
import axios from "axios";
import LineExample from "./charts/LineExample";
import BarExample from "./charts/BarExample";
export default {
name: 'Performance',
components: {
LineExample,
BarExample
},
computed: {
chartStyle () {
return {
height: '500px',
position: 'relative'
}
}
}
}
};
</script>
I have the index.js where I have mentioned the routers, which are working well if I am not passing any data to performance, from where I will generate a graph using charts.
index.js
let router = new Router({
mode: 'hash', // https://router.vuejs.org/api/#mode
linkActiveClass: 'open active',
scrollBehavior: () => ({ y: 0 }),
routes: [
{
path: '/',
redirect: '/dashboard',
name: 'Home',
component: DefaultContainer,
children: [
{
path: 'Performance',
name: 'Performance',
component: Performance
}])
The data is not being passed, I followed some of the articles already discussed on stack overflow
Send the params like this;
<router-link :to="{name: 'Performance', params: { Line_base: project.Line_base }}">
<i class="fa fa-eye"></i>
</router-link>
In your Performance.vue Component you need to get de params from the route like this.
computed: {
lineBase () {
return this.$route.params.Line_base
}
}
It seems like you are making a syntaxerror. This the example from the vue router docs:
<!-- named route -->
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
Further on in the docs it specifies router-link properties, stating:
route.params
type: Object
An object that contains key/value pairs of dynamic segments and star
segments. If there are no params the value will be an empty object.
Compare that to your code:
<router-link to={name: 'Performance', params: {{project.Line_base}} }>
It seems you are forgetting the semicolon before to (which is shorthand for v-bind:to. Without that whatever comes after will just be passed as a string rather than a javascript expression. This should help.
You could try rewriting to:
<router-link :to="{name: 'Performance', params: {Line_base: project.Line_base} }">
Hope that helps!
EDIT: added clarification
My vue-router routes the URL on all menu buttons correctly, but does not show each Vue component properly. A demonstration can be found here.
Inside of my HTML (I am using Vuefy)
<div class="navbar-start">
<a class="navbar-item">
<router-link to="/" class="router-link"> // <-- THIS WORKS
Home
</router-link>
</a>
<a class="navbar-item">
<router-link to="/items" class="router-link"> // <-- THIS WORKS
My Products
</router-link>
</a>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">
<router-link to="/information" class="router-link"> // <-- DOES NOT WORK
Info
</router-link>
</a>
<div class="navbar-dropdown is-boxed">
<a class="navbar-item">
<router-link to="/about" class="router-link"> // <-- THIS WORKS
About
</router-link>
</a>
<a class="navbar-item">
<router-link to="/terms" class="router-link"> // <-- DOES NOT WORK
Terms
</router-link>
</a>
</div>
</div>
</div>
My router.js file is set up the following:
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/about',
name: 'about',
component: () => import('./views/About.vue')
},
{
path: '/new',
name: 'create-item',
component: () => import('./views/CreateItem.vue')
},
{
path: '/',
name: 'home',
component: Home
},
{
path: '/items',
name: 'my-items',
component: () => import('./views/MyItems.vue')
},
{
path: '/signin',
name: 'sign-in',
components: () => import('./views/SignIn.vue')
},
{
path: '/terms',
name: 'terms',
components: () => import('./views/Terms.vue')
},
{
path: '/information',
name: 'info',
components: () => import('./views/Info.vue')
}
]
})
Additionally, my App.vue file shows the router-view properly, along with the menu.
<template>
<div id="app">
<div id="nav">
<Menu/>
</div>
<router-view/>
</div>
</template>
<script type="text/javascript">
import Menu from '#/components/Menu.vue'
export default {
components: {
Menu
}
}
</script>
The following is a photograph of my navigation. To repeat, clicking on 'info' and 'terms' (submenu of info) do not load their respective Vue components, but does change the URL.
I triple-checked my syntax and checked the documentation, but could not seem to find my error. The platform at which my code is hosted at can be found here. Any help would be appreciated. Thanks, Edwin.
I found the error. I spelled 'component' instead of 'components' several times in my routes.js file.
I'm having an issue with doing a redirect following a form submission for logging in on Angular 2. The application performs a full reload on the redirect to dashboard. I have checked several posts on stack overflow & other blogs, with no luck. This is the closest one; However, there is no answer on the thread. See my code below.
After I press the login, the page loads, and then reloads again. The URL is also changing to put the query string in the URL, which I suspect is causing the issue. How can I fix this issue? I suspect is has something to do with the way my form is set up.
auth.component.ts
import { Component, OnInit, ViewChild } from '#angular/core';
import { NgForm, FormBuilder, Validators } from '#angular/forms';
import { Router } from '#angular/router';
import { User } from '../shared/user';
declare var Materialize:any;
import { AuthService } from '../shared/services/auth.service';
#Component({
moduleId: module.id,
selector: 'logon',
templateUrl: 'auth.component.html',
})
export class AuthComponent implements OnInit {
currentUser = new User(null, '', '', '', '', 'vistor');
submitted = false;
authForm: NgForm;
#ViewChild('authForm') currentForm: NgForm;
constructor(
private router: Router,
public authService: AuthService
) { }
ngOnInit(): void {
}
onSubmit() {
this.submitted = true;
this.authService.login(this.currentUser).then(response => {
if (response) {
this.goToDashboard();
} else {
var toastContent = '<span><b>Invalid email or password!</b></span>';
Materialize.toast(toastContent, 5000, 'red');
}
});
}
goToDashboard() {
this.router.navigate(['dashboard']);
}
}
auth.component.html
<div class="container">
<div class="card">
<div class="card-content">
<span class="card-title">Logon</span>
<form materialize #authForm="ngForm" class="col s12">
<div class="input-field col s12">
<input required class="validate" id="email" type="email" name="email" [(ngModel)]="currentUser.email" #email="ngModel" validate="email">
<label for="email" data-error="Invalid Email">Email</label>
</div>
<div class="input-field col s12">
<input required class="validate" id="password" type="password" name="password" [(ngModel)]="currentUser.password" #password="ngModel" validate="password">
<label for="password" data-error="Invalid Password">Password</label>
</div>
<div class="card-action">
<button [disabled]="!authForm.form.valid" (click)="onSubmit()" class="btn orange darken-1 waves-effect waves-light" type="submit">Log In
<i class="material-icons right">send</i>
</button>
</div>
</form>
</div>
</div>
</div>
Angular 2 Routes
const routes: Routes = [
{ path: '', redirectTo: '/auth', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'spelling', component: SpellingComponent },
{ path: 'definition', component: DefinitionComponent },
{ path: 'auth', component: AuthComponent },
{ path: '**', redirectTo: '/dashboard', pathMatch: 'full' }
];
Don't use the type as submit in Angular Single Page applications. The reason might be
<button [disabled]="!authForm.form.valid" (click)="onSubmit()" class="btn orange darken-1 waves-effect waves-light" type="submit">Log In
<i class="material-icons right">send</i>
</button>
Try using
<button [disabled]="!authForm.form.valid" (click)="onSubmit()" class="btn orange darken-1 waves-effect waves-light" type="button">Log In
<i class="material-icons right">send</i>
</button>
Angular 2 needs an order in paths to show the correct routing, I think the solution is related with the order of paths. For example, you can try this:
const routes: Routes = [
{ path: '', redirectTo: '/auth', pathMatch: 'full' },
{ path: 'auth', component: AuthComponent },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'spelling', component: SpellingComponent },
{ path: 'definition', component: DefinitionComponent },
{ path: '**', redirectTo: '/dashboard' }
];
and
goToDashboard() {
this.router.navigate(['dashboard/']);
}