Skip to content

Commit db18fb3

Browse files
committed
Components converted to standalone
1 parent f295c41 commit db18fb3

16 files changed

+82
-154
lines changed

angular.json

+6-13
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,20 @@
55
"projects": {
66
"angular-form-input-cross-validator": {
77
"projectType": "application",
8-
"schematics": {
9-
"@schematics/angular:application": {
10-
"strict": true
11-
}
12-
},
8+
"schematics": {},
139
"root": "",
1410
"sourceRoot": "src",
1511
"prefix": "app",
1612
"architect": {
1713
"build": {
18-
"builder": "@angular-devkit/build-angular:browser",
14+
"builder": "@angular-devkit/build-angular:application",
1915
"options": {
2016
"outputPath": "dist/angular-form-input-cross-validator",
2117
"index": "src/index.html",
22-
"main": "src/main.ts",
23-
"polyfills": "src/polyfills.ts",
18+
"browser": "src/main.ts",
19+
"polyfills": [
20+
"zone.js"
21+
],
2422
"tsConfig": "tsconfig.app.json",
2523
"assets": [
2624
"src/favicon.ico",
@@ -30,9 +28,7 @@
3028
"src/styles.css"
3129
],
3230
"scripts": [],
33-
"vendorChunk": true,
3431
"extractLicenses": false,
35-
"buildOptimizer": false,
3632
"sourceMap": true,
3733
"optimization": false,
3834
"namedChunks": true
@@ -49,9 +45,6 @@
4945
"outputHashing": "all",
5046
"sourceMap": false,
5147
"namedChunks": false,
52-
"extractLicenses": true,
53-
"vendorChunk": false,
54-
"buildOptimizer": true,
5548
"budgets": [
5649
{
5750
"type": "initial",

src/app/app.component.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<h1 class="content" data-cy="pageHeading">{{title}}</h1>
1+
<h1 class="content" data-cy="pageHeading">{{pageHeading}}</h1>
22

33
<nav>
44
<a id="reactiveForm" routerLink="/reactive-form" routerLinkActive="active">Reactive form</a>

src/app/app.component.spec.ts

+39-56
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,55 @@
1-
import { TestBed, ComponentFixture, waitForAsync } from '@angular/core/testing';
2-
import { ActivatedRoute } from '@angular/router';
3-
import { RouterTestingModule } from '@angular/router/testing';
4-
import { RouterLinkStubDirective } from '../tests/router-link-directive-stub';
1+
import { TestBed, waitForAsync, fakeAsync, tick } from '@angular/core/testing';
2+
import { Router, RouterLink, provideRouter } from '@angular/router';
3+
import { RouterTestingHarness } from '@angular/router/testing';
54
import { AppComponent } from './app.component';
6-
import { NO_ERRORS_SCHEMA } from '@angular/core';
75
import { By } from '@angular/platform-browser';
8-
6+
import { appConfig } from './app.config';
97

108
describe('AppComponent', () => {
11-
let route: ActivatedRoute;
129
let appComponent: AppComponent;
13-
let app: ComponentFixture<AppComponent>;
14-
let routerLinks: RouterLinkStubDirective[];
10+
let harness: RouterTestingHarness;
1511

1612
beforeEach(waitForAsync(() => {
17-
TestBed.configureTestingModule({
18-
imports: [
19-
RouterTestingModule
20-
],
21-
declarations: [
22-
AppComponent,
23-
RouterLinkStubDirective
24-
],
25-
schemas: [NO_ERRORS_SCHEMA],
26-
providers:
27-
[
28-
{
29-
provide: ActivatedRoute,
30-
useValue: {
31-
snapshot: { data: { title: 'Angular - Reactive form input value cross-validation' } }
32-
}
33-
}
34-
]
35-
}).compileComponents();
36-
37-
route = TestBed.inject(ActivatedRoute);
38-
13+
TestBed.configureTestingModule(Object.assign({}, appConfig, {
14+
imports: [AppComponent],
15+
providers: [
16+
provideRouter([{ path: '**', component: AppComponent }])
17+
]
18+
}))
19+
.compileComponents()
20+
.then(async () => {
21+
harness = await RouterTestingHarness.create();
22+
appComponent = await harness.navigateByUrl('/', AppComponent);
23+
harness.detectChanges();
24+
});
3925
}));
4026

41-
beforeEach(() => {
42-
app = TestBed.createComponent(AppComponent);
43-
appComponent = app.componentInstance;
44-
appComponent.title = route.snapshot.data['title'];
45-
app.detectChanges();
46-
47-
// Find DebugElements with an attached RouterLinkStubDirective
48-
const linkElms = app.debugElement.queryAll(By.directive(RouterLinkStubDirective));
49-
50-
// Using each DebugElement's injector
51-
routerLinks = linkElms.map(el => el.injector.get(RouterLinkStubDirective));
27+
it('should create an instance of the app', () => {
28+
expect(appComponent).toBeInstanceOf(AppComponent);
5229
});
5330

54-
it('Should create the app', () => {
55-
expect(appComponent).toBeTruthy();
31+
it('should get RouterLinks from template', () => {
32+
const linkItems = harness.routeNativeElement?.querySelectorAll('a') as unknown as HTMLAnchorElement[];
33+
expect(linkItems.length).toBe(2);
34+
expect(linkItems[0].getAttribute('routerLink')).toBe('/reactive-form');
35+
expect(linkItems[1].getAttribute('routerLink')).toBe('/template-driven-form');
5636
});
5737

58-
it('can get RouterLinks from template', () => {
59-
expect(routerLinks.length).toBe(2);
60-
expect(routerLinks[0].linkParams).toBe('/reactive-form');
61-
expect(routerLinks[1].linkParams).toBe('/template-driven-form');
62-
});
38+
it('should activate RouterLinks', fakeAsync(() => {
39+
const linkElms = harness.routeDebugElement?.queryAll(By.directive(RouterLink));
40+
linkElms![0].triggerEventHandler('click', { button: 0, });
41+
tick();
42+
expect(TestBed.inject(Router).url).toEqual('/reactive-form');
6343

64-
it("Should have 'route.snapshot.data.title' as title", () => {
65-
expect(appComponent.title).toEqual('Angular - Reactive form input value cross-validation');
66-
});
44+
linkElms![1].triggerEventHandler('click', { button: 0, });
45+
tick();
46+
expect(TestBed.inject(Router).url).toEqual('/template-driven-form');
47+
}));
6748

68-
it('Should render title', () => {
69-
const compiled = app.nativeElement;
70-
expect(compiled.querySelector('h1').textContent).toContain('Angular - Reactive form input value cross-validation');
49+
it('should render correct page heading', () => {
50+
appComponent.pageHeading = 'Angular - Reactive form input value cross-validation';
51+
harness.detectChanges();
52+
const heading = harness.routeNativeElement?.querySelector('h1');
53+
expect(heading?.textContent).toContain('Angular - Reactive form input value cross-validation');
7154
});
72-
});
55+
});

src/app/app.component.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { Component, OnInit, OnDestroy } from '@angular/core';
2-
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
2+
import { Router, NavigationEnd, ActivatedRoute, RouterOutlet, RouterLink, RouterLinkActive } from '@angular/router';
33
import { Subscription } from 'rxjs';
44
import { filter } from 'rxjs/operators';
55

66
@Component({
77
selector: 'app-root',
8+
standalone: true,
9+
imports: [RouterOutlet, RouterLink, RouterLinkActive],
810
templateUrl: './app.component.html',
911
styleUrls: ['./app.component.css']
1012
})
@@ -15,7 +17,7 @@ export class AppComponent implements OnInit, OnDestroy {
1517

1618
}
1719

18-
title = 'Angular - Form input value cross validator';
20+
pageHeading = 'Angular - Form input value cross validator';
1921
routeSubscription!: Subscription;
2022

2123
setTitle() {
@@ -27,7 +29,7 @@ export class AppComponent implements OnInit, OnDestroy {
2729
while (route && route.firstChild) {
2830
route = route.firstChild;
2931
}
30-
route?.snapshot.data['title'] ? this.title = route.snapshot.data['title'] : '';
32+
route?.snapshot.data['title'] ? this.pageHeading = route.snapshot.data['title'] : '';
3133
});
3234
}
3335

src/app/app.config.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { ApplicationConfig } from '@angular/core';
2+
import { provideRouter } from '@angular/router';
3+
import { routes } from './app.routes';
4+
5+
export const appConfig: ApplicationConfig = {
6+
providers: [
7+
provideRouter(routes)
8+
]
9+
};

src/app/app.module.ts

-27
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import { NgModule } from '@angular/core';
2-
import { Routes, RouterModule } from '@angular/router';
1+
import { Routes } from '@angular/router';
32
import { ReactiveFormComponent } from './reactive-form/reactive-form.component';
43
import { TemplateDrivenFormComponent } from './template-driven-form/template-driven-form.component';
54

6-
const routes: Routes = [
5+
export const routes: Routes = [
76
{
87
path: 'reactive-form', component: ReactiveFormComponent,
98
data: { title: 'Angular - Reactive form input value cross-validation' }
@@ -14,10 +13,4 @@ const routes: Routes = [
1413
},
1514
{ path: '**', redirectTo: '/reactive-form', pathMatch: 'full' },
1615
{ path: '', redirectTo: '/reactive-form', pathMatch: 'full' },
17-
];
18-
19-
@NgModule({
20-
imports: [RouterModule.forRoot(routes, { initialNavigation: 'enabledBlocking' })],
21-
exports: [RouterModule]
22-
})
23-
export class AppRoutingModule { }
16+
];

src/app/compare-input-validator.directive.ts

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export function compareInputValidator(crossFields: Array<string>): ValidatorFn {
1212
}
1313
@Directive({
1414
selector: '[appCompareInputValidate]',
15+
standalone: true,
1516
providers: [{ provide: NG_VALIDATORS, useExisting: CompareInputValidatorDirective, multi: true }]
1617
})
1718
export class CompareInputValidatorDirective {

src/app/package.json

-9
This file was deleted.

src/app/reactive-form/reactive-form.component.spec.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,14 @@ import { FormsModule, ReactiveFormsModule, FormBuilder } from '@angular/forms';
33
import { ReactiveFormComponent } from './reactive-form.component';
44
import { UserR, mockValidRuser, mockInvalidRuser } from '../user';
55

6-
import { NO_ERRORS_SCHEMA } from '@angular/core';
7-
86
describe('ReactiveForm', () => {
97
let component: ReactiveFormComponent;
108
let app: ComponentFixture<ReactiveFormComponent>;
119

1210
beforeEach(waitForAsync(() => {
1311
TestBed.configureTestingModule({
14-
declarations: [ReactiveFormComponent],
1512
providers: [FormBuilder],
16-
imports: [FormsModule, ReactiveFormsModule],
17-
schemas: [NO_ERRORS_SCHEMA]
13+
imports: [FormsModule, ReactiveFormsModule, ReactiveFormComponent]
1814
})
1915
.compileComponents();
2016

src/app/reactive-form/reactive-form.component.ts

+4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import { Component } from '@angular/core';
22
import { FormBuilder, Validators } from '@angular/forms';
33
import { compareInputValidator } from '../compare-input-validator.directive';
4+
import { CommonModule } from '@angular/common';
5+
import { ReactiveFormsModule } from '@angular/forms';
46

57
@Component({
68
selector: 'app-reactive-form',
9+
standalone: true,
10+
imports: [CommonModule, ReactiveFormsModule],
711
templateUrl: './reactive-form.component.html',
812
styleUrls: ['./reactive-form.component.css']
913
})

src/app/template-driven-form/template-driven-form.component.spec.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,13 @@ import { TemplateDrivenFormComponent } from './template-driven-form.component';
44

55
import { FormsModule } from '@angular/forms';
66

7-
import { NO_ERRORS_SCHEMA } from '@angular/core';
8-
97
describe('TemplateDrivenFormComponent', () => {
108
let component: TemplateDrivenFormComponent;
119
let app: ComponentFixture<TemplateDrivenFormComponent>;
1210

1311
beforeEach(waitForAsync(() => {
1412
TestBed.configureTestingModule({
15-
imports: [FormsModule],
16-
declarations: [TemplateDrivenFormComponent],
17-
schemas: [NO_ERRORS_SCHEMA]
13+
imports: [FormsModule, TemplateDrivenFormComponent]
1814
})
1915
.compileComponents();
2016
}));

src/app/template-driven-form/template-driven-form.component.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import { Component } from '@angular/core';
2-
import { NgForm } from '@angular/forms';
2+
import { NgForm, FormsModule } from '@angular/forms';
33
import { User } from '../user';
4+
import { CommonModule } from '@angular/common';
5+
import { CompareInputValidatorDirective } from '../compare-input-validator.directive';
46

57
@Component({
68
selector: 'app-template-driven-form',
9+
standalone: true,
10+
imports: [CommonModule, FormsModule, CompareInputValidatorDirective],
711
templateUrl: './template-driven-form.component.html',
812
styleUrls: ['./template-driven-form.component.css']
913
})

src/main.ts

+5-11
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
1-
import { enableProdMode } from '@angular/core';
2-
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
1+
import { bootstrapApplication } from '@angular/platform-browser';
2+
import { appConfig } from './app/app.config';
3+
import { AppComponent } from './app/app.component';
34

4-
import { AppModule } from './app/app.module';
5-
import { environment } from './environments/environment';
6-
7-
if (environment.production) {
8-
enableProdMode();
9-
}
10-
11-
platformBrowserDynamic().bootstrapModule(AppModule)
12-
.catch(err => console.error(err));
5+
bootstrapApplication(AppComponent, appConfig)
6+
.catch((err) => console.error(err));

src/styles.css

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ app-root {
1212

1313
.main-container {
1414
background-color: #f7f7f7;
15-
width: calc(100%-48px);
15+
width: calc(100% - 48px);
1616
padding: 24px;
1717
color: #111;
1818
font-weight: 400;
@@ -92,7 +92,7 @@ input {
9292
}
9393

9494
.alert {
95-
width: calc(100%-20px);
95+
width: calc(100% - 20px);
9696
padding: 0 10px;
9797
margin-bottom: 20px;
9898
border: 1px solid transparent;

src/tests/router-link-directive-stub.ts

-11
This file was deleted.

0 commit comments

Comments
 (0)