How to get previous route on 404 Error page in angular? - javascript

I have some pages and when I change router link to some wrong url and it redirect me to 404 page. In this 404 Error page I have button that will redirect me to previous page. Now I have some problems that this redirect button when I click it redirects to that wrong url and again to 404.
I try to show by photo:
1)My route. write wrong url -> redirect to 404 page.
Now the problem is when I click button to redirect at the previous route "Home" it redirect me to this wrong route.
goBack() {
this._location.back();
}

You can use JS history API to achieve this.
This is a sample to match your use case
goBack() {
window.history.go(-2);
}
And this also keeps navigiation within the SPA scope (Page wouldn't refresh).
Side effect for this is that you need to make sure that the user follows a particular flow; in which he needs to be within a working page, then goes somewhere not found then get redirected to the 404 Page..
I would recommend a button that navigates to Home or Dashboard features instead.

You can achieve this by number of ways , however I think the most elegant way is to use power of Injectable services in Angular.
Here is my solution of this problem:
Create an Injectable service which will set a variable as soon as the current navigation end. The value of this variable can be used in any of the other components where ever we would need. Obviously one has to inject the service in the required component.
In my example, I have created RouterService:
import { Injectable } from '#angular/core';
import { Router, NavigationEnd } from '#angular/router';
#Injectable({ providedIn: 'root' })
export class RouterService {
private previousUrl: string = undefined;
private currentUrl: string = undefined;
constructor(public router : Router) {
this.currentUrl = this.router.url;
router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
this.previousUrl = this.currentUrl;
this.currentUrl = event.url;
};
});
}
public getPreviousUrl(){
return this.previousUrl;
}
}
To illustrate the navigation , I have created two components viz. home and not-found Components.
Below are the code snippets for both of these components :
a) home.component.ts :
import { Component, VERSION } from '#angular/core';
import { NavigationEnd, Router } from '#angular/router';
import { filter } from 'rxjs/operators';
import { RouterService } from '../../service/router.service';
#Component({
selector: 'not-home-app',
templateUrl: './home.component.html',
styleUrls: [ './home.component.scss' ]
})
export class HomeComponent {
name = 'Angular ' + VERSION.major;
constructor(private router: Router,private routerService: RouterService) {}
takeMeToNotFoundPage(){
this.router.navigate(['/notFound']);
}
}
b) not-found.component.ts:
import { Component, VERSION } from '#angular/core';
import { NavigationEnd, Router } from '#angular/router';
import { filter } from 'rxjs/operators';
import { RouterService } from '../../service/router.service';
#Component({
selector: 'not-found-app',
templateUrl: './not-found.component.html',
styleUrls: [ './not-found.component.scss' ]
})
export class NotFoundComponent {
previousUrl: string;
constructor(private router: Router, private routerService: RouterService) {
router.events
.pipe(filter(event => event instanceof NavigationEnd))
.subscribe((event: NavigationEnd) => {
console.log('prev:', event.url);
this.previousUrl = event.url;
});
}
loadPreviousRoute(){
let previous = this.routerService.getPreviousUrl();
if(previous)
this.routerService.router.navigateByUrl(previous);
}
}
When the application will first load, I will route it to 'home' page. There I provided a button to navigate to not-found page.
As you see in the above code of home component , I am setting the previous url in the router service which I can use in next component ( in this example it is 'not-found' component'
c) below are the html code snippets for both home and not-found components :
Home.component.html :
<hello name="{{ name }}"></hello>
<p>
Start editing to see some magic happen :)
</p>
<button type="button" (click)="takeMeToNotFoundPage()">Not FOUND!</button>
not-found.component.html:
<p>
<span style="background-color: red">NOT FOUND!!</span>
</p>
<button type="button" (click)="loadPreviousRoute()">Go Back to Previous Route</button>
Hope this will help you to solve your problem. If it will , please provide your feedback and upvote it accordingly as it will help others in future too.

Related

How do i add properly create a component to my Jhipster + Angular project with a workin routerlink?

SO i generated a new application on jhipster and i have wanted to create a front side FAQ page for my web portal, i created it as an entity and it generated all the CRUD components (detail, delete, edit). This of course in the jhipster template looks like an admin/user view table with buttons to view, edit or delete. I want to make the FAQ public to visitors of the website without needing to have an account...
So i generated a component 'faq-page' like the documentation says: https://www.jhipster.tech/using-angular/ only problem is the routerlink does not redirect me to '/faq' instead it redirects me to the 404 page. I created the 'faq-page' component based on the existing 'home' like below snippets:
faq-page.component.html (just has some texts for now)
faq-page.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'jhi-faq-page',
templateUrl: './faq-page.component.html',
styleUrls: ['./faq-page.component.scss']
})
export class FaqPageComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
faq-page.module.ts
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { TestAppSharedModule } from 'app/shared/shared.module';
import { FAQ_PAGE_ROUTE } from './faq-page.route';
import { FaqPageComponent } from './faq-page.component'
#NgModule({
imports: [RouterModule.forChild([FAQ_PAGE_ROUTE]), TestAppSharedModule ],
declarations: [FaqPageComponent]
})
export class FaqModule { }
faq-page.route.ts
import { Route } from '#angular/router';
import { FaqPageComponent } from './faq-page.component';
export const FAQ_PAGE_ROUTE: Route = {
path: 'faq',
component: FaqPageComponent,
data: {
authorities: [],
pageTitle: 'faq-page.title'
}
};
Check your app-routing.module.ts and make sure the ...LAYOUT_ROUTES, line comes last!
ng generate will add your new component at the end, which will let the catch-all 404 page (contained in LAYOUT_ROUTES) match before your new page.
This needs to be printed somewhere in large friendly letters.

Angular how to hide a global component when a specific route is opened? [duplicate]

This question already has answers here:
How to Update a Component without refreshing full page - Angular
(7 answers)
Closed 3 years ago.
I'm not sure whether this is possible or not in angular but I wanted to hide a global component when a specific route is opened.
Say for example I have the following:
app.component.html
<app-header></app-header>
<app-banner></app-banner> <!-- Global Component I want to hide -->
<div class="body-container">
<router-outlet></router-outlet>
</div>
<app-footer></app-footer>
app-routing.module.ts
import {NgModule} from '#angular/core';
import {Route, RouterModule} from '#angular/router';
import { StudentListComponent } from './Components/StudentList/StudentList.component';
import { SchoolMottoComponent } from './Components/SchoolMotto/SchoolMotto.component';
const routes: Routes = [
{path: 'StudentList', component: StudentListComponent },
{path: 'SchoolMotto', component: SchoolMottoComponent }
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
export const routingComponents = [StudentListComponent, SchoolMottoComponent]
With this, its a given that when I want to view the StudentList Component, then the url by default becomes localhost4200:/StudentList and the same with SchoolMotto it becomes localhost4200:/SchoolMotto.
Within the StudentListComponent, is an ag-grid that displays list of students, and when you click one of those students the url becomes something like this: localhost4200:/StudentList/view/cf077d79-a62d-46e6-bd94-14e733a5939d and its another sub-component of SchoolList that displays the details of that particular student.
I wanted to hide the Global banner component when the url has something like that: localhost4200:/StudentList/view/cf077d79-a62d-46e6-bd94-14e733a5939d. Only when the user views the specific details of a student.
Something like this:
app.component.html
<app-header></app-header>
**<app-banner *ngIf="router != '/StudentList/view/'"></app-banner> <!-- Global Component I want to hide -->**
<div class="body-container">
<router-outlet></router-outlet>
</div>
<app-footer></app-footer>
Is this doable or not? If it is, how?
You could use event emitter or subject to emit an event when you're in StudentList/view and use ngIf to hide the banner.
In your StudentList component.ts :
export class StudentList {
bannerSubject: Subject<any> = new Subject<any>();
ngOnInit() {
bannerSubject.next(true);
}
}
subscribe to this in your parent component and you can easily hide the banner.
You can acheieve that with the help of component interation using a service
You will use the help of Rxjs Observables here
You will emit an event when you reach the student view component, then recieve that event in app component then change the view condition
New Service:
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs';
#Injectable()
export class RouteService {
private routeChangedSource = new Subject<string>();
// Observable string streams
routeChanged$ = this.routeChangedSource.asObservable();
// Service message commands
changeRoute(mission: string) {
this.routeChangedSource.next(mission);
}
}
Student View Component.
import { Component } from '#angular/core';
import { routeService } from './mission.service';
#Component({
})
export class MissionControlComponent implements ngOnInit{
constructor(private routeService: routeService) {}
ngOnInit() {
this.routeService.changeRoute(mission);
}
}
App Component:
import { Component, Input, OnDestroy } from '#angular/core';
import { RouteService } from './route.service';
import { Subscription } from 'rxjs';
export class AppComponent implements OnDestroy {
studentView = false;
constructor(private routeService: RouteService) {
this.subscription = routeService.routeChanged$.subscribe(
value => {
this.studentView = true;
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
Now, your App Component can be:
<app-header></app-header>
<app-banner *ngIf="!studentView"></app-banner>
<div class="body-container">
<router-outlet></router-outlet>
</div>
<app-footer></app-footer>
<app-header></app-header>
<app-banner *ngIf="myService.hideGlobalComp"></app-banner> <!-- Global Component I want to hide -->
<div class="body-container">
<router-outlet></router-outlet>
</div>
<app-footer></app-footer>
in the ts file:
onCellClicked($event) { // place into your method there you want.
this.route.parent.url.subscribe(urlPath => {
this.url = urlPath[urlPath.length - 1].path;
});
if(this.url === 'StudentList/view') {
this.myService.hideGlobalComp = true;
}
}
}
In you ts file do like this.
add new variable router: string;
add in construction add this
constructor(private _router: Router){
this.router = _router.url;
}
Then in HTML use same code.
Let me know if this does not work.

Angular/Angular2, Refresh Component From routerLink (NavBar) , If already in existing route

If i am on same route , and i click again from nav bar. It doesn't do anything .
How can I refresh my component from navbar itself. Is there any method in routerLink.
<li [routerLinkActive]="['active']"><a [routerLink]="['/campaigns']">Creative</a></li>
<li [routerLinkActive]="['active']"><a [routerLink]="['/market-survey']">Survey</a></li>
click again means, suppose you click on creative (in my example) corresponding route will activate and component is loaded . Then I again click on creative . I want that component should refresh
This can be fixed this by creating another component
refresh.component.ts
import { Component, OnInit } from '#angular/core';
import {Router, ActivatedRoute, Params} from '#angular/router';
#Component({
selector: 'app-refresh',
template: `
<p>
refresh Works!
</p>
`,
styles: []
})
export class RefreshComponent implements OnInit {
constructor(private activatedRoute:ActivatedRoute,private route:Router) { }
ngOnInit() {
this.activatedRoute
.queryParams
.subscribe(params => {
if(params.url){
this.route.navigate([params.url]);
}
});
}
}
app.routing
{path: 'refresh',component:RefreshComponent},
and my new naviation li is
<li [routerLinkActive]="['active']"><a [routerLink]="['/refresh']" [queryParams]="{url:'campaigns'}" skipLocationChange="true">My AMP Creative</a></li>

How to reload the current Angular 2 Component

How can I reload the same component again in Angular 2?
Here is my code below:
import { Component, OnInit, ElementRef, Renderer } from '#angular/core';
import { Router, ActivatedRoute, Params } from '#angular/router';
import { productModel } from '../_models/index';
import { categoryListService } from '../_services/index';
#Component({
selector: 'app-product',
templateUrl: 'product.component.html',
styleUrls: ['product.component.css']
})
export class productComponent implements OnInit {
uidproduct: productModel;
param: number;
constructor(
private elementRef: ElementRef,
private route: ActivatedRoute,
private router: Router,
private categoryListService: categoryListService) { }
ngOnInit() {
this.route.params.subscribe(product => {
console.log('logging sub product obj', product);
});
this.uidproduct = JSON.parse(sessionStorage.getItem('product'));
var s = document.createElement("script");
s.type = "text/javascript";
s.src = "http://this/external/script/needs/to/be/loaded/each/time.js";
this.elementRef.nativeElement.appendChild(s);
}
nextproduct(){
let i = this.uidproduct.order;
this.categoryListService.findNextproduct(this.uidproduct);
this.param = ++i;
this.router.navigate([`/product/${this.param}`]);
}
}
nextproduct() is bound to a click event in the template.
The uidproduct is a JSON object that has a number of properties and i'm updating the DOM with {{uidproduct.classname}}
I'm using this in the template like this:
<div id="selected-product" class="{{uidproduct.classname}}">
When I click the <button (click)="nextproduct()"> it will change the class property in the DOM but I need to reload the component for the external script to have effect.
You can use *ngIf to re-render the content of a template:
#Component({
selector: '...',
template: `
<ng-container *ngIf="!rerender">
template content here
</ng-container>`
})
export class MyComponent {
rerender = false;
constructor(private cdRef:ChangeDetectorRef){}
doRerender() {
this.rerender = true;
this.cdRef.detectChanges();
this.rerender = false;
}
}
I don't understand why you need to reload the component. If you're binding to the various fields of uidproduct, then reloading that should refresh the values shown in the component. So reloading the component does nothing but add overhead.
If there is a terrific reason not mentioned here why you think you still need to do this, then here is what you do:
Navigate to another (possibly blank) component.
Navigate directly back.
The problem is that you need to wait for the first navigation to finish before doing the second one.
In your component, import NavigationEnd:
import { Router, NavigationEnd } from '#angular/router';
And then subscribe to it in your constructor:
constructor(private thingService: ThisThingService, private router: Router) {
router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
if (event.url === '/blank') {
this.router.navigate(['product']);
}
}
});
Notice that I wait for NavigationEnd to happen and then check to see I was routing to my blank component. If it is the blank component's path, I navigate back to the product. If you really need to pass that ID, just store it on your object and add it here.
Instead of routing to your product page in nextproduct(), navigate to blank.
this.router.navigate(['blank']);
And that should reload your component perfectly fine.
The problem I intentionally left in for simplicity, is that the subscribe call in the constructor will execute for every reload. So as an exercise to the reader, take it out of the constructor and create a nice service for it, or move it to the constructor of your app component, or maybe to your routing module or wherever makes sense to you.

Angular2 component doesn't detect routing parameter updates (Router 3.0)

I've got a small Plunk I'm using for playing around with the new Router 3.0 alpha currently available in Angular 2. It works well in general, but the issue is that once I click on a link that routes to the 'detail' component with a particular ID, it never changes when I click on a different link with a different ID. The component is never being reinstantiated, so it only ever shows what it was passed the very first time it is loaded.
Here's the component in question:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { ContactsService } from './contacts.service';
#Component({
selector: 'contacts-detail',
template: `
<h2>{{contact.name}}</h2>
`
})
export class ContactsDetailComponent implements OnInit {
constructor(private contactsService: ContactsService, private route: ActivatedRoute) {
}
ngOnInit() {
this.contact = this.contactsService.getContact(this.route.snapshot.params.id);
console.log('Fetching user', this.route.snapshot.params.id);
}
}
Here is the Plunk demonstrating the problem. Click on one author name and then another to see it not change.
In your ContactsDetailComponent, change the OnInit to this:
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
let id = +params['id'];
this.contact = this.contactsService.getContact(id);
});
}
Worked for me in your Plunk.
There appear to be multiple lifeCycle hooks that could possibly be used for this. I managed to get the desired behavior using the DoCheck interface and implementing the associated ngDoCheck() method in the component class, as seen below.
import { Component, DoCheck } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { ContactsService } from './contacts.service';
#Component({
selector: 'contacts-detail',
template: `
<h2>{{contact.name}}</h2>
`
})
export class ContactsDetailComponent implements AfterViewChecked, DoCheck {
constructor(private contactsService: ContactsService, private route: ActivatedRoute) {
}
ngDoCheck() {
this.contact = this.contactsService.getContact(this.route.snapshot.params.id);
}
}
Here's a plunk with the updated code.
I'm not convinced this is the best/correct lifecycle hook to use, though. Perhaps there is some sort of hook available from the Router that would serve this better.
Another way to do this:
ngOnInit() {
this.route.params.forEach((params: Params) => {
let id = +params['id'];
this.contact = this.contactsService.getContact(id);
});
}
Here retrieve the route params from an Observable. The advantage of using an Observable over Snapshot is to reuse the component without instantiating it again. Looks like this is the recommended way of doing this as per Angular 2.0 final documentation.

Categories

Resources