Skip to content

Commit 14ae930

Browse files
feat: Update to Angular 14 (#44)
- Expose additional components due to Typescript requirement. - Minor doco updates. - Build pipeline bump to Node16 (from 14) Co-authored-by: David Walschots <davidwalschots@users.noreply.github.com>
1 parent 44abdf6 commit 14ae930

26 files changed

+11507
-9909
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,4 @@ testem.log
4747
Thumbs.db
4848

4949
TESTS-*.xml
50+
/.angular/cache/*

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Changelog
2+
3+
## 8.0.0
4+
5+
* add support for Angular 14

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ Note that `formSubmitted` can be undefined when it's not known if the form is su
140140

141141
Angular provides a limited set of validator functions. To declare your own validator functions _and_ combine it with this library use the `ValidatorDeclaration` class. It supports declaring validators with zero, one or two arguments.
142142

143-
**Note** that if your validator doesn't return an object as the inner error result, but e.g. a `boolean` such as in the examples below, then this will be replaced by an object that can hold the validation message. Thus in the first example below `{ 'hasvalue': true }` becomes `{ 'hasvalue': { 'message': 'validation message' } }`.
143+
**Note** that if your validator doesn't return an object as the inner error result, but e.g. a `boolean` such as in the examples below, then this will be replaced by an object that can hold the validation message. Thus, in the first example below `{ 'hasvalue': true }` becomes `{ 'hasvalue': { 'message': 'validation message' } }`.
144144

145145
```ts
146146
const hasValueValidator = ValidatorDeclaration.wrapNoArgumentValidator(control => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"$schema": "./node_modules/ng-packagr/ng-package.schema.json",
3+
"dest": "../dist/angular-reactive-validation",
4+
"lib": {
5+
"entryFile": "src/public_api.ts"
6+
},
7+
"allowedNonPeerDependencies": ["."]
8+
}
+5-15
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "angular-reactive-validation",
33
"description": "Reactive Forms validation shouldn't require the developer to write lots of HTML to show validation messages. This library makes it easy.",
4-
"version": "7.0.0",
4+
"version": "8.0.0",
55
"repository": {
66
"type": "git",
77
"url": "https://github.com/davidwalschots/angular-reactive-validation.git"
@@ -20,19 +20,9 @@
2020
"private": false,
2121
"dependencies": {},
2222
"peerDependencies": {
23-
"@angular/core": "^13.0.0",
24-
"@angular/common": "^13.0.0",
25-
"@angular/forms": "^13.0.0",
26-
"rxjs": "^6.5.3"
27-
},
28-
"ngPackage": {
29-
"$schema": "./node_modules/ng-packagr/ng-package.schema.json",
30-
"dest": "../dist/angular-reactive-validation",
31-
"lib": {
32-
"entryFile": "src/public_api.ts"
33-
},
34-
"allowedNonPeerDependencies": [
35-
"."
36-
]
23+
"@angular/core": "^14.0.0",
24+
"@angular/common": "^14.0.0",
25+
"@angular/forms": "^14.0.0",
26+
"rxjs": "^6.6.7"
3727
}
3828
}

angular-reactive-validation/src/form/form.directive.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Component } from '@angular/core';
2-
import { FormGroup, ReactiveFormsModule } from '@angular/forms';
2+
import { UntypedFormGroup, ReactiveFormsModule } from '@angular/forms';
33
import { TestBed } from '@angular/core/testing';
44
import { By } from '@angular/platform-browser';
55

@@ -37,6 +37,6 @@ describe('FormDirective', () => {
3737
</form>`
3838
})
3939
class TestHostComponent {
40-
form = new FormGroup({});
40+
form = new UntypedFormGroup({});
4141
}
4242
});

angular-reactive-validation/src/get-control-path.spec.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import { TestBed, inject } from '@angular/core/testing';
2-
import { FormBuilder } from '@angular/forms';
2+
import { UntypedFormBuilder } from '@angular/forms';
33

44
import { getControlPath } from './get-control-path';
55

66
describe('getControlPath', () => {
77
beforeEach(() => {
88
TestBed.configureTestingModule({
99
providers: [
10-
FormBuilder
10+
UntypedFormBuilder
1111
]
1212
});
1313
});
1414

15-
it(`emits paths for form groups`, inject([FormBuilder], (fb: FormBuilder) => {
15+
it(`emits paths for form groups`, inject([UntypedFormBuilder], (fb: UntypedFormBuilder) => {
1616
const firstName = fb.control('');
1717
fb.group({
1818
name: fb.group({
@@ -23,7 +23,7 @@ describe('getControlPath', () => {
2323
expect(getControlPath(firstName)).toEqual('name.firstName');
2424
}));
2525

26-
it(`emits numeric paths for form arrays`, inject([FormBuilder], (fb: FormBuilder) => {
26+
it(`emits numeric paths for form arrays`, inject([UntypedFormBuilder], (fb: UntypedFormBuilder) => {
2727
const firstName = fb.control('');
2828
const firstName2 = fb.control('');
2929

@@ -42,21 +42,21 @@ describe('getControlPath', () => {
4242
expect(getControlPath(firstName2)).toEqual('persons.1.firstName');
4343
}));
4444

45-
it(`emits an empty string for a control without parents`, inject([FormBuilder], (fb: FormBuilder) => {
45+
it(`emits an empty string for a control without parents`, inject([UntypedFormBuilder], (fb: UntypedFormBuilder) => {
4646
const control = fb.control('');
4747

4848
expect(getControlPath(control)).toEqual('');
4949
}));
5050

51-
it(`emits an index string for a control with only a form array as parent`, inject([FormBuilder], (fb: FormBuilder) => {
51+
it(`emits an index string for a control with only a form array as parent`, inject([UntypedFormBuilder], (fb: UntypedFormBuilder) => {
5252
const control = fb.control('');
5353

5454
fb.array([control]);
5555

5656
expect(getControlPath(control)).toEqual('0');
5757
}));
5858

59-
it(`emits a single identifier for a control with only a single form group as parent`, inject([FormBuilder], (fb: FormBuilder) => {
59+
it(`emits a single identifier for a control with only a single form group as parent`, inject([UntypedFormBuilder], (fb: UntypedFormBuilder) => {
6060
const control = fb.control('');
6161

6262
fb.group({

angular-reactive-validation/src/get-form-control-from-container.spec.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import { TestBed, inject } from '@angular/core/testing';
2-
import { FormBuilder } from '@angular/forms';
2+
import { UntypedFormBuilder } from '@angular/forms';
33

44
import { getFormControlFromContainer } from './get-form-control-from-container';
55

66
describe('getFormControlFromContainer', () => {
77
beforeEach(() => {
88
TestBed.configureTestingModule({
99
providers: [
10-
FormBuilder
10+
UntypedFormBuilder
1111
]
1212
});
1313
});
1414

15-
it(`gets a FormControl from the FormGroup`, inject([FormBuilder], (fb: FormBuilder) => {
15+
it(`gets a FormControl from the FormGroup`, inject([UntypedFormBuilder], (fb: UntypedFormBuilder) => {
1616
const firstName = fb.control('');
1717
const group = fb.group({
1818
firstName: firstName
@@ -25,13 +25,13 @@ describe('getFormControlFromContainer', () => {
2525
expect(getFormControlFromContainer('firstName', container)).toBe(firstName);
2626
}));
2727

28-
it(`throws an Error when no container is provided`, inject([FormBuilder], (fb: FormBuilder) => {
28+
it(`throws an Error when no container is provided`, inject([UntypedFormBuilder], (fb: UntypedFormBuilder) => {
2929
expect(() => getFormControlFromContainer('firstName', undefined)).toThrow(new Error(
3030
`You can't pass a string to arv-validation-messages's for attribute, when the ` +
3131
`arv-validation-messages element is not a child of an element with a formGroupName or formGroup declaration.`));
3232
}));
3333

34-
it(`throws an Error when there is no FormControl with the given name`, inject([FormBuilder], (fb: FormBuilder) => {
34+
it(`throws an Error when there is no FormControl with the given name`, inject([UntypedFormBuilder], (fb: UntypedFormBuilder) => {
3535
const group = fb.group({});
3636

3737
const container: any = {
@@ -44,7 +44,7 @@ describe('getFormControlFromContainer', () => {
4444
));
4545
}));
4646

47-
it(`throws an Error when there is a FormGroup with the given name`, inject([FormBuilder], (fb: FormBuilder) => {
47+
it(`throws an Error when there is a FormGroup with the given name`, inject([UntypedFormBuilder], (fb: UntypedFormBuilder) => {
4848
const group = fb.group({
4949
name: fb.group({})
5050
});
@@ -59,7 +59,7 @@ describe('getFormControlFromContainer', () => {
5959
));
6060
}));
6161

62-
it(`throws an Error when there is a FormArray with the given name`, inject([FormBuilder], (fb: FormBuilder) => {
62+
it(`throws an Error when there is a FormArray with the given name`, inject([UntypedFormBuilder], (fb: UntypedFormBuilder) => {
6363
const group = fb.group({
6464
name: fb.array([])
6565
});

angular-reactive-validation/src/get-form-control-from-container.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import { FormGroup, FormControl, ControlContainer, FormGroupDirective } from '@angular/forms';
1+
import { UntypedFormGroup, UntypedFormControl, ControlContainer, FormGroupDirective } from '@angular/forms';
22

3-
export const getFormControlFromContainer = (name: string, controlContainer: ControlContainer | undefined): FormControl => {
3+
export const getFormControlFromContainer = (name: string, controlContainer: ControlContainer | undefined): UntypedFormControl => {
44
if (controlContainer) {
5-
const control = (controlContainer.control as FormGroup).controls[name];
5+
const control = (controlContainer.control as UntypedFormGroup).controls[name];
66
if (!control) {
77
throw new Error(`There is no control named '${name}'` +
88
(getPath(controlContainer).length > 0 ? ` within '${getPath(controlContainer).join('.')}'` : '') + '.');
99
}
10-
if (!(control instanceof FormControl)) {
10+
if (!(control instanceof UntypedFormControl)) {
1111
throw new Error(`The control named '${name}' ` +
1212
(getPath(controlContainer).length > 0 ? `within '${getPath(controlContainer).join('.')}' ` : '') +
1313
`is not a FormControl. Maybe you accidentally referenced a FormGroup or FormArray?`);
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
export {ReactiveValidationModule} from './reactive-validation.module';
2-
export {ReactiveValidationModuleConfiguration} from './reactive-validation-module-configuration';
3-
export {Validators} from './validators';
4-
export {ValidatorDeclaration} from './validator-declaration';
5-
export {ValidationMessageComponent} from './validation-message/validation-message.component';
6-
export {FormDirective} from './form/form.directive';
7-
export {ValidationMessagesComponent} from './validation-messages/validation-messages.component';
1+
export { FormDirective } from './form/form.directive';
2+
export { ReactiveValidationModule } from './reactive-validation.module';
3+
export { ReactiveValidationModuleConfiguration } from './reactive-validation-module-configuration';
4+
export { Validators } from './validators';
5+
export { ValidatorDeclaration } from './validator-declaration';
6+
export { ValidationMessagesComponent } from './validation-messages/validation-messages.component';
7+
export { ValidationMessageComponent } from './validation-message/validation-message.component';

angular-reactive-validation/src/reactive-validation-module-configuration.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FormControl } from '@angular/forms';
1+
import { UntypedFormControl } from '@angular/forms';
22

33
export interface ReactiveValidationModuleConfiguration {
44
/**
@@ -9,5 +9,5 @@ export interface ReactiveValidationModuleConfiguration {
99
* @param formSubmitted whether the form is submitted or not. When undefined, it's not known
1010
* if the form is submitted, due to the form tag missing a formGroup.
1111
*/
12-
displayValidationMessageWhen?: (control: FormControl, formSubmitted: boolean | undefined) => boolean;
12+
displayValidationMessageWhen?: (control: UntypedFormControl, formSubmitted: boolean | undefined) => boolean;
1313
}

angular-reactive-validation/src/validation-error.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
import { FormControl, ValidationErrors } from '@angular/forms';
1+
import { UntypedFormControl, ValidationErrors } from '@angular/forms';
22

33
export class ValidationError {
4-
control: FormControl;
4+
control: UntypedFormControl;
55
key: string;
66
errorObject: ValidationErrors;
77

8-
constructor(control: FormControl, key: string, errorObject: ValidationErrors) {
8+
constructor(control: UntypedFormControl, key: string, errorObject: ValidationErrors) {
99
this.control = control;
1010
this.key = key;
1111
this.errorObject = errorObject;
1212
}
1313

14-
static fromFirstError(control: FormControl): ValidationError | undefined {
14+
static fromFirstError(control: UntypedFormControl): ValidationError | undefined {
1515
if (!control.errors) {
1616
return undefined;
1717
}

angular-reactive-validation/src/validation-message/validation-message.component.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { TestBed, ComponentFixture } from '@angular/core/testing';
44
import { ValidationMessageComponent } from './validation-message.component';
55
import { ValidationError } from '../validation-error';
66
import { Validators } from '../validators';
7-
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
7+
import { UntypedFormControl, UntypedFormGroup, ReactiveFormsModule } from '@angular/forms';
88

99
describe('ValidationMessageComponent', () => {
1010
describe('canHandle', () => {
@@ -130,10 +130,10 @@ describe('ValidationMessageComponent', () => {
130130
class TestHostComponent {
131131
@ViewChild(ValidationMessageComponent, { static: true }) validationMessageComponent: ValidationMessageComponent;
132132

133-
age = new FormControl(0, [
133+
age = new UntypedFormControl(0, [
134134
Validators.min(10, 'invalid age')
135135
]);
136-
form = new FormGroup({
136+
form = new UntypedFormGroup({
137137
age: this.age
138138
});
139139
}

angular-reactive-validation/src/validation-message/validation-message.component.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Component, Input, ViewEncapsulation, Optional, OnInit } from '@angular/core';
2-
import { FormControl, ValidationErrors, ControlContainer } from '@angular/forms';
2+
import { UntypedFormControl, ValidationErrors, ControlContainer } from '@angular/forms';
33

44
import { ValidationError } from '../validation-error';
55
import { getFormControlFromContainer, isControlContainerVoidOrInitialized } from '../get-form-control-from-container';
@@ -22,14 +22,14 @@ export class ValidationMessageComponent implements OnInit {
2222
* The FormControl for which a custom validation message should be shown. This is only required when the parent
2323
* ValidationMessagesComponent has multiple FormControls specified.
2424
*/
25-
set for(control: FormControl | string | undefined) {
25+
set for(control: UntypedFormControl | string | undefined) {
2626
if (!isControlContainerVoidOrInitialized(this.controlContainer)) {
2727
this.initializeForOnInit = () => this.for = control;
2828
return;
2929
}
3030
this._for = typeof control === 'string' ? getFormControlFromContainer(control, this.controlContainer) : control;
3131
}
32-
get for(): FormControl | string | undefined {
32+
get for(): UntypedFormControl | string | undefined {
3333
return this._for;
3434
}
3535

@@ -40,7 +40,7 @@ export class ValidationMessageComponent implements OnInit {
4040
key: string | undefined;
4141

4242
private _context: ValidationErrors | undefined;
43-
private _for: FormControl | undefined;
43+
private _for: UntypedFormControl | undefined;
4444

4545
constructor(@Optional() private controlContainer: ControlContainer) { }
4646

angular-reactive-validation/src/validation-messages/validation-messages.component.spec.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Component, ViewChild } from '@angular/core';
22
import { TestBed, ComponentFixture } from '@angular/core/testing';
3-
import { ControlContainer, FormGroup, FormControl, ReactiveFormsModule, FormGroupDirective } from '@angular/forms';
3+
import { ControlContainer, UntypedFormGroup, ReactiveFormsModule, FormGroupDirective, FormControl, FormGroup, UntypedFormControl }
4+
from '@angular/forms';
45
import { Subject } from 'rxjs';
56

67
import { ValidationMessagesComponent } from './validation-messages.component';
@@ -14,7 +15,7 @@ const isErrorEvent = (event: Event | string): event is ErrorEvent => (event as E
1415
describe('ValidationMessagesComponent', () => {
1516
describe('properties and functions', () => {
1617
let component: ValidationMessagesComponent;
17-
let formGroup: FormGroup;
18+
let formGroup: UntypedFormGroup;
1819
let firstNameControl: FormControl;
1920
let middleNameControl: FormControl;
2021
let lastNameControl: FormControl;
@@ -29,7 +30,7 @@ describe('ValidationMessagesComponent', () => {
2930
Validators.required('A last name is required'),
3031
Validators.minLength(5, minLength => `Last name needs to be at least ${minLength} characters long`)
3132
]);
32-
formGroup = new FormGroup({
33+
formGroup = new UntypedFormGroup({
3334
firstName: firstNameControl,
3435
middleName: middleNameControl,
3536
lastName: lastNameControl
@@ -83,7 +84,7 @@ describe('ValidationMessagesComponent', () => {
8384
it(`getErrorMessages returns the first error message per touched control (default configuration)`, () => {
8485
component.for = [firstNameControl, middleNameControl, lastNameControl];
8586
firstNameControl.markAsTouched();
86-
// We skip middleNameControl on purpose, to ensure that it doesn't return it's error.
87+
// We skip middleNameControl on purpose, to ensure that it doesn't return its error.
8788
lastNameControl.markAsTouched();
8889
lastNameControl.setValue('abc');
8990

@@ -131,7 +132,7 @@ describe('ValidationMessagesComponent', () => {
131132

132133
describe('an alternative configuration', () => {
133134
const configuration = {
134-
displayValidationMessageWhen: () => true
135+
displayValidationMessageWhen: (_: UntypedFormControl, __: boolean | undefined) => true
135136
};
136137

137138
beforeEach(() => {
@@ -155,7 +156,7 @@ describe('ValidationMessagesComponent', () => {
155156

156157
it(`displayValidationMessageWhen's formSubmitted is undefined when a FormDirective is not provided`, () => {
157158
fixture.detectChanges();
158-
expect(configuration.displayValidationMessageWhen).toHaveBeenCalledWith(jasmine.any(FormControl), undefined);
159+
expect(configuration.displayValidationMessageWhen).toHaveBeenCalledWith(jasmine.any(UntypedFormControl), undefined);
159160
});
160161
});
161162

0 commit comments

Comments
 (0)