@@ -25,20 +25,27 @@ import type {
2525import { RuntimeErrorCode } from './errors' ;
2626import type { AbstractControl } from './model/abstract_model' ;
2727
28- function isEmptyInputValue ( value : any ) : boolean {
29- /**
30- * Check if the object is a string or array before evaluating the length attribute.
31- * This avoids falsely rejecting objects that contain a custom length attribute.
32- * For example, the object {id: 1, length: 0, width: 0} should not be returned as empty.
33- */
34- return (
35- value == null || ( ( typeof value === 'string' || Array . isArray ( value ) ) && value . length === 0 )
36- ) ;
28+ function isEmptyInputValue ( value : unknown ) : boolean {
29+ return value == null || lengthOrSize ( value ) === 0 ;
3730}
3831
39- function hasValidLength ( value : any ) : boolean {
32+ /**
33+ * Extract the length property in case it's an array or a string.
34+ * Extract the size property in case it's a set.
35+ * Return null else.
36+ * @param value Either an array, set or undefined.
37+ */
38+ function lengthOrSize ( value : unknown ) : number | null {
4039 // non-strict comparison is intentional, to check for both `null` and `undefined` values
41- return value != null && typeof value . length === 'number' ;
40+ if ( value == null ) {
41+ return null ;
42+ } else if ( Array . isArray ( value ) || typeof value === 'string' ) {
43+ return value . length ;
44+ } else if ( value instanceof Set ) {
45+ return value . size ;
46+ }
47+
48+ return null ;
4249}
4350
4451/**
@@ -290,13 +297,14 @@ export class Validators {
290297
291298 /**
292299 * @description
293- * Validator that requires the length of the control's value to be greater than or equal
294- * to the provided minimum length. This validator is also provided by default if you use the
300+ * Validator that requires the number of items in the control's value to be greater than or equal
301+ * to the provided minimum length. This validator is also provided by default if you use
295302 * the HTML5 `minlength` attribute. Note that the `minLength` validator is intended to be used
296- * only for types that have a numeric `length` property, such as strings or arrays. The
297- * `minLength` validator logic is also not invoked for values when their `length` property is 0
298- * (for example in case of an empty string or an empty array), to support optional controls. You
299- * can use the standard `required` validator if empty values should not be considered valid.
303+ * only for types that have a numeric `length` or `size` property, such as strings, arrays or
304+ * sets. The `minLength` validator logic is also not invoked for values when their `length` or
305+ * `size` property is 0 (for example in case of an empty string or an empty array), to support
306+ * optional controls. You can use the standard `required` validator if empty values should not be
307+ * considered valid.
300308 *
301309 * @usageNotes
302310 *
@@ -324,10 +332,11 @@ export class Validators {
324332
325333 /**
326334 * @description
327- * Validator that requires the length of the control's value to be less than or equal
328- * to the provided maximum length. This validator is also provided by default if you use the
335+ * Validator that requires the number of items in the control's value to be less than or equal
336+ * to the provided maximum length. This validator is also provided by default if you use
329337 * the HTML5 `maxlength` attribute. Note that the `maxLength` validator is intended to be used
330- * only for types that have a numeric `length` property, such as strings or arrays.
338+ * only for types that have a numeric `length` or `size` property, such as strings, arrays or
339+ * sets.
331340 *
332341 * @usageNotes
333342 *
@@ -456,7 +465,7 @@ export class Validators {
456465 */
457466export function minValidator ( min : number ) : ValidatorFn {
458467 return ( control : AbstractControl ) : ValidationErrors | null => {
459- if ( isEmptyInputValue ( control . value ) || isEmptyInputValue ( min ) ) {
468+ if ( control . value == null || min == null ) {
460469 return null ; // don't validate empty values to allow optional controls
461470 }
462471 const value = parseFloat ( control . value ) ;
@@ -472,7 +481,7 @@ export function minValidator(min: number): ValidatorFn {
472481 */
473482export function maxValidator ( max : number ) : ValidatorFn {
474483 return ( control : AbstractControl ) : ValidationErrors | null => {
475- if ( isEmptyInputValue ( control . value ) || isEmptyInputValue ( max ) ) {
484+ if ( control . value == null || max == null ) {
476485 return null ; // don't validate empty values to allow optional controls
477486 }
478487 const value = parseFloat ( control . value ) ;
@@ -511,32 +520,41 @@ export function emailValidator(control: AbstractControl): ValidationErrors | nul
511520}
512521
513522/**
514- * Validator that requires the length of the control's value to be greater than or equal
523+ * Validator that requires the number of items in the control's value to be greater than or equal
515524 * to the provided minimum length. See `Validators.minLength` for additional information.
525+ *
526+ * The minLengthValidator respects every length property in an object, regardless of whether it's an array.
527+ * For example, the object {id: 1, length: 0, width: 0} should be validated.
516528 */
517529export function minLengthValidator ( minLength : number ) : ValidatorFn {
518530 return ( control : AbstractControl ) : ValidationErrors | null => {
519- if ( isEmptyInputValue ( control . value ) || ! hasValidLength ( control . value ) ) {
531+ const length = control . value ?. length ?? lengthOrSize ( control . value ) ;
532+ if ( length === null || length === 0 ) {
520533 // don't validate empty values to allow optional controls
521- // don't validate values without `length` property
534+ // don't validate values without `length` or `size` property
522535 return null ;
523536 }
524537
525- return control . value . length < minLength
526- ? { 'minlength' : { 'requiredLength' : minLength , 'actualLength' : control . value . length } }
538+ return length < minLength
539+ ? { 'minlength' : { 'requiredLength' : minLength , 'actualLength' : length } }
527540 : null ;
528541 } ;
529542}
530543
531544/**
532- * Validator that requires the length of the control's value to be less than or equal
545+ * Validator that requires the number of items in the control's value to be less than or equal
533546 * to the provided maximum length. See `Validators.maxLength` for additional information.
547+ *
548+ * The maxLengthValidator respects every length property in an object, regardless of whether it's an array.
549+ * For example, the object {id: 1, length: 0, width: 0} should be validated.
534550 */
535551export function maxLengthValidator ( maxLength : number ) : ValidatorFn {
536552 return ( control : AbstractControl ) : ValidationErrors | null => {
537- return hasValidLength ( control . value ) && control . value . length > maxLength
538- ? { 'maxlength' : { 'requiredLength' : maxLength , 'actualLength' : control . value . length } }
539- : null ;
553+ const length = control . value ?. length ?? lengthOrSize ( control . value ) ;
554+ if ( length !== null && length > maxLength ) {
555+ return { 'maxlength' : { 'requiredLength' : maxLength , 'actualLength' : length } } ;
556+ }
557+ return null ;
540558 } ;
541559}
542560
0 commit comments