2016-08-14 00:26:08 +00:00
/ * *
* @license
2020-05-19 19:08:49 +00:00
* Copyright Google LLC All Rights Reserved .
2016-08-14 00:26:08 +00:00
*
* Use of this source code is governed by an MIT - style license that can be
2024-09-20 15:23:15 +00:00
* found in the LICENSE file at https : //angular.dev/license
2016-08-14 00:26:08 +00:00
* /
2023-01-02 10:41:37 +00:00
import { AsyncValidatorFn , FormArray , FormControl , FormGroup , Validators } from '../index' ;
2021-12-12 01:36:31 +00:00
2026-02-09 21:18:00 +00:00
import { asyncValidator , asyncValidatorReturningObservable } from './util' ;
import { useAutoTick , timeout } from '@angular/private/testing' ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
( function ( ) {
function otherAsyncValidator() {
return Promise . resolve ( { 'other' : true } ) ;
}
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
function syncValidator() {
return null ;
}
2018-10-29 08:36:17 +00:00
2024-04-18 17:29:04 +00:00
describe ( 'FormControl' , ( ) = > {
2026-02-04 04:51:54 +00:00
useAutoTick ( ) ;
2024-04-18 17:29:04 +00:00
it ( 'should default the value to null' , ( ) = > {
const c = new FormControl ( ) ;
expect ( c . value ) . toBe ( null ) ;
2020-04-06 22:44:00 +00:00
} ) ;
2016-08-24 23:58:43 +00:00
2024-11-14 16:21:59 +00:00
describe ( 'markAllAsDirty' , ( ) = > {
it ( 'should mark only the control itself as dirty' , ( ) = > {
const control = new FormControl ( '' ) ;
expect ( control . dirty ) . toBe ( false ) ;
control . markAllAsDirty ( ) ;
expect ( control . dirty ) . toBe ( true ) ;
} ) ;
} ) ;
2024-04-18 17:29:04 +00:00
describe ( 'markAllAsTouched' , ( ) = > {
it ( 'should mark only the control itself as touched' , ( ) = > {
const control = new FormControl ( '' ) ;
expect ( control . touched ) . toBe ( false ) ;
control . markAllAsTouched ( ) ;
expect ( control . touched ) . toBe ( true ) ;
} ) ;
2020-04-06 22:44:00 +00:00
} ) ;
2016-09-01 23:51:42 +00:00
2024-04-18 17:29:04 +00:00
describe ( 'boxed values' , ( ) = > {
it ( 'should support valid boxed values on creation' , ( ) = > {
const c = new FormControl ( { value : 'some val' , disabled : true } , null ! , null ! ) ;
expect ( c . disabled ) . toBe ( true ) ;
expect ( c . value ) . toBe ( 'some val' ) ;
expect ( c . status ) . toBe ( 'DISABLED' ) ;
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not treat objects as boxed values when `disabled` field is present, but `value` is missing' , ( ) = > {
const c = new FormControl ( { disabled : true } ) ;
expect ( c . value ) . toEqual ( { disabled : true } ) ;
expect ( c . disabled ) . toBe ( false ) ;
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should honor boxed value with disabled control when validating' , ( ) = > {
const c = new FormControl ( { value : '' , disabled : true } , Validators . required ) ;
expect ( c . disabled ) . toBe ( true ) ;
expect ( c . valid ) . toBe ( false ) ;
expect ( c . status ) . toBe ( 'DISABLED' ) ;
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not treat objects as boxed values if they have more than two props' , ( ) = > {
const c : FormControl = new FormControl (
{ value : '' , disabled : true , test : 'test' } as any ,
null ! ,
null ! ,
) ;
expect ( c . value ) . toEqual ( { value : '' , disabled : true , test : 'test' } ) ;
expect ( c . disabled ) . toBe ( false ) ;
} ) ;
2017-08-03 01:10:10 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not treat objects as boxed values if disabled is missing' , ( ) = > {
const c = new FormControl ( { value : '' , test : 'test' } , null ! , null ! ) ;
expect ( c . value ) . toEqual ( { value : '' , test : 'test' } ) ;
expect ( c . disabled ) . toBe ( false ) ;
} ) ;
2020-04-06 22:44:00 +00:00
} ) ;
2017-08-03 01:10:10 +00:00
2024-04-18 17:29:04 +00:00
describe ( 'updateOn' , ( ) = > {
it ( 'should default to on change' , ( ) = > {
const c = new FormControl ( '' ) ;
expect ( c . updateOn ) . toEqual ( 'change' ) ;
2017-08-09 22:41:53 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
it ( 'should default to on change with an options obj' , ( ) = > {
const c = new FormControl ( '' , { validators : Validators.required } ) ;
expect ( c . updateOn ) . toEqual ( 'change' ) ;
} ) ;
2017-08-09 22:41:53 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should set updateOn when updating on blur' , ( ) = > {
const c = new FormControl ( '' , { updateOn : 'blur' } ) ;
expect ( c . updateOn ) . toEqual ( 'blur' ) ;
2020-04-06 22:44:00 +00:00
} ) ;
2017-08-09 22:41:53 +00:00
2024-04-18 17:29:04 +00:00
describe ( 'in groups and arrays' , ( ) = > {
it ( 'should default to group updateOn when not set in control' , ( ) = > {
const g = new FormGroup (
{ one : new FormControl ( ) , two : new FormControl ( ) } ,
{ updateOn : 'blur' } ,
) ;
expect ( g . get ( 'one' ) ! . updateOn ) . toEqual ( 'blur' ) ;
expect ( g . get ( 'two' ) ! . updateOn ) . toEqual ( 'blur' ) ;
} ) ;
it ( 'should default to array updateOn when not set in control' , ( ) = > {
const a = new FormArray ( [ new FormControl ( ) , new FormControl ( ) ] , { updateOn : 'blur' } ) ;
expect ( a . get ( [ 0 ] ) ! . updateOn ) . toEqual ( 'blur' ) ;
expect ( a . get ( [ 1 ] ) ! . updateOn ) . toEqual ( 'blur' ) ;
} ) ;
it ( 'should set updateOn with nested groups' , ( ) = > {
const g = new FormGroup (
2020-04-06 22:44:00 +00:00
{
group : new FormGroup ( { one : new FormControl ( ) , two : new FormControl ( ) } ) ,
} ,
2024-04-18 17:29:04 +00:00
{ updateOn : 'blur' } ,
) ;
2017-08-09 22:41:53 +00:00
2024-04-18 17:29:04 +00:00
expect ( g . get ( 'group.one' ) ! . updateOn ) . toEqual ( 'blur' ) ;
expect ( g . get ( 'group.two' ) ! . updateOn ) . toEqual ( 'blur' ) ;
expect ( g . get ( 'group' ) ! . updateOn ) . toEqual ( 'blur' ) ;
} ) ;
2017-08-09 22:41:53 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should set updateOn with nested arrays' , ( ) = > {
const g = new FormGroup (
2020-04-06 22:44:00 +00:00
{
arr : new FormArray ( [ new FormControl ( ) , new FormControl ( ) ] ) ,
} ,
2024-04-18 17:29:04 +00:00
{ updateOn : 'blur' } ,
) ;
2017-08-09 22:41:53 +00:00
2024-04-18 17:29:04 +00:00
expect ( g . get ( [ 'arr' , 0 ] ) ! . updateOn ) . toEqual ( 'blur' ) ;
expect ( g . get ( [ 'arr' , 1 ] ) ! . updateOn ) . toEqual ( 'blur' ) ;
expect ( g . get ( 'arr' ) ! . updateOn ) . toEqual ( 'blur' ) ;
} ) ;
2017-08-09 22:41:53 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should allow control updateOn to override group updateOn' , ( ) = > {
const g = new FormGroup (
2020-04-06 22:44:00 +00:00
{ one : new FormControl ( '' , { updateOn : 'change' } ) , two : new FormControl ( ) } ,
2024-04-18 17:29:04 +00:00
{ updateOn : 'blur' } ,
) ;
2017-08-09 22:41:53 +00:00
2024-04-18 17:29:04 +00:00
expect ( g . get ( 'one' ) ! . updateOn ) . toEqual ( 'change' ) ;
expect ( g . get ( 'two' ) ! . updateOn ) . toEqual ( 'blur' ) ;
} ) ;
2017-08-09 22:41:53 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should set updateOn with complex setup' , ( ) = > {
const g = new FormGroup ( {
group : new FormGroup (
2017-08-09 22:41:53 +00:00
{ one : new FormControl ( '' , { updateOn : 'change' } ) , two : new FormControl ( ) } ,
2024-04-18 17:29:04 +00:00
{ updateOn : 'blur' } ,
) ,
groupTwo : new FormGroup ( { one : new FormControl ( ) } , { updateOn : 'submit' } ) ,
three : new FormControl ( ) ,
} ) ;
expect ( g . get ( 'group.one' ) ! . updateOn ) . toEqual ( 'change' ) ;
expect ( g . get ( 'group.two' ) ! . updateOn ) . toEqual ( 'blur' ) ;
expect ( g . get ( 'groupTwo.one' ) ! . updateOn ) . toEqual ( 'submit' ) ;
expect ( g . get ( 'three' ) ! . updateOn ) . toEqual ( 'change' ) ;
2017-08-09 22:41:53 +00:00
} ) ;
2017-08-03 01:10:10 +00:00
} ) ;
} ) ;
2024-04-18 17:29:04 +00:00
describe ( 'validator' , ( ) = > {
it ( 'should run validator with the initial value' , ( ) = > {
const c = new FormControl ( 'value' , Validators . required ) ;
expect ( c . valid ) . toEqual ( true ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should rerun the validator when the value changes' , ( ) = > {
const c = new FormControl ( 'value' , Validators . required ) ;
c . setValue ( null ) ;
expect ( c . valid ) . toEqual ( false ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should support arrays of validator functions if passed' , ( ) = > {
const c = new FormControl ( 'value' , [ Validators . required , Validators . minLength ( 3 ) ] ) ;
c . setValue ( 'a' ) ;
expect ( c . valid ) . toEqual ( false ) ;
2017-07-25 22:01:04 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'aaa' ) ;
expect ( c . valid ) . toEqual ( true ) ;
} ) ;
2017-07-25 22:01:04 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should support single validator from options obj' , ( ) = > {
const c : FormControl = new FormControl ( null , { validators : Validators.required } ) ;
expect ( c . valid ) . toEqual ( false ) ;
expect ( c . errors ) . toEqual ( { required : true } ) ;
2017-07-25 22:01:04 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'value' ) ;
expect ( c . valid ) . toEqual ( true ) ;
} ) ;
2017-07-25 22:01:04 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should support multiple validators from options obj' , ( ) = > {
const c : FormControl = new FormControl ( null , {
validators : [ Validators . required , Validators . minLength ( 3 ) ] ,
} ) ;
expect ( c . valid ) . toEqual ( false ) ;
expect ( c . errors ) . toEqual ( { required : true } ) ;
2017-07-25 22:01:04 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'aa' ) ;
expect ( c . valid ) . toEqual ( false ) ;
expect ( c . errors ) . toEqual ( { minlength : { requiredLength : 3 , actualLength : 2 } } ) ;
2017-07-25 22:01:04 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'aaa' ) ;
expect ( c . valid ) . toEqual ( true ) ;
} ) ;
2017-07-25 22:01:04 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should support a null validators value' , ( ) = > {
const c = new FormControl ( null , { validators : null } ) ;
expect ( c . valid ) . toEqual ( true ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should support an empty options obj' , ( ) = > {
const c = new FormControl ( null , { } ) ;
expect ( c . valid ) . toEqual ( true ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should return errors' , ( ) = > {
const c = new FormControl ( null , Validators . required ) ;
expect ( c . errors ) . toEqual ( { 'required' : true } ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should set single validator' , ( ) = > {
const c : FormControl = new FormControl ( null ) ;
expect ( c . valid ) . toEqual ( true ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValidators ( Validators . required ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( null ) ;
expect ( c . valid ) . toEqual ( false ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'abc' ) ;
expect ( c . valid ) . toEqual ( true ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should set multiple validators from array' , ( ) = > {
const c = new FormControl ( '' ) ;
expect ( c . valid ) . toEqual ( true ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValidators ( [ Validators . minLength ( 5 ) , Validators . required ] ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( '' ) ;
expect ( c . valid ) . toEqual ( false ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'abc' ) ;
expect ( c . valid ) . toEqual ( false ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'abcde' ) ;
expect ( c . valid ) . toEqual ( true ) ;
} ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should override validators using `setValidators` function' , ( ) = > {
const c = new FormControl ( '' ) ;
expect ( c . valid ) . toEqual ( true ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValidators ( [ Validators . minLength ( 5 ) , Validators . required ] ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( '' ) ;
expect ( c . valid ) . toEqual ( false ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'abc' ) ;
expect ( c . valid ) . toEqual ( false ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'abcde' ) ;
expect ( c . valid ) . toEqual ( true ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
// Define new set of validators, overriding previously applied ones.
c . setValidators ( [ Validators . maxLength ( 2 ) ] ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'abcdef' ) ;
expect ( c . valid ) . toEqual ( false ) ;
2022-11-16 08:59:40 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'a' ) ;
expect ( c . valid ) . toEqual ( true ) ;
} ) ;
2022-11-16 08:59:40 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not mutate the validators array when overriding using setValidators' , ( ) = > {
const control = new FormControl ( '' ) ;
const originalValidators = [ Validators . required ] ;
2022-11-16 08:59:40 +00:00
2024-04-18 17:29:04 +00:00
control . setValidators ( originalValidators ) ;
control . addValidators ( Validators . minLength ( 10 ) ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
expect ( originalValidators . length ) . toBe ( 1 ) ;
} ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should override validators by setting `control.validator` field value' , ( ) = > {
const c = new FormControl ( '' ) ;
expect ( c . valid ) . toEqual ( true ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
// Define new set of validators, overriding previously applied ones.
c . validator = Validators . compose ( [ Validators . minLength ( 5 ) , Validators . required ] ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( '' ) ;
expect ( c . valid ) . toEqual ( false ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'abc' ) ;
expect ( c . valid ) . toEqual ( false ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'abcde' ) ;
expect ( c . valid ) . toEqual ( true ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
// Define new set of validators, overriding previously applied ones.
c . validator = Validators . compose ( [ Validators . maxLength ( 2 ) ] ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'abcdef' ) ;
expect ( c . valid ) . toEqual ( false ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'a' ) ;
expect ( c . valid ) . toEqual ( true ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should clear validators' , ( ) = > {
const c = new FormControl ( '' , Validators . required ) ;
expect ( c . valid ) . toEqual ( false ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . clearValidators ( ) ;
expect ( c . validator ) . toEqual ( null ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( '' ) ;
expect ( c . valid ) . toEqual ( true ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should add after clearing' , ( ) = > {
const c = new FormControl ( '' , Validators . required ) ;
expect ( c . valid ) . toEqual ( false ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
c . clearValidators ( ) ;
expect ( c . validator ) . toEqual ( null ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
c . setValidators ( [ Validators . required ] ) ;
expect ( c . validator ) . not . toBe ( null ) ;
} ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should check presence of and remove a validator set in the control constructor' , ( ) = > {
const c = new FormControl ( '' , Validators . required ) ;
expect ( c . hasValidator ( Validators . required ) ) . toEqual ( true ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
c . removeValidators ( Validators . required ) ;
expect ( c . hasValidator ( Validators . required ) ) . toEqual ( false ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
c . addValidators ( Validators . required ) ;
expect ( c . hasValidator ( Validators . required ) ) . toEqual ( true ) ;
} ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should check presence of and remove a validator set with addValidators' , ( ) = > {
const c = new FormControl ( '' ) ;
expect ( c . hasValidator ( Validators . required ) ) . toEqual ( false ) ;
c . addValidators ( Validators . required ) ;
expect ( c . hasValidator ( Validators . required ) ) . toEqual ( true ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
c . removeValidators ( Validators . required ) ;
expect ( c . hasValidator ( Validators . required ) ) . toEqual ( false ) ;
} ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should check presence of and remove multiple validators set at the same time' , ( ) = > {
const c = new FormControl ( '3' ) ;
const minValidator = Validators . min ( 4 ) ;
c . addValidators ( [ Validators . required , minValidator ] ) ;
expect ( c . hasValidator ( Validators . required ) ) . toEqual ( true ) ;
expect ( c . hasValidator ( minValidator ) ) . toEqual ( true ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
c . removeValidators ( [ Validators . required , minValidator ] ) ;
expect ( c . hasValidator ( Validators . required ) ) . toEqual ( false ) ;
expect ( c . hasValidator ( minValidator ) ) . toEqual ( false ) ;
} ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should be able to remove a validator added multiple times' , ( ) = > {
const c = new FormControl ( '' , Validators . required ) ;
c . addValidators ( Validators . required ) ;
c . addValidators ( Validators . required ) ;
expect ( c . hasValidator ( Validators . required ) ) . toEqual ( true ) ;
2022-11-16 08:59:40 +00:00
2024-04-18 17:29:04 +00:00
c . removeValidators ( Validators . required ) ;
expect ( c . hasValidator ( Validators . required ) ) . toEqual ( false ) ;
} ) ;
2022-11-16 08:59:40 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not mutate the validators array when adding/removing sync validators' , ( ) = > {
const originalValidators = [ Validators . required ] ;
const control = new FormControl ( '' , originalValidators ) ;
2022-11-16 08:59:40 +00:00
2024-04-18 17:29:04 +00:00
control . addValidators ( Validators . min ( 10 ) ) ;
expect ( originalValidators . length ) . toBe ( 1 ) ;
2022-11-16 08:59:40 +00:00
2024-04-18 17:29:04 +00:00
control . removeValidators ( Validators . required ) ;
expect ( originalValidators . length ) . toBe ( 1 ) ;
} ) ;
2022-11-16 08:59:40 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not mutate the validators array when adding/removing async validators' , ( ) = > {
const firstValidator = asyncValidator ( 'one' ) ;
const secondValidator = asyncValidator ( 'two' ) ;
const originalValidators = [ firstValidator ] ;
const control = new FormControl ( '' , null , originalValidators ) ;
2022-11-16 08:59:40 +00:00
2024-04-18 17:29:04 +00:00
control . addAsyncValidators ( secondValidator ) ;
expect ( originalValidators . length ) . toBe ( 1 ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
control . removeAsyncValidators ( firstValidator ) ;
expect ( originalValidators . length ) . toBe ( 1 ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should return false when checking presence of a validator not identical by reference' , ( ) = > {
const minValidator = Validators . min ( 5 ) ;
const c = new FormControl ( '1' , minValidator ) ;
expect ( c . hasValidator ( minValidator ) ) . toEqual ( true ) ;
expect ( c . hasValidator ( Validators . min ( 5 ) ) ) . toEqual ( false ) ;
} ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
describe ( 'asyncValidator' , ( ) = > {
2026-02-04 04:51:54 +00:00
it ( 'should run validator with the initial value' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( 'value' , null ! , asyncValidator ( 'expected' ) ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( false ) ;
expect ( c . errors ) . toEqual ( { 'async' : true } ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should support validators returning observables' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( 'value' , null ! , asyncValidatorReturningObservable ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( false ) ;
expect ( c . errors ) . toEqual ( { 'async' : true } ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should rerun the validator when the value changes' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( 'value' , null ! , asyncValidator ( 'expected' ) ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'expected' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( true ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should run the async validator only when the sync validator passes' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( '' , Validators . required , asyncValidator ( 'expected' ) ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . errors ) . toEqual ( { 'required' : true } ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'some value' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . errors ) . toEqual ( { 'async' : true } ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should mark the control as pending while running the async validation' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( '' , null ! , asyncValidator ( 'expected' ) ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . pending ) . toEqual ( true ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . pending ) . toEqual ( false ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should only use the latest async validation run' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl (
'' ,
null ! ,
asyncValidator ( 'expected' , { 'long' : 200 , 'expected' : 100 } ) ,
) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'long' ) ;
c . setValue ( 'expected' ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
await timeout ( 300 ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( true ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should support arrays of async validator functions if passed' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( 'value' , null ! , [
asyncValidator ( 'expected' ) ,
otherAsyncValidator ,
] ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2017-07-25 22:01:04 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . errors ) . toEqual ( { 'async' : true , 'other' : true } ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2017-07-25 22:01:04 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should support a single async validator from options obj' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( 'value' , { asyncValidators : asyncValidator ( 'expected' ) } ) ;
expect ( c . pending ) . toEqual ( true ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2017-07-25 22:01:04 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( false ) ;
expect ( c . errors ) . toEqual ( { 'async' : true } ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2017-07-25 22:01:04 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should support multiple async validators from options obj' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( 'value' , {
asyncValidators : [ asyncValidator ( 'expected' ) , otherAsyncValidator ] ,
} ) ;
expect ( c . pending ) . toEqual ( true ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2017-07-25 22:01:04 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( false ) ;
expect ( c . errors ) . toEqual ( { 'async' : true , 'other' : true } ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2017-07-25 22:01:04 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should support a mix of validators from options obj' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( '' , {
validators : Validators.required ,
asyncValidators : asyncValidator ( 'expected' ) ,
} ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . errors ) . toEqual ( { required : true } ) ;
2017-07-25 22:01:04 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'value' ) ;
expect ( c . pending ) . toBe ( true ) ;
2017-07-25 22:01:04 +00:00
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( false ) ;
expect ( c . errors ) . toEqual ( { 'async' : true } ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should add single async validator' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( 'value' , null ! ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setAsyncValidators ( asyncValidator ( 'expected' ) ) ;
expect ( c . asyncValidator ) . not . toEqual ( null ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'expected' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( true ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should add async validator from array' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( 'value' , null ! ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setAsyncValidators ( [ asyncValidator ( 'expected' ) ] ) ;
expect ( c . asyncValidator ) . not . toEqual ( null ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'expected' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( true ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2020-07-02 01:16:49 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should override validators using `setAsyncValidators` function' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( '' ) ;
expect ( c . valid ) . toEqual ( true ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setAsyncValidators ( [ asyncValidator ( 'expected' ) ] ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( '' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( false ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'expected' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( true ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
// Define new set of validators, overriding previously applied ones.
c . setAsyncValidators ( [ asyncValidator ( 'new expected' ) ] ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'expected' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( false ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'new expected' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( true ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2022-11-16 08:59:40 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not mutate the validators array when overriding using setValidators' , ( ) = > {
const control = new FormControl ( '' ) ;
const originalValidators = [ asyncValidator ( 'one' ) ] ;
2022-11-16 08:59:40 +00:00
2024-04-18 17:29:04 +00:00
control . setAsyncValidators ( originalValidators ) ;
control . addAsyncValidators ( asyncValidator ( 'two' ) ) ;
2022-11-16 08:59:40 +00:00
2024-04-18 17:29:04 +00:00
expect ( originalValidators . length ) . toBe ( 1 ) ;
} ) ;
2020-07-02 01:16:49 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should override validators by setting `control.asyncValidator` field value' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( '' ) ;
expect ( c . valid ) . toEqual ( true ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . asyncValidator = Validators . composeAsync ( [ asyncValidator ( 'expected' ) ] ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( '' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( false ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'expected' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( true ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
// Define new set of validators, overriding previously applied ones.
c . asyncValidator = Validators . composeAsync ( [ asyncValidator ( 'new expected' ) ] ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'expected' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( false ) ;
2020-07-02 01:16:49 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'new expected' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( true ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should clear async validators' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( 'value' , [ asyncValidator ( 'expected' ) , otherAsyncValidator ] ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . clearValidators ( ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . asyncValidator ) . toEqual ( null ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2021-07-12 17:41:02 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should not change validity state if control is disabled while async validating' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( 'value' , [ asyncValidator ( 'expected' ) ] ) ;
c . disable ( ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . status ) . toEqual ( 'DISABLED' ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should check presence of and remove a validator set in the control constructor' , ( ) = > {
const asyncVal = asyncValidator ( 'expected' ) ;
const c = new FormControl ( '' , null , asyncVal ) ;
expect ( c . hasAsyncValidator ( asyncVal ) ) . toEqual ( true ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
c . removeAsyncValidators ( asyncVal ) ;
expect ( c . hasAsyncValidator ( asyncVal ) ) . toEqual ( false ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
c . addAsyncValidators ( asyncVal ) ;
expect ( c . hasAsyncValidator ( asyncVal ) ) . toEqual ( true ) ;
} ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should check presence of and remove a validator set with addValidators' , ( ) = > {
const c = new FormControl ( '' ) ;
const asyncVal = asyncValidator ( 'expected' ) ;
c . addAsyncValidators ( asyncVal ) ;
expect ( c . hasAsyncValidator ( asyncVal ) ) . toEqual ( true ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
c . removeAsyncValidators ( asyncVal ) ;
expect ( c . hasAsyncValidator ( asyncVal ) ) . toEqual ( false ) ;
} ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should check presence of and remove multiple validators set at the same time' , ( ) = > {
const c = new FormControl ( '3' ) ;
const asyncVal1 = asyncValidator ( 'expected1' ) ;
const asyncVal2 = asyncValidator ( 'expected2' ) ;
c . addAsyncValidators ( [ asyncVal1 , asyncVal2 ] ) ;
expect ( c . hasAsyncValidator ( asyncVal1 ) ) . toEqual ( true ) ;
expect ( c . hasAsyncValidator ( asyncVal2 ) ) . toEqual ( true ) ;
c . removeAsyncValidators ( [ asyncVal1 , asyncVal2 ] ) ;
expect ( c . hasAsyncValidator ( asyncVal1 ) ) . toEqual ( false ) ;
expect ( c . hasAsyncValidator ( asyncVal2 ) ) . toEqual ( false ) ;
} ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should be able to remove a validator added multiple times' , ( ) = > {
const asyncVal = asyncValidator ( 'expected' ) ;
const c = new FormControl ( '' , null , asyncVal ) ;
c . addAsyncValidators ( asyncVal ) ;
c . addAsyncValidators ( asyncVal ) ;
expect ( c . hasAsyncValidator ( asyncVal ) ) . toEqual ( true ) ;
2021-07-12 17:41:02 +00:00
2024-04-18 17:29:04 +00:00
c . removeAsyncValidators ( asyncVal ) ;
expect ( c . hasAsyncValidator ( asyncVal ) ) . toEqual ( false ) ;
} ) ;
2020-04-06 22:44:00 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should return false when checking presence of a validator not identical by reference' , ( ) = > {
const asyncVal = asyncValidator ( 'expected' ) ;
const asyncValDifferentFn = asyncValidator ( 'expected' ) ;
const c = new FormControl ( '1' , null , asyncVal ) ;
expect ( c . hasAsyncValidator ( asyncVal ) ) . toEqual ( true ) ;
expect ( c . hasAsyncValidator ( asyncValDifferentFn ) ) . toEqual ( false ) ;
} ) ;
2016-08-14 00:26:08 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
describe ( 'dirty' , ( ) = > {
it ( 'should be false after creating a control' , ( ) = > {
const c = new FormControl ( 'value' ) ;
expect ( c . dirty ) . toEqual ( false ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should be true after changing the value of the control' , ( ) = > {
const c = new FormControl ( 'value' ) ;
c . markAsDirty ( ) ;
expect ( c . dirty ) . toEqual ( true ) ;
} ) ;
2016-08-14 00:26:08 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
describe ( 'touched' , ( ) = > {
it ( 'should be false after creating a control' , ( ) = > {
const c = new FormControl ( 'value' ) ;
expect ( c . touched ) . toEqual ( false ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should be true after markAsTouched runs' , ( ) = > {
const c = new FormControl ( 'value' ) ;
c . markAsTouched ( ) ;
expect ( c . touched ) . toEqual ( true ) ;
} ) ;
2016-08-14 00:26:08 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
describe ( 'setValue' , ( ) = > {
let g : FormGroup , c : FormControl ;
beforeEach ( ( ) = > {
c = new FormControl ( 'oldValue' ) ;
g = new FormGroup ( { 'one' : c } ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should set the value of the control' , ( ) = > {
c . setValue ( 'newValue' ) ;
expect ( c . value ) . toEqual ( 'newValue' ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should invoke ngOnChanges if it is present' , ( ) = > {
let ngOnChanges : any ;
c . registerOnChange ( ( v : any ) = > ( ngOnChanges = [ 'invoked' , v ] ) ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'newValue' ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( ngOnChanges ) . toEqual ( [ 'invoked' , 'newValue' ] ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not invoke on change when explicitly specified' , ( ) = > {
let onChange : any = null ;
c . registerOnChange ( ( v : any ) = > ( onChange = [ 'invoked' , v ] ) ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'newValue' , { emitModelToViewChange : false } ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( onChange ) . toBeNull ( ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should set the parent' , ( ) = > {
c . setValue ( 'newValue' ) ;
expect ( g . value ) . toEqual ( { 'one' : 'newValue' } ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not set the parent when explicitly specified' , ( ) = > {
c . setValue ( 'newValue' , { onlySelf : true } ) ;
expect ( g . value ) . toEqual ( { 'one' : 'oldValue' } ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should fire an event' , async ( ) = > {
2024-04-18 17:29:04 +00:00
c . valueChanges . subscribe ( ( value ) = > {
expect ( value ) . toEqual ( 'newValue' ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'newValue' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should not fire an event when explicitly specified' , async ( ) = > {
2024-04-18 17:29:04 +00:00
c . valueChanges . subscribe ( ( value ) = > {
throw 'Should not happen' ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'newValue' , { emitEvent : false } ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should work on a disabled control' , ( ) = > {
g . addControl ( 'two' , new FormControl ( 'two' ) ) ;
c . disable ( ) ;
c . setValue ( 'new value' ) ;
expect ( c . value ) . toEqual ( 'new value' ) ;
expect ( g . value ) . toEqual ( { 'two' : 'two' } ) ;
} ) ;
2016-08-14 00:26:08 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
describe ( 'patchValue' , ( ) = > {
let g : FormGroup , c : FormControl ;
beforeEach ( ( ) = > {
c = new FormControl ( 'oldValue' ) ;
g = new FormGroup ( { 'one' : c } ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should set the value of the control' , ( ) = > {
c . patchValue ( 'newValue' ) ;
expect ( c . value ) . toEqual ( 'newValue' ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should invoke ngOnChanges if it is present' , ( ) = > {
let ngOnChanges : any ;
c . registerOnChange ( ( v : any ) = > ( ngOnChanges = [ 'invoked' , v ] ) ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . patchValue ( 'newValue' ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( ngOnChanges ) . toEqual ( [ 'invoked' , 'newValue' ] ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not invoke on change when explicitly specified' , ( ) = > {
let onChange : any = null ;
c . registerOnChange ( ( v : any ) = > ( onChange = [ 'invoked' , v ] ) ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . patchValue ( 'newValue' , { emitModelToViewChange : false } ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( onChange ) . toBeNull ( ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should set the parent' , ( ) = > {
c . patchValue ( 'newValue' ) ;
expect ( g . value ) . toEqual ( { 'one' : 'newValue' } ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not set the parent when explicitly specified' , ( ) = > {
c . patchValue ( 'newValue' , { onlySelf : true } ) ;
expect ( g . value ) . toEqual ( { 'one' : 'oldValue' } ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should fire an event' , async ( ) = > {
2024-04-18 17:29:04 +00:00
c . valueChanges . subscribe ( ( value ) = > {
expect ( value ) . toEqual ( 'newValue' ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . patchValue ( 'newValue' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should not fire an event when explicitly specified' , async ( ) = > {
2024-04-18 17:29:04 +00:00
c . valueChanges . subscribe ( ( value ) = > {
throw 'Should not happen' ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . patchValue ( 'newValue' , { emitEvent : false } ) ;
2016-08-24 23:58:43 +00:00
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should patch value on a disabled control' , ( ) = > {
g . addControl ( 'two' , new FormControl ( 'two' ) ) ;
c . disable ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . patchValue ( 'new value' ) ;
expect ( c . value ) . toEqual ( 'new value' ) ;
expect ( g . value ) . toEqual ( { 'two' : 'two' } ) ;
} ) ;
2020-04-06 22:44:00 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
describe ( 'reset()' , ( ) = > {
let c : FormControl ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
beforeEach ( ( ) = > {
c = new FormControl ( 'initial value' ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should reset to a specific value if passed' , ( ) = > {
c . setValue ( 'new value' ) ;
expect ( c . value ) . toBe ( 'new value' ) ;
2016-10-18 05:51:13 +00:00
2024-04-18 17:29:04 +00:00
c . reset ( 'initial value' ) ;
expect ( c . value ) . toBe ( 'initial value' ) ;
} ) ;
2021-12-10 21:56:17 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not set the parent when explicitly specified' , ( ) = > {
const g = new FormGroup ( { 'one' : c } ) ;
c . patchValue ( 'newValue' , { onlySelf : true } ) ;
expect ( g . value ) . toEqual ( { 'one' : 'initial value' } ) ;
} ) ;
2021-12-10 21:56:17 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should reset to a specific value if passed with boxed value' , ( ) = > {
c . setValue ( 'new value' ) ;
expect ( c . value ) . toBe ( 'new value' ) ;
2021-12-10 21:56:17 +00:00
2024-04-18 17:29:04 +00:00
c . reset ( { value : 'initial value' , disabled : false } ) ;
expect ( c . value ) . toBe ( 'initial value' ) ;
} ) ;
2021-12-10 21:56:17 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should clear the control value if no value is passed' , ( ) = > {
c . setValue ( 'new value' ) ;
expect ( c . value ) . toBe ( 'new value' ) ;
2021-12-10 21:56:17 +00:00
2024-04-18 17:29:04 +00:00
c . reset ( ) ;
expect ( c . value ) . toBe ( null ) ;
} ) ;
2021-12-10 21:56:17 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should reset to the initial value if specified in FormControlOptions' , ( ) = > {
const c2 = new FormControl ( 'foo' , { nonNullable : true } ) ;
expect ( c2 . value ) . toBe ( 'foo' ) ;
expect ( c2 . defaultValue ) . toBe ( 'foo' ) ;
2021-12-10 21:56:17 +00:00
2024-04-18 17:29:04 +00:00
c2 . setValue ( 'bar' ) ;
expect ( c2 . value ) . toBe ( 'bar' ) ;
expect ( c2 . defaultValue ) . toBe ( 'foo' ) ;
2021-12-10 21:56:17 +00:00
2024-04-18 17:29:04 +00:00
c2 . reset ( ) ;
expect ( c2 . value ) . toBe ( 'foo' ) ;
expect ( c2 . defaultValue ) . toBe ( 'foo' ) ;
2021-12-10 21:56:17 +00:00
2025-09-10 16:56:37 +00:00
c2 . reset ( 'baz' , { overwriteDefaultValue : true } ) ;
expect ( c2 . value ) . toBe ( 'baz' ) ;
expect ( c2 . defaultValue ) . toBe ( 'baz' ) ;
2024-04-18 17:29:04 +00:00
const c3 = new FormControl ( 'foo' , { nonNullable : false } ) ;
expect ( c3 . value ) . toBe ( 'foo' ) ;
expect ( c3 . defaultValue ) . toBe ( null ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c3 . setValue ( 'bar' ) ;
expect ( c3 . value ) . toBe ( 'bar' ) ;
expect ( c3 . defaultValue ) . toBe ( null ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c3 . reset ( ) ;
expect ( c3 . value ) . toBe ( null ) ;
expect ( c3 . defaultValue ) . toBe ( null ) ;
2025-09-10 16:56:37 +00:00
c3 . reset ( 'baz' , { overwriteDefaultValue : true } ) ;
expect ( c3 . value ) . toBe ( 'baz' ) ;
expect ( c3 . defaultValue ) . toBe ( 'baz' ) ;
2024-04-18 17:29:04 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should look inside FormState objects for a default value' , ( ) = > {
const c2 = new FormControl ( { value : 'foo' , disabled : false } , { initialValueIsDefault : true } ) ;
expect ( c2 . value ) . toBe ( 'foo' ) ;
expect ( c2 . defaultValue ) . toBe ( 'foo' ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c2 . setValue ( 'bar' ) ;
expect ( c2 . value ) . toBe ( 'bar' ) ;
expect ( c2 . defaultValue ) . toBe ( 'foo' ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c2 . reset ( ) ;
expect ( c2 . value ) . toBe ( 'foo' ) ;
expect ( c2 . defaultValue ) . toBe ( 'foo' ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not alter the disabled state when resetting, even if a default value is provided' , ( ) = > {
const c2 = new FormControl ( { value : 'foo' , disabled : true } , { nonNullable : true } ) ;
expect ( c2 . value ) . toBe ( 'foo' ) ;
expect ( c2 . defaultValue ) . toBe ( 'foo' ) ;
expect ( c2 . disabled ) . toBe ( true ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c2 . setValue ( 'bar' ) ;
c2 . enable ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c2 . reset ( ) ;
expect ( c2 . value ) . toBe ( 'foo' ) ;
expect ( c2 . defaultValue ) . toBe ( 'foo' ) ;
expect ( c2 . disabled ) . toBe ( false ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should update the value of any parent controls with passed value' , ( ) = > {
const g = new FormGroup ( { 'one' : c } ) ;
c . setValue ( 'new value' ) ;
expect ( g . value ) . toEqual ( { 'one' : 'new value' } ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . reset ( 'initial value' ) ;
expect ( g . value ) . toEqual ( { 'one' : 'initial value' } ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should update the value of any parent controls with null value' , ( ) = > {
const g = new FormGroup ( { 'one' : c } ) ;
c . setValue ( 'new value' ) ;
expect ( g . value ) . toEqual ( { 'one' : 'new value' } ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . reset ( ) ;
expect ( g . value ) . toEqual ( { 'one' : null } ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should mark the control as pristine' , ( ) = > {
c . markAsDirty ( ) ;
expect ( c . pristine ) . toBe ( false ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . reset ( ) ;
expect ( c . pristine ) . toBe ( true ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should set the parent pristine state if all pristine' , ( ) = > {
const g = new FormGroup ( { 'one' : c } ) ;
c . markAsDirty ( ) ;
expect ( g . pristine ) . toBe ( false ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . reset ( ) ;
expect ( g . pristine ) . toBe ( true ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not set the parent pristine state if it has other dirty controls' , ( ) = > {
const c2 = new FormControl ( 'two' ) ;
const g = new FormGroup ( { 'one' : c , 'two' : c2 } ) ;
c . markAsDirty ( ) ;
c2 . markAsDirty ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . reset ( ) ;
expect ( g . pristine ) . toBe ( false ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should mark the control as untouched' , ( ) = > {
c . markAsTouched ( ) ;
expect ( c . untouched ) . toBe ( false ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . reset ( ) ;
expect ( c . untouched ) . toBe ( true ) ;
2016-08-24 23:58:43 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
it ( 'should set the parent untouched state if all untouched' , ( ) = > {
const g = new FormGroup ( { 'one' : c } ) ;
c . markAsTouched ( ) ;
expect ( g . untouched ) . toBe ( false ) ;
2016-08-24 23:58:43 +00:00
2020-04-06 22:44:00 +00:00
c . reset ( ) ;
2024-04-18 17:29:04 +00:00
expect ( g . untouched ) . toBe ( true ) ;
2016-08-24 23:58:43 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
it ( 'should not set the parent untouched state if other touched controls' , ( ) = > {
const c2 = new FormControl ( 'two' ) ;
const g = new FormGroup ( { 'one' : c , 'two' : c2 } ) ;
c . markAsTouched ( ) ;
c2 . markAsTouched ( ) ;
2016-08-14 00:26:08 +00:00
2020-04-06 22:44:00 +00:00
c . reset ( ) ;
2024-04-18 17:29:04 +00:00
expect ( g . untouched ) . toBe ( false ) ;
2020-04-06 22:44:00 +00:00
} ) ;
2016-10-19 16:54:54 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should retain the disabled state of the control' , ( ) = > {
c . disable ( ) ;
c . reset ( ) ;
2016-10-19 16:54:54 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . disabled ) . toBe ( true ) ;
2020-04-06 22:44:00 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should set disabled state based on boxed value if passed' , ( ) = > {
c . disable ( ) ;
c . reset ( { value : null , disabled : false } ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . disabled ) . toBe ( false ) ;
2021-05-23 20:16:02 +00:00
} ) ;
2020-04-06 22:44:00 +00:00
2024-04-18 17:29:04 +00:00
describe ( 'reset() events' , ( ) = > {
let g : FormGroup , c2 : FormControl , logger : any [ ] ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
beforeEach ( ( ) = > {
c2 = new FormControl ( 'two' ) ;
g = new FormGroup ( { 'one' : c , 'two' : c2 } ) ;
logger = [ ] ;
} ) ;
2020-04-06 22:44:00 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should emit one valueChange event per reset control' , ( ) = > {
g . valueChanges . subscribe ( ( ) = > logger . push ( 'group' ) ) ;
c . valueChanges . subscribe ( ( ) = > logger . push ( 'control1' ) ) ;
c2 . valueChanges . subscribe ( ( ) = > logger . push ( 'control2' ) ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . reset ( ) ;
expect ( logger ) . toEqual ( [ 'control1' , 'group' ] ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should not fire an event when explicitly specified' , async ( ) = > {
2024-04-18 17:29:04 +00:00
g . valueChanges . subscribe ( ( value ) = > {
throw 'Should not happen' ;
} ) ;
c . valueChanges . subscribe ( ( value ) = > {
throw 'Should not happen' ;
} ) ;
c2 . valueChanges . subscribe ( ( value ) = > {
throw 'Should not happen' ;
} ) ;
c . reset ( null , { emitEvent : false } ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
} ) ;
2024-04-18 17:29:04 +00:00
it ( 'should emit one statusChange event per reset control' , ( ) = > {
g . statusChanges . subscribe ( ( ) = > logger . push ( 'group' ) ) ;
c . statusChanges . subscribe ( ( ) = > logger . push ( 'control1' ) ) ;
c2 . statusChanges . subscribe ( ( ) = > logger . push ( 'control2' ) ) ;
c . reset ( ) ;
expect ( logger ) . toEqual ( [ 'control1' , 'group' ] ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should emit one statusChange event per disabled control' , ( ) = > {
g . statusChanges . subscribe ( ( ) = > logger . push ( 'group' ) ) ;
c . statusChanges . subscribe ( ( ) = > logger . push ( 'control1' ) ) ;
c2 . statusChanges . subscribe ( ( ) = > logger . push ( 'control2' ) ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . reset ( { value : null , disabled : true } ) ;
expect ( logger ) . toEqual ( [ 'control1' , 'group' ] ) ;
} ) ;
} ) ;
2020-04-06 22:44:00 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
describe ( 'valueChanges & statusChanges' , ( ) = > {
let c : FormControl ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
beforeEach ( ( ) = > {
c = new FormControl ( 'old' , Validators . required ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should fire an event after the value has been updated' , ( done ) = > {
c . valueChanges . subscribe ( {
next : ( value : any ) = > {
expect ( c . value ) . toEqual ( 'new' ) ;
expect ( value ) . toEqual ( 'new' ) ;
done ( ) ;
} ,
} ) ;
c . setValue ( 'new' ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should fire an event after the status has been updated to invalid' , async ( ) = > {
2024-04-18 17:29:04 +00:00
c . statusChanges . subscribe ( {
next : ( status : any ) = > {
expect ( c . status ) . toEqual ( 'INVALID' ) ;
expect ( status ) . toEqual ( 'INVALID' ) ;
} ,
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( '' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should fire statusChanges events for async validators added via options object' , async ( ) = > {
2024-04-18 17:29:04 +00:00
// The behavior can be tested for each of the model types.
let statuses : string [ ] = [ ] ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
// Create a form control with an async validator added via options object.
const asc = new FormControl ( '' , { asyncValidators : [ ( ) = > Promise . resolve ( null ) ] } ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
// Subscribe to status changes.
asc . statusChanges . subscribe ( ( status : any ) = > statuses . push ( status ) ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
// After a tick, the async validator should change status PENDING -> VALID.
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( statuses ) . toEqual ( [ 'VALID' ] ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should fire an event after the status has been updated to pending' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( 'old' , Validators . required , asyncValidator ( 'expected' ) ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
const log : string [ ] = [ ] ;
c . valueChanges . subscribe ( { next : ( value : any ) = > log . push ( ` value: ' ${ value } ' ` ) } ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . statusChanges . subscribe ( { next : ( status : any ) = > log . push ( ` status: ' ${ status } ' ` ) } ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( '' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'nonEmpty' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'expected' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( log ) . toEqual ( [
"value: ''" ,
"status: 'INVALID'" ,
"value: 'nonEmpty'" ,
"status: 'PENDING'" ,
"status: 'INVALID'" ,
"value: 'expected'" ,
"status: 'PENDING'" ,
"status: 'VALID'" ,
] ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should update set errors and status before emitting an event' , async ( ) = > {
2024-04-18 17:29:04 +00:00
c . setValue ( '' ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( false ) ;
expect ( c . errors ) . toEqual ( { 'required' : true } ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2026-02-04 04:51:54 +00:00
it ( 'should return a cold observable' , async ( ) = > {
2024-04-18 17:29:04 +00:00
let value : string | null = null ;
c . setValue ( 'will be ignored' ) ;
c . valueChanges . subscribe ( ( v ) = > ( value = v ) ) ;
c . setValue ( 'new' ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
// @ts-expect-error see microsoft/TypeScript#9998
expect ( value ) . toEqual ( 'new' ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2020-04-06 22:44:00 +00:00
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
describe ( 'setErrors' , ( ) = > {
it ( 'should set errors on a control' , ( ) = > {
const c = new FormControl ( 'someValue' ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setErrors ( { 'someError' : true } ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . valid ) . toEqual ( false ) ;
expect ( c . errors ) . toEqual ( { 'someError' : true } ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should reset the errors and validity when the value changes' , ( ) = > {
const c = new FormControl ( 'someValue' , Validators . required ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
c . setErrors ( { 'someError' : true } ) ;
c . setValue ( '' ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . errors ) . toEqual ( { 'required' : true } ) ;
} ) ;
2016-08-14 00:26:08 +00:00
2024-04-18 17:29:04 +00:00
it ( "should update the parent group's validity" , ( ) = > {
const c = new FormControl ( 'someValue' ) ;
const g = new FormGroup ( { 'one' : c } ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
expect ( g . valid ) . toEqual ( true ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . setErrors ( { 'someError' : true } ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
expect ( g . valid ) . toEqual ( false ) ;
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
it ( "should not reset parent's errors" , ( ) = > {
const c = new FormControl ( 'someValue' ) ;
const g = new FormGroup ( { 'one' : c } ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
g . setErrors ( { 'someGroupError' : true } ) ;
c . setErrors ( { 'someError' : true } ) ;
expect ( g . errors ) . toEqual ( { 'someGroupError' : true } ) ;
} ) ;
it ( 'should reset errors when updating a value' , ( ) = > {
const c = new FormControl ( 'oldValue' ) ;
const g = new FormGroup ( { 'one' : c } ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
g . setErrors ( { 'someGroupError' : true } ) ;
c . setErrors ( { 'someError' : true } ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'newValue' ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
expect ( c . errors ) . toEqual ( null ) ;
expect ( g . errors ) . toEqual ( null ) ;
} ) ;
2020-04-06 22:44:00 +00:00
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
describe ( 'disable() & enable()' , ( ) = > {
it ( 'should mark the control as disabled' , ( ) = > {
const c = new FormControl ( null ) ;
expect ( c . disabled ) . toBe ( false ) ;
expect ( c . valid ) . toBe ( true ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . disable ( ) ;
expect ( c . disabled ) . toBe ( true ) ;
expect ( c . valid ) . toBe ( false ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . enable ( ) ;
expect ( c . disabled ) . toBe ( false ) ;
expect ( c . valid ) . toBe ( true ) ;
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should set the control status as disabled' , ( ) = > {
const c = new FormControl ( null ) ;
expect ( c . status ) . toEqual ( 'VALID' ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . disable ( ) ;
expect ( c . status ) . toEqual ( 'DISABLED' ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . enable ( ) ;
expect ( c . status ) . toEqual ( 'VALID' ) ;
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should retain the original value when disabled' , ( ) = > {
const c = new FormControl ( 'some value' ) ;
expect ( c . value ) . toEqual ( 'some value' ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . disable ( ) ;
expect ( c . value ) . toEqual ( 'some value' ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . enable ( ) ;
expect ( c . value ) . toEqual ( 'some value' ) ;
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should keep the disabled control in the group, but return false for contains()' , ( ) = > {
const c = new FormControl ( '' ) ;
const g = new FormGroup ( { 'one' : c } ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
expect ( g . get ( 'one' ) ) . toBeDefined ( ) ;
expect ( g . contains ( 'one' ) ) . toBe ( true ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . disable ( ) ;
expect ( g . get ( 'one' ) ) . toBeDefined ( ) ;
expect ( g . contains ( 'one' ) ) . toBe ( false ) ;
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should mark the parent group disabled if all controls are disabled' , ( ) = > {
const c = new FormControl ( ) ;
const c2 = new FormControl ( ) ;
const g = new FormGroup ( { 'one' : c , 'two' : c2 } ) ;
expect ( g . enabled ) . toBe ( true ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . disable ( ) ;
expect ( g . enabled ) . toBe ( true ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c2 . disable ( ) ;
expect ( g . enabled ) . toBe ( false ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . enable ( ) ;
expect ( g . enabled ) . toBe ( true ) ;
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should update the parent group value when child control status changes' , ( ) = > {
const c = new FormControl ( 'one' ) ;
const c2 = new FormControl ( 'two' ) ;
const g = new FormGroup ( { 'one' : c , 'two' : c2 } ) ;
expect ( g . value ) . toEqual ( { 'one' : 'one' , 'two' : 'two' } ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . disable ( ) ;
expect ( g . value ) . toEqual ( { 'two' : 'two' } ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c2 . disable ( ) ;
expect ( g . value ) . toEqual ( { 'one' : 'one' , 'two' : 'two' } ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . enable ( ) ;
expect ( g . value ) . toEqual ( { 'one' : 'one' } ) ;
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should mark the parent array disabled if all controls are disabled' , ( ) = > {
const c = new FormControl ( ) ;
const c2 = new FormControl ( ) ;
const a = new FormArray ( [ c , c2 ] ) ;
expect ( a . enabled ) . toBe ( true ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . disable ( ) ;
expect ( a . enabled ) . toBe ( true ) ;
2018-06-20 15:16:42 +00:00
2024-04-18 17:29:04 +00:00
c2 . disable ( ) ;
expect ( a . enabled ) . toBe ( false ) ;
c . enable ( ) ;
expect ( a . enabled ) . toBe ( true ) ;
} ) ;
2018-06-20 15:16:42 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should update the parent array value when child control status changes' , ( ) = > {
const c = new FormControl ( 'one' ) ;
const c2 = new FormControl ( 'two' ) ;
const a = new FormArray ( [ c , c2 ] ) ;
expect ( a . value ) . toEqual ( [ 'one' , 'two' ] ) ;
2018-06-20 15:16:42 +00:00
2024-04-18 17:29:04 +00:00
c . disable ( ) ;
expect ( a . value ) . toEqual ( [ 'two' ] ) ;
2018-06-20 15:16:42 +00:00
2024-04-18 17:29:04 +00:00
c2 . disable ( ) ;
expect ( a . value ) . toEqual ( [ 'one' , 'two' ] ) ;
2018-06-20 15:16:42 +00:00
2024-04-18 17:29:04 +00:00
c . enable ( ) ;
expect ( a . value ) . toEqual ( [ 'one' ] ) ;
} ) ;
2018-06-20 15:16:42 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should ignore disabled array controls when determining dirtiness' , ( ) = > {
const c = new FormControl ( 'one' ) ;
const c2 = new FormControl ( 'two' ) ;
const a = new FormArray ( [ c , c2 ] ) ;
c . markAsDirty ( ) ;
expect ( a . dirty ) . toBe ( true ) ;
2018-06-20 15:16:42 +00:00
2024-04-18 17:29:04 +00:00
c . disable ( ) ;
expect ( c . dirty ) . toBe ( true ) ;
expect ( a . dirty ) . toBe ( false ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . enable ( ) ;
expect ( a . dirty ) . toBe ( true ) ;
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not make a dirty array not dirty when disabling controls' , ( ) = > {
const c = new FormControl ( 'one' ) ;
const c2 = new FormControl ( 'two' ) ;
const a = new FormArray ( [ c , c2 ] ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
a . markAsDirty ( ) ;
expect ( a . dirty ) . toBe ( true ) ;
expect ( c . dirty ) . toBe ( false ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . disable ( ) ;
expect ( a . dirty ) . toBe ( true ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . enable ( ) ;
expect ( a . dirty ) . toBe ( true ) ;
} ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should ignore disabled controls in validation' , ( ) = > {
const c = new FormControl ( null , Validators . required ) ;
const c2 = new FormControl ( null ) ;
const g = new FormGroup ( { one : c , two : c2 } ) ;
expect ( g . valid ) . toBe ( false ) ;
2016-08-24 23:58:43 +00:00
c . disable ( ) ;
2024-04-18 17:29:04 +00:00
expect ( g . valid ) . toBe ( true ) ;
2016-08-24 23:58:43 +00:00
c . enable ( ) ;
2024-04-18 17:29:04 +00:00
expect ( g . valid ) . toBe ( false ) ;
2016-08-24 23:58:43 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
it ( 'should ignore disabled controls when serializing value in a group' , ( ) = > {
const c = new FormControl ( 'one' ) ;
const c2 = new FormControl ( 'two' ) ;
const g = new FormGroup ( { one : c , two : c2 } ) ;
expect ( g . value ) . toEqual ( { one : 'one' , two : 'two' } ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . disable ( ) ;
expect ( g . value ) . toEqual ( { two : 'two' } ) ;
2018-06-20 15:16:42 +00:00
2024-04-18 17:29:04 +00:00
c . enable ( ) ;
expect ( g . value ) . toEqual ( { one : 'one' , two : 'two' } ) ;
} ) ;
2018-06-20 15:16:42 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should ignore disabled controls when serializing value in an array' , ( ) = > {
const c = new FormControl ( 'one' ) ;
const c2 = new FormControl ( 'two' ) ;
const a = new FormArray ( [ c , c2 ] ) ;
expect ( a . value ) . toEqual ( [ 'one' , 'two' ] ) ;
2018-06-20 15:16:42 +00:00
2024-04-18 17:29:04 +00:00
c . disable ( ) ;
expect ( a . value ) . toEqual ( [ 'two' ] ) ;
c . enable ( ) ;
expect ( a . value ) . toEqual ( [ 'one' , 'two' ] ) ;
2018-06-20 15:16:42 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
it ( 'should ignore disabled controls when determining dirtiness' , ( ) = > {
const c = new FormControl ( 'one' ) ;
const c2 = new FormControl ( 'two' ) ;
const g = new FormGroup ( { one : c , two : c2 } ) ;
c . markAsDirty ( ) ;
expect ( g . dirty ) . toBe ( true ) ;
2016-08-24 23:58:43 +00:00
c . disable ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . dirty ) . toBe ( true ) ;
expect ( g . dirty ) . toBe ( false ) ;
2016-08-24 23:58:43 +00:00
c . enable ( ) ;
2024-04-18 17:29:04 +00:00
expect ( g . dirty ) . toBe ( true ) ;
2016-08-24 23:58:43 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
it ( 'should not make a dirty group not dirty when disabling controls' , ( ) = > {
const c = new FormControl ( 'one' ) ;
const c2 = new FormControl ( 'two' ) ;
const g = new FormGroup ( { one : c , two : c2 } ) ;
g . markAsDirty ( ) ;
expect ( g . dirty ) . toBe ( true ) ;
expect ( c . dirty ) . toBe ( false ) ;
2016-09-09 19:00:38 +00:00
c . disable ( ) ;
2024-04-18 17:29:04 +00:00
expect ( g . dirty ) . toBe ( true ) ;
c . enable ( ) ;
expect ( g . dirty ) . toBe ( true ) ;
2016-09-09 19:00:38 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
it ( 'should ignore disabled controls when determining touched state' , ( ) = > {
const c = new FormControl ( 'one' ) ;
const c2 = new FormControl ( 'two' ) ;
const g = new FormGroup ( { one : c , two : c2 } ) ;
c . markAsTouched ( ) ;
expect ( g . touched ) . toBe ( true ) ;
c . disable ( ) ;
expect ( c . touched ) . toBe ( true ) ;
expect ( g . touched ) . toBe ( false ) ;
c . enable ( ) ;
expect ( g . touched ) . toBe ( true ) ;
2016-09-09 19:00:38 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
it ( 'should not run validators on disabled controls' , ( ) = > {
const validator = jasmine . createSpy ( 'validator' ) ;
const c = new FormControl ( '' , validator ) ;
expect ( validator . calls . count ( ) ) . toEqual ( 1 ) ;
c . disable ( ) ;
expect ( validator . calls . count ( ) ) . toEqual ( 1 ) ;
2016-08-24 23:58:43 +00:00
2024-04-18 17:29:04 +00:00
c . setValue ( 'value' ) ;
expect ( validator . calls . count ( ) ) . toEqual ( 1 ) ;
c . enable ( ) ;
expect ( validator . calls . count ( ) ) . toEqual ( 2 ) ;
2020-04-06 22:44:00 +00:00
} ) ;
2017-01-22 08:37:22 +00:00
2024-04-18 17:29:04 +00:00
describe ( 'disabled errors' , ( ) = > {
it ( 'should clear out the errors when disabled' , ( ) = > {
const c = new FormControl ( '' , Validators . required ) ;
expect ( c . errors ) . toEqual ( { required : true } ) ;
c . disable ( ) ;
expect ( c . errors ) . toEqual ( null ) ;
c . enable ( ) ;
expect ( c . errors ) . toEqual ( { required : true } ) ;
} ) ;
2026-02-04 04:51:54 +00:00
it ( 'should clear out async errors when disabled' , async ( ) = > {
2024-04-18 17:29:04 +00:00
const c = new FormControl ( '' , null ! , asyncValidator ( 'expected' ) ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . errors ) . toEqual ( { 'async' : true } ) ;
c . disable ( ) ;
expect ( c . errors ) . toEqual ( null ) ;
2017-12-14 15:51:05 +00:00
2024-04-18 17:29:04 +00:00
c . enable ( ) ;
2026-02-04 04:51:54 +00:00
await timeout ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . errors ) . toEqual ( { 'async' : true } ) ;
2026-02-04 04:51:54 +00:00
} ) ;
2020-04-06 22:44:00 +00:00
} ) ;
2017-12-14 15:51:05 +00:00
2024-04-18 17:29:04 +00:00
describe ( 'disabled events' , ( ) = > {
let logger : string [ ] ;
let c : FormControl ;
let g : FormGroup ;
2017-12-14 15:51:05 +00:00
2024-04-18 17:29:04 +00:00
beforeEach ( ( ) = > {
logger = [ ] ;
c = new FormControl ( '' , Validators . required ) ;
g = new FormGroup ( { one : c } ) ;
} ) ;
2017-12-14 15:51:05 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should emit a statusChange event when disabled status changes' , ( ) = > {
c . statusChanges . subscribe ( ( status : string ) = > logger . push ( status ) ) ;
c . disable ( ) ;
expect ( logger ) . toEqual ( [ 'DISABLED' ] ) ;
c . enable ( ) ;
expect ( logger ) . toEqual ( [ 'DISABLED' , 'INVALID' ] ) ;
} ) ;
it ( 'should emit status change events in correct order' , ( ) = > {
c . statusChanges . subscribe ( ( ) = > logger . push ( 'control' ) ) ;
g . statusChanges . subscribe ( ( ) = > logger . push ( 'group' ) ) ;
c . disable ( ) ;
expect ( logger ) . toEqual ( [ 'control' , 'group' ] ) ;
} ) ;
it ( 'should throw when sync validator passed into async validator param' , ( ) = > {
const fn = ( ) = >
new FormControl ( '' , syncValidator , syncValidator as unknown as AsyncValidatorFn ) ;
// test for the specific error since without the error check it would still throw an error
// but
// not a meaningful one
expect ( fn ) . toThrowError (
2026-01-07 21:21:25 +00:00
/NG01101: Expected async validator to return Promise or Observable\. Are you using a synchronous validator where an async validator is expected\? Find more at https:\/\/(?:next\.)?angular\.dev\/errors\/NG01101/ ,
2024-04-18 17:29:04 +00:00
) ;
} ) ;
2017-11-06 08:59:09 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should not emit value change events when emitEvent = false' , ( ) = > {
c . valueChanges . subscribe ( ( ) = > logger . push ( 'control' ) ) ;
g . valueChanges . subscribe ( ( ) = > logger . push ( 'group' ) ) ;
c . disable ( { emitEvent : false } ) ;
expect ( logger ) . toEqual ( [ ] ) ;
c . enable ( { emitEvent : false } ) ;
expect ( logger ) . toEqual ( [ ] ) ;
} ) ;
it ( 'should not emit status change events when emitEvent = false' , ( ) = > {
c . statusChanges . subscribe ( ( ) = > logger . push ( 'control' ) ) ;
g . statusChanges . subscribe ( ( ) = > logger . push ( 'form' ) ) ;
c . disable ( { emitEvent : false } ) ;
expect ( logger ) . toEqual ( [ ] ) ;
c . enable ( { emitEvent : false } ) ;
expect ( logger ) . toEqual ( [ ] ) ;
} ) ;
} ) ;
} ) ;
describe ( 'pending' , ( ) = > {
let c : FormControl ;
2017-11-06 08:59:09 +00:00
2020-04-06 22:44:00 +00:00
beforeEach ( ( ) = > {
2024-04-18 17:29:04 +00:00
c = new FormControl ( 'value' ) ;
} ) ;
it ( 'should be false after creating a control' , ( ) = > {
expect ( c . pending ) . toEqual ( false ) ;
2020-04-06 22:44:00 +00:00
} ) ;
2017-11-06 08:59:09 +00:00
2024-04-18 17:29:04 +00:00
it ( 'should be true after changing the value of the control' , ( ) = > {
2017-11-06 08:59:09 +00:00
c . markAsPending ( ) ;
2024-04-18 17:29:04 +00:00
expect ( c . pending ) . toEqual ( true ) ;
2017-11-06 08:59:09 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
describe ( 'status change events' , ( ) = > {
let logger : string [ ] ;
beforeEach ( ( ) = > {
logger = [ ] ;
c . statusChanges . subscribe ( ( status ) = > logger . push ( status ) ) ;
} ) ;
it ( 'should emit event after marking control as pending' , ( ) = > {
c . markAsPending ( ) ;
expect ( logger ) . toEqual ( [ 'PENDING' ] ) ;
} ) ;
it ( 'should not emit event when emitEvent = false' , ( ) = > {
c . markAsPending ( { emitEvent : false } ) ;
expect ( logger ) . toEqual ( [ ] ) ;
} ) ;
2017-11-06 08:59:09 +00:00
} ) ;
} ) ;
2021-11-30 19:46:46 +00:00
2024-04-18 17:29:04 +00:00
describe ( 'can be extended' , ( ) = > {
// We don't technically support extending Forms classes, but people do it anyway.
// We need to make sure that there is some way to extend them to avoid causing breakage.
class FCExt extends FormControl {
constructor (
formState ? :
| any
| {
value? : any ;
disabled? : boolean ;
} ,
. . . args : any
) {
super ( formState , . . . args ) ;
}
2021-11-30 19:46:46 +00:00
}
2024-04-18 17:29:04 +00:00
it ( 'should perform basic FormControl operations' , ( ) = > {
const nc = new FCExt ( { value : 'foo' } ) ;
nc . setValue ( 'bar' ) ;
// There is no need to assert because, if this test compiles, then it is possible to correctly
// extend FormControl.
} ) ;
2021-11-30 19:46:46 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
describe ( 'inspecting the prototype still provides FormControl type' , ( ) = > {
// The constructor should be a function with a prototype property of T.
// (This is the assumption we don't want to break.)
type Constructor < T > = Function & { prototype : T } ;
2021-11-30 19:46:46 +00:00
2024-04-18 17:29:04 +00:00
function isInstanceOf < T > ( value : Constructor < T > , arg : unknown ) : arg is T {
// The implementation does not matter; we want to check whether this guard narrows the type.
return true ;
}
2021-11-30 19:46:46 +00:00
2024-04-18 17:29:04 +00:00
// This is a nullable FormControl, and we want isInstanceOf to narrow the type.
const fcOrNull : FormControl | null = new FormControl ( 42 ) ;
2021-11-30 19:46:46 +00:00
2024-04-18 17:29:04 +00:00
it ( 'and is appropriately narrowed' , ( ) = > {
if ( isInstanceOf ( FormControl , fcOrNull ) ) {
// If the guard does not work, then this code will not compile due to null being in the
// type.
fcOrNull . setValue ( 7 ) ;
}
} ) ;
2021-11-30 19:46:46 +00:00
} ) ;
2024-04-18 17:29:04 +00:00
describe ( 'Function.name' , ( ) = > {
it ( 'returns FormControl' , ( ) = > {
// This is always true in the trivial case, but can be broken by various methods of overriding
// FormControl's exported constructor.
expect ( FormControl . name ) . toBe ( 'FormControl' ) ;
} ) ;
2021-11-30 19:46:46 +00:00
} ) ;
} ) ;
2017-12-16 22:42:55 +00:00
} ) ( ) ;