Skip to content

Commit 8464dff

Browse files
committed
Add revamp of refresh-guard for Angular 7.2.15.
1 parent 5991af7 commit 8464dff

28 files changed

Lines changed: 7844 additions & 0 deletions

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ with.
1010

1111
## My JavaScript Demos - I Love JavaScript!
1212

13+
* [Prevent Routing To Secondary View If Page Refresh In Angular 7.2.15](https://bennadel.github.io/JavaScript-Demos/demos/prevent-secondary-view-on-refresh-angular7/)
1314
* [Performing A SublimeText-Inspired Fuzzy Search For String Matching In Angular 7.2.15](https://bennadel.github.io/JavaScript-Demos/demos/fuzzy-match-angular7/)
1415
* [Using replaceUrl To Persist Search Filters In The URL Without Messing Up The Browser History In Angular 7.2.14](https://bennadel.github.io/JavaScript-Demos/demos/router-filter-replace-state-angular7/)
1516
* [Creating A Proxy For Analytics Libraries In Order To Defer Loading And Parsing Overhead In Angular 7.2.13](https://bennadel.github.io/JavaScript-Demos/demos/delayed-script-load-proxy-service-angular7/)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
# Now that we're using Webpack, we can install modules locally and just ignore
3+
# them since the assets are baked into the compiled modules.
4+
node_modules/
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
:host {
3+
display: block ;
4+
font-size: 18px ;
5+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
// Import the core angular services.
3+
import { Component } from "@angular/core";
4+
5+
// ----------------------------------------------------------------------------------- //
6+
// ----------------------------------------------------------------------------------- //
7+
8+
@Component({
9+
selector: "my-app",
10+
styleUrls: [ "./app.component.less" ],
11+
template:
12+
`
13+
<p>
14+
<a [routerLink]="[ '/app', { outlets: { primary: 'main' } } ]">
15+
Open Main View
16+
</a>
17+
&mdash;
18+
<a [routerLink]="[ '/app', { outlets: { primary: null } } ]">
19+
Close Main View
20+
</a>
21+
</p>
22+
23+
<p>
24+
<a [routerLink]="[ '/app', { outlets: { secondary: 'secondary' } } ]">
25+
Open Secondary View
26+
</a>
27+
&mdash;
28+
<a [routerLink]="[ '/app', { outlets: { secondary: null } } ]">
29+
Close Secondary View
30+
</a>
31+
</p>
32+
33+
<router-outlet></router-outlet>
34+
<router-outlet name="secondary"></router-outlet>
35+
`
36+
})
37+
export class AppComponent {
38+
// ...
39+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
2+
// Import the core angular services.
3+
import { BrowserModule } from "@angular/platform-browser";
4+
import { NgModule } from "@angular/core";
5+
import { RouterModule } from "@angular/router";
6+
7+
// Import the application components and services.
8+
import { AppComponent } from "./app.component";
9+
import { DoNotShowSecondaryOnRefreshGuard } from "./do-not-show-secondary-on-refresh.guard";
10+
import { MainViewComponent } from "./main-view.component";
11+
import { SecondaryViewComponent } from "./secondary-view.component";
12+
13+
// ----------------------------------------------------------------------------------- //
14+
// ----------------------------------------------------------------------------------- //
15+
16+
@NgModule({
17+
imports: [
18+
BrowserModule,
19+
RouterModule.forRoot(
20+
[
21+
{
22+
path: "app",
23+
children: [
24+
{
25+
path: "main",
26+
component: MainViewComponent
27+
},
28+
{
29+
path: "secondary",
30+
outlet: "secondary",
31+
component: SecondaryViewComponent,
32+
canActivate: [ DoNotShowSecondaryOnRefreshGuard ]
33+
}
34+
]
35+
}
36+
],
37+
{
38+
// Tell the router to use the hash instead of HTML5 pushstate.
39+
useHash: true,
40+
41+
// Enable the Angular 6+ router features for scrolling and anchors.
42+
scrollPositionRestoration: "enabled",
43+
anchorScrolling: "enabled",
44+
enableTracing: false
45+
}
46+
)
47+
],
48+
providers: [
49+
// CAUTION: We don't need to specify the LocationStrategy because we are setting
50+
// the "useHash" property in the Router module above (which will be setting the
51+
// strategy for us).
52+
// --
53+
// {
54+
// provide: LocationStrategy,
55+
// useClass: HashLocationStrategy
56+
// }
57+
],
58+
declarations: [
59+
AppComponent,
60+
MainViewComponent,
61+
SecondaryViewComponent
62+
],
63+
bootstrap: [
64+
AppComponent
65+
]
66+
})
67+
export class AppModule {
68+
// ...
69+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
2+
// Import the core angular services.
3+
import { ActivatedRouteSnapshot } from "@angular/router";
4+
import { CanActivate } from "@angular/router";
5+
import { Injectable } from "@angular/core";
6+
import { PRIMARY_OUTLET } from "@angular/router";
7+
import { Router } from "@angular/router";
8+
import { RouterStateSnapshot } from "@angular/router";
9+
import { UrlTree } from "@angular/router";
10+
11+
// ----------------------------------------------------------------------------------- //
12+
// ----------------------------------------------------------------------------------- //
13+
14+
@Injectable({
15+
providedIn: "root"
16+
})
17+
export class DoNotShowSecondaryOnRefreshGuard implements CanActivate {
18+
19+
private router: Router;
20+
21+
// I initialize the secondary-view route guard.
22+
constructor( router: Router ) {
23+
24+
this.router = router;
25+
26+
}
27+
28+
// ---
29+
// PUBLIC METHODS.
30+
// ---
31+
32+
// I determine if the requested route can be activated (ie, navigated to).
33+
public canActivate(
34+
activatedRouteSnapshot: ActivatedRouteSnapshot,
35+
routerStateSnapshot: RouterStateSnapshot
36+
) : boolean {
37+
38+
console.log( "[GUARD] Page Refresh:", this.isPageRefresh() );
39+
40+
// We don't want to render this secondary view on page-refresh. As such, if this
41+
// is a page-refresh, we'll navigate to the same URL less the secondary outlet.
42+
if ( this.isPageRefresh() ) {
43+
44+
console.warn( "[GUARD] Secondary view not allowed on refresh." );
45+
46+
this.router.navigateByUrl( this.getUrlWithoutSecondary( routerStateSnapshot ) );
47+
return( false );
48+
49+
}
50+
51+
return( true );
52+
53+
}
54+
55+
// ---
56+
// PRIVATE METHODS.
57+
// ---
58+
59+
// I return the requested URL (as defined in the snapshot), less any the "secondary"
60+
// named-outlet segments.
61+
private getUrlWithoutSecondary( routerStateSnapshot: RouterStateSnapshot ) : UrlTree {
62+
63+
var urlTree = this.router.parseUrl( routerStateSnapshot.url );
64+
var segment = urlTree.root;
65+
66+
// Since the "secondary" outlet is known to be directly off the primary view
67+
// (ie, not nested within another named-outlet), we're going to walk down the
68+
// tree of primary outlets and delete any "secondary" children. This should
69+
// leave us with a UrlTree that contains everything that the original URL had,
70+
// less the "secondary" named-outlet.
71+
while ( segment && segment.children ) {
72+
73+
delete( segment.children.secondary );
74+
75+
segment = segment.children[ PRIMARY_OUTLET ];
76+
77+
}
78+
79+
return( urlTree );
80+
81+
}
82+
83+
84+
// I determine if the current route-request is part of a page refresh.
85+
private isPageRefresh() : boolean {
86+
87+
// If the router has yet to establish a single navigation, it means that this
88+
// navigation is the first attempt to reconcile the application state with the
89+
// URL state. Meaning, this is a page refresh.
90+
return( ! this.router.navigated );
91+
92+
}
93+
94+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
:host {
3+
border-left: 7px solid #CCCCCC ;
4+
display: block ;
5+
margin: 16px 0px 16px 0px ;
6+
padding: 15px 0px 15px 20px ;
7+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
// Import the core angular services.
3+
import { Component } from "@angular/core";
4+
5+
// ----------------------------------------------------------------------------------- //
6+
// ----------------------------------------------------------------------------------- //
7+
8+
@Component({
9+
selector: "main-view",
10+
styleUrls: [ "./main-view.component.less" ],
11+
template:
12+
`
13+
This is the main-view.
14+
<a [routerLink]="[{ foo: 'bar' }]">Add optional params</a>
15+
`
16+
})
17+
export class MainViewComponent {
18+
// ...
19+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
6+
<title>
7+
Prevent Routing To Secondary View If Page Refresh In Angular 7.2.15
8+
</title>
9+
</head>
10+
<body>
11+
12+
<h1>
13+
Prevent Routing To Secondary View If Page Refresh In Angular 7.2.15
14+
</h1>
15+
16+
<my-app>
17+
<p>
18+
<em>Loading files...</em>
19+
</p>
20+
21+
<p>
22+
npm Run Scripts:
23+
</p>
24+
25+
<ul>
26+
<li>
27+
<strong>npm run build</strong> &mdash; Compiles the .ts file into bundles.
28+
</li>
29+
<li>
30+
<strong>npm run watch</strong> &mdash; Compiles the .ts file into bundles and then watches files for changes.
31+
</li>
32+
</ul>
33+
</my-app>
34+
35+
</body>
36+
</html>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
// Import these libraries for their side-effects.
3+
import "core-js/es";
4+
import "zone.js/dist/zone.js";

0 commit comments

Comments
 (0)