Skip to content

Commit 570635b

Browse files
committed
Part 4a: Configure AngularJs Otherwise Handler
1 parent cf0814b commit 570635b

File tree

7 files changed

+209
-3
lines changed

7 files changed

+209
-3
lines changed

.editorconfig

-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,3 @@ trim_trailing_whitespace = true
1010

1111
[*.md]
1212
max_line_length = off
13-
trim_trailing_whitespace = false

guide/part-4.md

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# 4. Hacks To Get Hybrid Routing Working
2+
3+
## Downgrade the Router service to use in AngularJs
4+
5+
The first step is to downgrade the Router service so we can use it in AngularJs. We can add other downgraded services here too later.
6+
7+
[services.downgrade.ts](../src/app/legacy/downgrade/services.downgrade.ts)
8+
9+
```ts
10+
legacyApp.factory('router', downgradeInjectable(Router));
11+
```
12+
13+
And update the [legacy/downgrade/index.ts](../src/app/legacy/downgrade/index.ts) file.
14+
15+
```ts
16+
import './services.downgrade.ts';
17+
```
18+
19+
## Create AngularJs Legacy Route Helper
20+
21+
Create a service that will get the current path and try and route to that path using the Angular router service we just downgraded.
22+
23+
[legacy.route-helper.ts](../src/app/legacy/routing/legacy.route-helper.ts)
24+
25+
```ts
26+
export class LegacyRouteHelper {
27+
static $inject = [
28+
'$location',
29+
'router',
30+
];
31+
constructor(
32+
private $location,
33+
private router: Router,
34+
) {}
35+
36+
handleNgRoute(): void {
37+
const path = this.$location.path();
38+
path && this.router.navigateByUrl(path);
39+
}
40+
}
41+
42+
legacyApp.service('legacyRouteHelper', LegacyRouteHelper);
43+
```
44+
45+
And update the [legacy/routing/index.ts](../src/app/legacy/routing/index.ts) file.
46+
47+
```ts
48+
import './legacy.route-helper.ts';
49+
```
50+
51+
## Solution 1. Configure AngularJs Otherwise Handler
52+
53+
Now we configure a handler in AngularJs for any non-AngularJs routes to try and route to them using the helper we just created.
54+
55+
[legacy.routes.ts](../src/app/legacy/routing/legacy.routes.ts)
56+
57+
```ts
58+
legacyRoutes.$inject = ['$stateProvider', '$urlRouterProvider'];
59+
function legacyRoutes($stateProvider, $urlRouterProvider) {
60+
// ...
61+
62+
$urlRouterProvider.otherwise(($injector) => {
63+
const legacyRouteHelper: LegacyRouteHelper = $injector.get('legacyRouteHelper');
64+
legacyRouteHelper.handleNgRoute();
65+
});
66+
}
67+
```
68+
69+
You should *now* be able to navigate to [/hello-ng](http://localhost:4200/hello-ng) and it should work!
70+
71+
## Clean Things Up
72+
73+
Let's remove our headings and add a few links to be able to test some other scenarios we need to solve for.
74+
75+
## Problem 2: Angular RouterOutlet Doesn't Clear
76+
77+
<!-- ... -->
78+
79+
## 4.x. Alternatives
80+
81+
There are alternative ways to solve the hybrid routing issue:
82+
83+
### 4.x.1. Create Catch All Routes
84+
85+
Create a catch all (or "sink") route for both the AngularJs UI Router and Angular Router that will have an empty template. This will mean when there's a valid Angular route the Angular router will handle it and the AngularJs router will show an empty template. Alternatively, if there's a valid AngularJs route the AngularJs router will handle it and the Angular router will show an empty template.
86+
87+
This would look like this in Angular:
88+
89+
```ts
90+
@Component({selector: 'empty', template: ''})
91+
class EmptyComponent {}
92+
93+
@NgModule({
94+
// ...other imports
95+
imports: [
96+
RouterModule.forRoot([
97+
// ...other routes
98+
99+
// The catch all route has to come LAST
100+
{ path: '**', component: EmptyComponent }
101+
])
102+
]
103+
})
104+
```
105+
106+
And in AngularJs:
107+
108+
```ts
109+
$stateProvider
110+
// ...other states
111+
112+
// The catch all route has to come LAST
113+
.state('catchAll', {
114+
url: '*path',
115+
template: '',
116+
controller: () => { /*...Code to route using Angular router*/ }
117+
});
118+
```
119+
120+
#### 4.x.1 Pros
121+
122+
- Easy to set up
123+
- Easy to understand
124+
125+
#### 4.x.1 Cons
126+
127+
- You cannot catch invalid routes to redirect the user
128+
129+
### 4.x.2. Create Catch All AngularJs Route and Angular UrlHandlingStrategy
130+
131+
Do the same catch all route in AngularJs as above, but use a UrlHandlingStrategy in Angular
132+
133+
```ts
134+
class AppUrlHandlingStrategy implements UrlHandlingStrategy {
135+
shouldProcessUrl(url) {
136+
// This is a simple example where you've prefixed angular routes with `/a/`
137+
// You could also use the AppUrlHandlingStragegy we created earlier
138+
return url.toString().startsWith("/a/");
139+
}
140+
extract(url) { return url; }
141+
merge(url, whole) { return url; }
142+
}
143+
144+
@NgModule({
145+
imports: [
146+
RouterModule.forRoot([
147+
// ...routes
148+
])
149+
],
150+
providers: [
151+
{ provide: UrlHandlingStrategy, useClass: AppUrlHandlingStrategy }
152+
],
153+
})
154+
```
155+
156+
#### 4.x.2 Pros
157+
158+
- Not too hard to set up
159+
- Not too hard to understand
160+
- More configurable than just using a catch all route
161+
162+
#### 4.x.2 Cons
163+
164+
- You cannot catch invalid routes to redirect the user (as before)
165+
166+
## Next step
167+
168+
Conclusion???
169+
170+
## Further Reading
171+
172+
- <https://blog.nrwl.io/upgrading-angular-applications-managing-routers-and-url-ca5588290aaa>

src/app/legacy/downgrade/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
import './app.component.downgrade';
2+
import './services.downgrade';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { downgradeInjectable } from '@angular/upgrade/static';
2+
import { Router } from '@angular/router';
3+
4+
import { legacyApp } from '../legacy.app.module';
5+
6+
legacyApp.factory('router', downgradeInjectable(Router));

src/app/legacy/routing/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
import './legacy.routes';
2+
import './legacy.route-helper';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Router } from '@angular/router';
2+
3+
import { legacyApp } from '../legacy.app.module';
4+
5+
export class LegacyRouteHelper {
6+
static $inject = [
7+
'$location',
8+
'router',
9+
];
10+
constructor(
11+
private $location,
12+
private router: Router,
13+
) {}
14+
15+
handleNgRoute(): void {
16+
const path = this.$location.path();
17+
path && this.router.navigateByUrl(path);
18+
}
19+
}
20+
21+
legacyApp.service('legacyRouteHelper', LegacyRouteHelper);

src/app/legacy/routing/legacy.routes.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import { LegacyRouteHelper } from './legacy.route-helper';
12
import { legacyApp } from '../legacy.app.module';
23

34
legacyApp.config(legacyRoutes);
45

5-
legacyRoutes.$inject = ['$stateProvider'];
6-
function legacyRoutes($stateProvider) {
6+
legacyRoutes.$inject = ['$stateProvider', '$urlRouterProvider'];
7+
function legacyRoutes($stateProvider, $urlRouterProvider) {
78

89
$stateProvider
910
.state('helloAjs', {
@@ -15,4 +16,9 @@ function legacyRoutes($stateProvider) {
1516
`,
1617
});
1718

19+
$urlRouterProvider.otherwise(($injector) => {
20+
const legacyRouteHelper: LegacyRouteHelper = $injector.get('legacyRouteHelper');
21+
legacyRouteHelper.handleNgRoute();
22+
});
23+
1824
}

0 commit comments

Comments
 (0)