Skip to content

Commit bbdbb61

Browse files
refactor: update directives/components to use standalone APIs (#92)
1 parent b1bff03 commit bbdbb61

17 files changed

+119
-133
lines changed

LICENSE.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2020-2021 Brandon Roberts
3+
Copyright (c) 2020-2022 Brandon Roberts
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ import { ComponentRouterModule } from '@angular-component/router';
6464
export class FeatureModule {}
6565
```
6666

67+
## Usage with Standalone Features (v14+)
68+
6769
After your components are registered, use the `Router` and `Route` components to register some routes.
6870

6971
```html

angular.json

+11-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@
2525
"scripts": []
2626
},
2727
"configurations": {
28+
"development": {
29+
"vendorChunk": true,
30+
"extractLicenses": false,
31+
"buildOptimizer": false,
32+
"sourceMap": true,
33+
"optimization": false,
34+
"namedChunks": true
35+
},
2836
"production": {
2937
"fileReplacements": [
3038
{
@@ -53,12 +61,13 @@
5361
]
5462
}
5563
},
56-
"outputs": ["{options.outputPath}"]
64+
"outputs": ["{options.outputPath}"],
65+
"defaultConfiguration": "development"
5766
},
5867
"serve": {
5968
"builder": "@angular-devkit/build-angular:dev-server",
6069
"options": {
61-
"browserTarget": "example-app:build"
70+
"browserTarget": "example-app:build:development"
6271
},
6372
"configurations": {
6473
"production": {

apps/example-app/src/app/app.module.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { CommonModule } from '@angular/common';
33
import { HttpClientModule } from '@angular/common/http';
44
import { BrowserModule } from '@angular/platform-browser';
55
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
6-
import { ComponentRouterModule } from '@angular-component/router';
6+
import { provideComponentRouter } from '@angular-component/router';
77

88
import { StoreModule } from '@ngrx/store';
99
import { EffectsModule } from '@ngrx/effects';
@@ -21,7 +21,6 @@ import { AppComponent } from '@example-app/core/containers';
2121
BrowserModule,
2222
BrowserAnimationsModule,
2323
HttpClientModule,
24-
ComponentRouterModule.forRoot(),
2524

2625
/**
2726
* StoreModule.forRoot is imported once in the root module, accepting a reducer
@@ -74,5 +73,6 @@ import { AppComponent } from '@example-app/core/containers';
7473
CoreModule,
7574
],
7675
bootstrap: [AppComponent],
76+
providers: [provideComponentRouter()],
7777
})
7878
export class AppModule {}

libs/router/LICENSE.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2020-2021 Brandon Roberts
3+
Copyright (c) 2020-2022 Brandon Roberts
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

libs/router/package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
},
2323
"homepage": "https://github.com/angular-component/router#readme",
2424
"peerDependencies": {
25-
"@angular/common": ">=9.0.0",
26-
"@angular/core": ">=9.0.0",
27-
"rxjs": ">=7.4.0"
25+
"@angular/common": ">=14.0.0-rc.0",
26+
"@angular/core": ">=14.0.0-rc.0",
27+
"rxjs": ">=7.5.0"
2828
},
2929
"sideEffects": false
3030
}

libs/router/src/lib/link-active.directive.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const LINK_ACTIVE_OPTIONS: LinkActiveOptions = {
3535
* </li>
3636
* </ol>
3737
*/
38-
@Directive({ selector: '[linkActive]' })
38+
@Directive({ selector: '[linkActive]', standalone: true })
3939
export class LinkActive implements AfterContentInit, OnDestroy, OnChanges {
4040
@ContentChildren(LinkTo, { descendants: true })
4141
public links: QueryList<LinkTo>;

libs/router/src/lib/link-to.directive.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const DEFAULT_TARGET = '_self';
2020
* <a linkTo="/home/page" [queryParams]="{ id: 123 }">Home Page</a>
2121
* <a [linkTo]="'/pages' + page.id">Page 1</a>
2222
*/
23-
@Directive({ selector: 'a[linkTo]' })
23+
@Directive({ selector: 'a[linkTo]', standalone: true })
2424
export class LinkTo {
2525
@Input() target = DEFAULT_TARGET;
2626
@HostBinding('href') linkHref?: string | null;

libs/router/src/lib/route-component.directive.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Directive, Input } from '@angular/core';
22

33
@Directive({
44
selector: '[routeComponent]',
5+
standalone: true,
56
})
67
export class RouteComponentTemplate {
78
@Input() routeComponent: any;

libs/router/src/lib/route.component.ts

+31-39
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1+
import { CommonModule } from '@angular/common';
12
import {
23
Component,
34
OnInit,
45
Input,
56
Type,
67
ViewContainerRef,
7-
ComponentFactoryResolver,
88
ContentChild,
99
TemplateRef,
1010
ChangeDetectionStrategy,
1111
Self,
12-
NgModuleFactory,
13-
Compiler,
1412
OnDestroy,
13+
NgModuleRef,
14+
createNgModuleRef,
1515
} from '@angular/core';
1616

1717
import { Subject, BehaviorSubject, of, from } from 'rxjs';
@@ -24,7 +24,7 @@ import {
2424
map,
2525
} from 'rxjs/operators';
2626

27-
import { Load, Route, RouteOptions } from './route';
27+
import { Load, ModuleWithRoute, Route, RouteOptions } from './route';
2828
import { Params, RouteParams, RoutePath } from './route-params.service';
2929
import { RouterComponent } from './router.component';
3030
import { Router } from './router.service';
@@ -46,6 +46,8 @@ interface State {
4646
@Component({
4747
// tslint:disable-next-line:component-selector
4848
selector: 'route',
49+
standalone: true,
50+
imports: [CommonModule],
4951
template: `
5052
<ng-container
5153
*ngIf="(shouldRender$ | async) && template"
@@ -110,9 +112,7 @@ export class RouteComponent implements OnInit, OnDestroy {
110112
constructor(
111113
private router: Router,
112114
private routerComponent: RouterComponent,
113-
private resolver: ComponentFactoryResolver,
114-
private viewContainerRef: ViewContainerRef,
115-
private compiler: Compiler
115+
private viewContainerRef: ViewContainerRef
116116
) {}
117117

118118
ngOnInit(): void {
@@ -176,32 +176,26 @@ export class RouteComponent implements OnInit, OnDestroy {
176176
private loadAndRender(route: Route) {
177177
if (route.load) {
178178
return from(
179-
route.load().then((componentOrModule) => {
180-
if (componentOrModule instanceof NgModuleFactory) {
181-
const moduleRef = componentOrModule.create(
182-
this.viewContainerRef.injector
183-
);
184-
const component = moduleRef.instance.routeComponent;
185-
186-
this.renderComponent(component);
187-
} else if (componentOrModule.ɵmod) {
188-
return this.compiler
189-
.compileModuleAsync(componentOrModule as Type<any>)
190-
.then((moduleFactory) => {
191-
const moduleRef = moduleFactory.create(
192-
this.viewContainerRef.injector
193-
);
194-
const component = moduleRef.instance.routeComponent;
195-
this.renderComponent(component);
196-
197-
return true;
198-
});
199-
} else {
200-
this.renderComponent(componentOrModule);
201-
}
179+
route
180+
.load()
181+
.then(
182+
(componentOrModule: NgModuleRef<ModuleWithRoute> | Type<any>) => {
183+
let component: Type<any>;
184+
185+
if ((componentOrModule as any).ɵmod) {
186+
const moduleRef: NgModuleRef<ModuleWithRoute> =
187+
createNgModuleRef(
188+
componentOrModule as Type<any>,
189+
this.viewContainerRef.injector
190+
);
191+
component = moduleRef.instance.routeComponent;
192+
} else {
193+
component = componentOrModule as Type<any>;
194+
}
202195

203-
return true;
204-
})
196+
this.renderComponent(component);
197+
}
198+
)
205199
);
206200
} else {
207201
this.showTemplate();
@@ -210,14 +204,12 @@ export class RouteComponent implements OnInit, OnDestroy {
210204
}
211205

212206
private renderComponent(component: Type<any>) {
213-
const componentFactory = this.resolver.resolveComponentFactory(component);
214-
215207
this.showTemplate();
216-
this.viewContainerRef.createComponent(
217-
componentFactory,
218-
this.viewContainerRef.length,
219-
this.viewContainerRef.injector
220-
);
208+
209+
this.viewContainerRef.createComponent(component, {
210+
index: this.viewContainerRef.length,
211+
injector: this.viewContainerRef.injector,
212+
});
221213
}
222214

223215
private clearComponent() {

libs/router/src/lib/route.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { Type, NgModuleFactory } from '@angular/core';
1+
import { Type, NgModule } from '@angular/core';
22

33
import { Params } from './route-params.service';
44

5-
export type Load = () => Promise<NgModuleFactory<any> | Type<any> | any>;
5+
export type Load = () => Promise<NgModule | Type<any> | any>;
66

77
export interface Route {
88
path: string;

libs/router/src/lib/router.component.ts

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ interface State {
2727
@Component({
2828
// tslint:disable-next-line:component-selector
2929
selector: 'router',
30+
standalone: true,
3031
template: '<ng-content></ng-content>',
3132
})
3233
export class RouterComponent implements OnInit, OnDestroy {

libs/router/src/lib/router.module.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,23 @@ export function getQueryParams(router: Router) {
2626
return router.queryParams$;
2727
}
2828

29+
export function provideComponentRouter() {
30+
return [
31+
UrlParser,
32+
{ provide: LocationStrategy, useClass: PathLocationStrategy },
33+
{ provide: QueryParams, deps: [Router], useFactory: getQueryParams },
34+
];
35+
}
36+
2937
@NgModule({
30-
imports: [CommonModule],
31-
declarations: [components],
38+
imports: [CommonModule, components],
3239
exports: [components],
3340
})
3441
export class ComponentRouterModule {
3542
static forRoot(): ModuleWithProviders<ComponentRouterModule> {
3643
return {
3744
ngModule: ComponentRouterModule,
38-
providers: [
39-
UrlParser,
40-
{ provide: LocationStrategy, useClass: PathLocationStrategy },
41-
{ provide: QueryParams, deps: [Router], useFactory: getQueryParams },
42-
],
45+
providers: [provideComponentRouter()],
4346
};
4447
}
4548
}

libs/router/src/lib/router.service.spec.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Location, PlatformLocation } from '@angular/common';
2+
import { Injector } from '@angular/core';
23

34
import { Router } from './router.service';
45
import { UrlParser } from './url-parser';
@@ -28,7 +29,16 @@ describe('Router', () => {
2829

2930
urlParser = new UrlParser();
3031

31-
router = new Router(location, platformLocation, urlParser);
32+
const injector = Injector.create({
33+
providers: [
34+
{ provide: Router, deps: [] },
35+
{ provide: Location, useValue: location },
36+
{ provide: PlatformLocation, useValue: platformLocation },
37+
{ provide: UrlParser, useValue: urlParser },
38+
],
39+
});
40+
41+
router = injector.get(Router);
3242
});
3343

3444
describe('go', () => {

libs/router/src/lib/router.service.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Injectable } from '@angular/core';
1+
import { inject, Injectable } from '@angular/core';
22
import { PlatformLocation, Location } from '@angular/common';
33

44
import { BehaviorSubject } from 'rxjs';
@@ -17,6 +17,10 @@ interface State {
1717
providedIn: 'root',
1818
})
1919
export class Router {
20+
private location = inject(Location);
21+
private platformLocation = inject(PlatformLocation);
22+
private urlParser = inject(UrlParser);
23+
2024
private readonly state$ = new BehaviorSubject<State>({
2125
url: this.location.path(),
2226
queryParams: {},
@@ -36,11 +40,7 @@ export class Router {
3640
distinctUntilChanged(compareParams)
3741
);
3842

39-
constructor(
40-
private location: Location,
41-
private platformLocation: PlatformLocation,
42-
private urlParser: UrlParser
43-
) {
43+
constructor() {
4444
this.location.subscribe(() => {
4545
this.nextState(this.getLocation());
4646
});

package.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@
4040
"@angular/platform-browser": "14.0.0-rc.2",
4141
"@angular/platform-browser-dynamic": "14.0.0-rc.2",
4242
"@angular/router": "14.0.0-rc.2",
43-
"@ngrx/effects": "13.0.2",
44-
"@ngrx/entity": "13.0.2",
45-
"@ngrx/router-store": "13.0.2",
46-
"@ngrx/store": "13.0.2",
43+
"@ngrx/effects": "14.0.0-beta.0",
44+
"@ngrx/entity": "14.0.0-beta.0",
45+
"@ngrx/router-store": "14.0.0-beta.0",
46+
"@ngrx/store": "14.0.0-beta.0",
4747
"@nrwl/angular": "14.1.9",
4848
"angular-in-memory-web-api": "^0.13.0",
49-
"rxjs": "^7.4.0",
49+
"rxjs": "^7.5.0",
5050
"tslib": "^2.4.0",
5151
"zone.js": "0.11.4"
5252
},
@@ -55,7 +55,7 @@
5555
"@angular/cli": "14.0.0-rc.2",
5656
"@angular/compiler-cli": "14.0.0-rc.2",
5757
"@angular/language-service": "14.0.0-rc.2",
58-
"@ngrx/store-devtools": "13.0.2",
58+
"@ngrx/store-devtools": "14.0.0-beta.0",
5959
"@nrwl/cli": "14.1.9",
6060
"@nrwl/cypress": "14.1.9",
6161
"@nrwl/jest": "14.1.9",

0 commit comments

Comments
 (0)