Angular router link "stops" working? - javascript

app.routes.ts:
import { environment } from './environment';
import { RouterModule } from "#angular/router";
import { ContactUsComponent } from './static/components/contact-us.component';
import { HomeComponent } from './static/components/home.component';
import { PrivacyComponent } from './static/components/privacy.component';
import { ProductDetailsComponent } from './products/components/product-details.component';
import { ProductListComponent } from './products/components/product-list.component';
import { TermsComponent } from './static/components/terms.component';
export const ApplicationRoutes = RouterModule.forRoot([
{
path: '',
component: HomeComponent
},
{
path: 'products',
loadChildren : 'app/products/products.module#ProductModule'
},
{
path: 'product/:id',
component: ProductDetailsComponent
}
]);
product.routes.ts:
import { RouterModule } from "#angular/router";
import { ProductListComponent } from '../components/product-list.component';
import { ProductDetailsComponent } from '../components/product-details.component';
export const ProductRoutes = RouterModule.forChild([
{
path: 'products',
component: ProductListComponent
}
,
{
path: 'product/:id',
component: ProductDetailsComponent
}
]);
app.component.html:
Welcome!
<br/>
<div>
<a routerLink="/">Home</a>
</div>
<div>
<product-list></product-list>
</div>
<div>
<router-outlet></router-outlet>
</div>
<br/>
<div>
<a routerLink="terms">Terms</a>
<a routerLink="contact-us">Contact Us</a>
<a routerLink="privacy">Privacy</a>
</div>
product-list.component.html:
<product *ngFor="let p of products" [product]="p"></product>
product.component.ts:
import { Component, Input } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
#Component({
selector : 'product',
template :
` <div>
<a [routerLink]="['product', product.id]">
{{product.name}}
</a>
</div>
})
What happens is when I click on a product link in the app.component.html page, it loads ProductDetailsComponent containing the information for that product, but when I try to click on the other links again, the URL in the browser changes but nothing happens.
What I need is that on the first page load, say 'local.shop.com', a static component is displayed containing links to the products, inside app.component.html, and when you click on each link, it presents information regarding that product. I'm trying to avoid having to reload the page.
I'm not sure which more snippets of code are needed to provide enough context for this question, but please let me know.

this is due to angular component reuse feature that it changes the url, but doesnt change the view. You need to subscribe to the parameter received in your ProductDetailsComponent, and do something to it.
1) in your ProductDetailsComponent, import ActivatedRoute from #angular/route and Subscription from rxjs
import { Subscription } from 'rxjs/Rx';
import { ActivatedRoute} from '#angular/router';
import { Component, OnInit, OnDestroy} from '#angular/router';
export class ProductDetailsComponent implements onInit, onDestroy {
private subscription: Subscription;
productId: string;
2) in your ngOnInit, subscribe and do something inside it
ngOnInit() {
this.subscription = this.activatedRoute.params.subscribe((params) => {
this.productId = params['id'];
//do something here to trigger the changes
this.product = this.productService.getProduct(this.productId);
//example
console.log(this.product);
});
3) last but not least, do not forget to unsubscribe
ngOnDestroy() {
this.subscription.unsubscribe();
}
and of course, do not forget to call it in your constructor
constructor(private activatedRoute: ActivatedRoute) {}

Related

Angular routing problem - routing won't work as usual

I have a problem where when I type manually localhost:4200/create it goes on the page where i want it to go, but when I click on a link to lead me there, I get an error saying:
TypeError: Cannot read property 'unsubscribe' of undefined
at PostListComponent.ngOnDestroy
Here's my code:
header.component.html
<mat-toolbar color="primary">
<span><a routerLink="/">My Messages</a></span>
<ul>
<li><a routerLink="/create">New Post</a></li>
</ul>
</mat-toolbar>
app-routing.module.ts:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { PostCreateComponent } from './posts/post-create/post-create.component';
import { PostListComponent } from './posts/post-list/post-list.component';
const routes: Routes = [
{path: '', component: PostListComponent},
{path: 'create', component: PostCreateComponent},
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
postlistcomponent.ts
import { Component, OnDestroy, OnInit } from '#angular/core';
import { Subscription } from 'rxjs';
import { Post } from '../posts';
import { PostsService } from '../posts.service';
#Component({
selector: 'app-post-list',
templateUrl: './post-list.component.html',
styleUrls: ['./post-list.component.css'],
})
export class PostListComponent implements OnInit, OnDestroy {
posts: Post[] = [];
private postsSub: Subscription;
constructor(public postsService: PostsService) {}
ngOnInit(): void {
this.postsService.getPosts();
this.postsService.getPostUpdateListener().subscribe((posts: Post[]) => {
this.posts = posts;
});
}
onDelete(postId: string) {
this.postsService.deletePost(postId);
}
ngOnDestroy() {
this.postsSub.unsubscribe();
}
}
Like the error says, you're calling unsubscribe on an object that doesn't exist in PostListComponent (postlist.component.ts?)
In that file, find the ngOnDestroy function and for any this.object$.unsubscribe() functions, test for the object first -
if (this.object$ && !this.object$.closed) {
this.object$.unsubscribe()
}
I'm using this.object$ as an example - your variable will be called something different
When you navigate from / to /create your ngOnDestroy in the PostListComponent is throwing an error.
This is why it is happening on the link and not when you put in the url.
As you can see in your ngInit you are not passing any value to your variable (postsSub). That is why you cannot destroy it.
Change this :
ngOnInit(): void {
this.postsService.getPosts();
this.postsService.getPostUpdateListener().subscribe((posts: Post[]) => {
this.posts = posts;
});
}
For this:
ngOnInit(): void {
this.postsService.getPosts();
this.postsSub = this.postsService.getPostUpdateListener().subscribe((posts: Post[]) => {
this.posts = posts;
});
}
That should work.
Regards

Redirecting to maintenance page

I am looking for ways of redirecting a page to the maintenance page in angular but i am new and am research different methods for turning on maintenance mode
i found a possible solution here: # the approved answer
Angular JS redirect to page within module config
however i don't know how to implement it
if there someone who could explain it, i would appreciate it greatly
using an authGuard will solve this problem
auth-guard.service.ts file:
import { Injectable } from '#angular/core';
import { CanActivate, Router, RouterStateSnapshot, ActivatedRouteSnapshot } from '#angular/router';
import { AuthService } from './auth.service';
import { Observable } from 'rxjs';
#Injectable()
export class AuthGuardMaintenance implements CanActivate {
constructor(
private authService: AuthService, private router: Router
) {}
canActivate(): Observable<boolean> | Promise<boolean> | boolean {
if (this.authService.inMaintenance()) {
alert('This Site Is Still Under Maintenance')
this.router.navigate(['/maintenance']);
return false;
} else {
this.router.navigate(['/']);
return true;
}
}
}
auth.service file:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class AuthService {
constructor() { }
inMaintenance() {
return false;
}
}
then import it in the app.module.ts file and add it to providers
then import the auth guard to the app-routing.module.ts file add the property
canActivate: [AuthGuardMaintenance]
to the the root route
eg
export const routes: Routes = [
{ path: '', component: MainComponent, canActivate: [AuthGuardMaintenance] },
{ path: 'maintenance', component: MaintenanceViewComponent },
{ path: '**', component: PageNotFoundComponent },
];

change data on route event in Angular

How to change data in one component relatively to others on route event in Angular?
For e.g. if I have three components: "nav.component", "about.component" and "service.component".
So I want to display different text in "nav.component" when I switch between about and service pages in my app.
My "app.router.ts" file:
import { ModuleWithProviders } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
import { AboutComponent } from './about/about.component';
import { ServiceComponent } from './service/service.component';
export const router: Routes = [
{ path: '', redirectTo: 'about', pathMatch: 'full' },
{ path: 'about', component: AboutComponent },
{ path: 'service', component: ServiceComponent }
];
export const routes: ModuleWithProviders = RouterModule.forRoot(router);
I don't want to display just page name text in my nav bar while switching between these pages, it would be a custom text for each component.
Also I would like to store this data/text directly in "about.component.ts" and "service.component.ts" but not in the "app.router.ts" due to maintainability and scalability.
Is it possible?
U.P.D.
This is my "app.component.html" file:
<div class="container">
<!-- Nav Bar (text changes here) -->
<app-nav></app-nav>
<!-- Pages (components which are included in app.router.ts) -->
<router-outlet></router-outlet>
</div>
For e.g. this is "about.component.ts" file:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-about',
templateUrl: './about.component.html',
styleUrls: ['./about.component.scss']
})
export class AboutComponent implements OnInit {
const text_for_nav_bar = "This is my new About page."; // <-- text that should be displayed in nav component for this page on router event.
constructor() { }
ngOnInit() {
}
}
Using below code you will able to subscribe router change events. You need to add this code on nav bar.
Import router and Navigation start
import { Router, ActivatedRoute, NavigationStart } from '#angular/router';
import "rxjs/add/operator/filter";
import "rxjs/add/operator/pairwise";
Add below code in constrictor.
this.router.events
.filter(event => event instanceof NavigationStart)
.pairwise()
.subscribe((value: [NavigationStart, NavigationStart]) => {
let nextUrl = value[1].url;
if (nextUrl == '/about') {
// your code here for next url
}
},
(err) => {
},
() => { });
}
});
One way would be with *ngIf (or [hidden] if you want to load all contents to the DOM at once). And to catch current route, inject Router module:
class NavComponent {
constructor(private router: Router){
}
}
and in nav.component.html:
<div *ngIf="router.url === '/some/route'">
text for this route
</div>
<div *ngIf="router.url === '/other/route'">
text for other route
</div>
Doing same in component.ts, could be:
nav.component.html:
<h1>{{yourText}}</h1>
component.ts:
ngOnInit() {
if(this.router.url == '/some/route') {
yourText = 'Text'
} elseif(this.router.url == '/other/route') {
yourText = 'Other text'
}
}
You should use router datas
export const router: Routes = [
{ path: '', redirectTo: 'about', pathMatch: 'full' },
{ path: 'about', component: AboutComponent, data: {navigationText: 'Some text'} },
{ path: 'service', component: ServiceComponent, data: {navigationText: 'Some other text'} }
];
and in app.component.html
<div class="container">
<app-nav text="outlet.activatedRouteData.navigationText"></app-nav>
<router-outlet #outlet="outlet"></router-outlet>
</div>
Of course you need to add a "#Input text: string" property in nav.component.ts

How to import legacy js node_modules files in angular2 with webpack

I've a issue, I can't to import a BootstrapMenu in Angular2 with Bootstrap I met a difficulty when I want to import .js files with Webpack.
I get this error in my console :
Cannot find name 'BootstrapMenu'
I try to import BootStrapMenu like this :
import '../../../node_modules/bootstrap-menu/dist/BootstrapMenu.min.js';
This is my component :
import { Component } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import '../../../node_modules/bootstrap-menu/dist/BootstrapMenu.min.js';
console.log('`Dashboard` component loaded asynchronously');
#Component({
selector: 'dashboard',
templateUrl: 'dashboard.component.html'
})
export class Dashboard {
localState;
constructor(public route: ActivatedRoute) {
}
ngOnInit() {
this.route
.data
.subscribe((data: any) => {
this.localState = data.yourData;
});
console.log('hello `Dashboard` component');
var menu = new BootstrapMenu('.line', {
.....
.......
}
});
}
asyncDataWithWebpack() {
}
}
Thanks for your help

Redirect within component Angular 2

I have a simple method that at the end of it I want to redirect to another component:
export class AddDisplay{
display: any;
addPairTo(name: string, pairTo: string){
this.display = {};
this.display.name = name;
this.display.pairTo = pairTo;
}
}
What I wanna do is at the end of the method redirect to another component:
export class AddDisplay{
display: any;
addPairTo(name: string, pairTo: string){
this.display = {};
this.display.name = name;
this.display.pairTo = pairTo;
this.redirectTo('foo');
}
}
How do I achieve this in Angular 2?
first configure routing
import {RouteConfig, Router, ROUTER_DIRECTIVES} from 'angular2/router';
and
#RouteConfig([
{ path: '/addDisplay', component: AddDisplay, as: 'addDisplay' },
{ path: '/<secondComponent>', component: '<secondComponentName>', as: 'secondComponentAs' },
])
then in your component import and then inject Router
import {Router} from 'angular2/router'
export class AddDisplay {
constructor(private router: Router)
}
the last thing you have to do is to call
this.router.navigateByUrl('<pathDefinedInRouteConfig>');
or
this.router.navigate(['<aliasInRouteConfig>']);
#kit's answer is okay, but remember to add ROUTER_PROVIDERS to providers in the component. Then you can redirect to another page within ngOnInit method:
import {Component, OnInit} from 'angular2/core';
import {Router, ROUTER_PROVIDERS} from 'angular2/router'
#Component({
selector: 'loginForm',
templateUrl: 'login.html',
providers: [ROUTER_PROVIDERS]
})
export class LoginComponent implements OnInit {
constructor(private router: Router) { }
ngOnInit() {
this.router.navigate(['./SomewhereElse']);
}
}
This worked for me Angular cli 6.x:
import {Router} from '#angular/router';
constructor(private artistService: ArtistService, private router: Router) { }
selectRow(id: number): void{
this.router.navigate([`./artist-detail/${id}`]);
}
callLog(){
this.http.get('http://localhost:3000/getstudent/'+this.login.email+'/'+this.login.password)
.subscribe(data => {
this.getstud=data as string[];
if(this.getstud.length!==0) {
console.log(data)
this.route.navigate(['home']);// used for routing after importing Router
}
});
}

Categories