@@ -14,8 +14,23 @@ import {
1414 type WritableSignal ,
1515} from '@angular/core' ;
1616import { FORM_FIELD_PARSE_ERRORS } from '../directive/parse_errors' ;
17+ import { createParser } from '../util/parser' ;
1718import type { ValidationError } from './rules' ;
1819
20+ /**
21+ * Result of parsing a raw value into a model value.
22+ */
23+ export interface ParseResult < TValue > {
24+ /**
25+ * The parsed value, if parsing was successful.
26+ */
27+ readonly value ?: TValue ;
28+ /**
29+ * Errors encountered during parsing, if any.
30+ */
31+ readonly errors ?: readonly ValidationError . WithoutFieldTree [ ] ;
32+ }
33+
1934/**
2035 * Options for `transformedValue`.
2136 *
@@ -29,7 +44,7 @@ export interface TransformedValueOptions<TValue, TRaw> {
2944 * - `value`: The parsed model value. If `undefined`, the model will not be updated.
3045 * - `errors`: Any parse errors encountered. If `undefined`, no errors are reported.
3146 */
32- parse : ( rawValue : TRaw ) => { value ?: TValue ; errors ?: readonly ValidationError . WithoutFieldTree [ ] } ;
47+ parse : ( rawValue : TRaw ) => ParseResult < TValue > ;
3348
3449 /**
3550 * Format the model value into the raw value.
@@ -92,38 +107,30 @@ export function transformedValue<TValue, TRaw>(
92107 options : TransformedValueOptions < TValue , TRaw > ,
93108) : TransformedValueSignal < TRaw > {
94109 const { parse, format} = options ;
110+ const parser = createParser ( value , value . set , parse ) ;
95111
96- const parseErrors = linkedSignal ( {
97- source : value ,
98- computation : ( ) => [ ] as readonly ValidationError . WithoutFieldTree [ ] ,
99- } ) ;
100- const rawValue = linkedSignal ( ( ) => format ( value ( ) ) ) ;
101-
112+ // Wire up the parse errors from the parser to the form field.
102113 const formFieldParseErrors = inject ( FORM_FIELD_PARSE_ERRORS , { self : true , optional : true } ) ;
103114 if ( formFieldParseErrors ) {
104- formFieldParseErrors . set ( parseErrors ) ;
115+ formFieldParseErrors . set ( parser . errors ) ;
105116 }
106117
107118 // Create the result signal with overridden set/update and a `parseErrors` property.
119+ const rawValue = linkedSignal ( ( ) => format ( value ( ) ) ) ;
108120 const result = rawValue as WritableSignal < TRaw > & {
109121 parseErrors : Signal < readonly ValidationError . WithoutFieldTree [ ] > ;
110122 } ;
123+ result . parseErrors = parser . errors ;
111124 const originalSet = result . set . bind ( result ) ;
112125
126+ // Notify the parser when `set` or `update` is called on the raw value
113127 result . set = ( newRawValue : TRaw ) => {
114- const result = parse ( newRawValue ) ;
115- parseErrors . set ( result . errors ?? [ ] ) ;
116- if ( result . value !== undefined ) {
117- value . set ( result . value ) ;
118- }
128+ parser . setRawValue ( newRawValue ) ;
119129 originalSet ( newRawValue ) ;
120130 } ;
121-
122131 result . update = ( updateFn : ( value : TRaw ) => TRaw ) => {
123132 result . set ( updateFn ( rawValue ( ) ) ) ;
124133 } ;
125134
126- result . parseErrors = parseErrors . asReadonly ( ) ;
127-
128135 return result ;
129136}
0 commit comments