@@ -112,28 +112,35 @@ function formlyForm(formlyUsability, formlyWarn, $parse, formlyConfig, $interpol
112
112
setupFields ( )
113
113
114
114
// watch the model and evaluate watch expressions that depend on it.
115
- $scope . $watch ( 'model' , onModelOrFormStateChange , true )
115
+ if ( ! $scope . options . manualModelWatcher ) {
116
+ $scope . $watch ( 'model' , onModelOrFormStateChange , true )
117
+ } else if ( angular . isFunction ( $scope . options . manualModelWatcher ) ) {
118
+ $scope . $watch ( $scope . options . manualModelWatcher , onModelOrFormStateChange , true )
119
+ }
120
+
116
121
if ( $scope . options . formState ) {
117
122
$scope . $watch ( 'options.formState' , onModelOrFormStateChange , true )
118
123
}
119
124
120
125
function onModelOrFormStateChange ( ) {
121
- angular . forEach ( $scope . fields , function runFieldExpressionProperties ( field , index ) {
122
- const model = field . model || $scope . model
123
- const promise = field . runExpressions && field . runExpressions ( )
124
- if ( field . hideExpression ) { // can't use hide with expressionProperties reliably
125
- const val = model [ field . key ]
126
- field . hide = evalCloseToFormlyExpression ( field . hideExpression , val , field , index )
127
- }
128
- if ( field . extras && field . extras . validateOnModelChange && field . formControl ) {
129
- const validate = field . formControl . $validate
130
- if ( promise ) {
131
- promise . then ( validate )
132
- } else {
133
- validate ( )
134
- }
126
+ angular . forEach ( $scope . fields , runFieldExpressionProperties )
127
+ }
128
+
129
+ function runFieldExpressionProperties ( field , index ) {
130
+ const model = field . model || $scope . model
131
+ const promise = field . runExpressions && field . runExpressions ( )
132
+ if ( field . hideExpression ) { // can't use hide with expressionProperties reliably
133
+ const val = model [ field . key ]
134
+ field . hide = evalCloseToFormlyExpression ( field . hideExpression , val , field , index )
135
+ }
136
+ if ( field . extras && field . extras . validateOnModelChange && field . formControl ) {
137
+ const validate = field . formControl . $validate
138
+ if ( promise ) {
139
+ promise . then ( validate )
140
+ } else {
141
+ validate ( )
135
142
}
136
- } )
143
+ }
137
144
}
138
145
139
146
function setupFields ( ) {
@@ -158,6 +165,10 @@ function formlyForm(formlyUsability, formlyWarn, $parse, formlyConfig, $interpol
158
165
159
166
setupModels ( )
160
167
168
+ if ( $scope . options . watchAllExpressions ) {
169
+ angular . forEach ( $scope . fields , setupHideExpressionWatcher )
170
+ }
171
+
161
172
angular . forEach ( $scope . fields , attachKey ) // attaches a key based on the index if a key isn't specified
162
173
angular . forEach ( $scope . fields , setupWatchers ) // setup watchers for all fields
163
174
}
@@ -217,6 +228,8 @@ function formlyForm(formlyUsability, formlyWarn, $parse, formlyConfig, $interpol
217
228
function setupModels ( ) {
218
229
// a set of field models that are already watched (the $scope.model will have its own watcher)
219
230
const watchedModels = [ $scope . model ]
231
+ // we will not set up automatic model watchers if manual mode is set
232
+ const manualModelWatcher = $scope . options . manualModelWatcher
220
233
221
234
if ( $scope . options . formState ) {
222
235
// $scope.options.formState will have its own watcher
@@ -226,21 +239,31 @@ function formlyForm(formlyUsability, formlyWarn, $parse, formlyConfig, $interpol
226
239
angular . forEach ( $scope . fields , ( field ) => {
227
240
const isNewModel = initModel ( field )
228
241
229
- if ( field . model && isNewModel && watchedModels . indexOf ( field . model ) === - 1 ) {
242
+ if ( field . model && isNewModel && watchedModels . indexOf ( field . model ) === - 1 && ! manualModelWatcher ) {
230
243
$scope . $watch ( ( ) => field . model , onModelOrFormStateChange , true )
231
244
watchedModels . push ( field . model )
232
245
}
233
246
} )
234
247
}
235
248
249
+ function setupHideExpressionWatcher ( field , index ) {
250
+ if ( field . hideExpression ) { // can't use hide with expressionProperties reliably
251
+ const model = field . model || $scope . model
252
+ $scope . $watch ( function hideExpressionWatcher ( ) {
253
+ const val = model [ field . key ]
254
+ return evalCloseToFormlyExpression ( field . hideExpression , val , field , index )
255
+ } , ( hide ) => field . hide = hide , true )
256
+ }
257
+ }
258
+
236
259
function initModel ( field ) {
237
260
let isNewModel = true
238
261
239
262
if ( angular . isString ( field . model ) ) {
240
263
const expression = field . model
241
264
const index = $scope . fields . indexOf ( field )
242
265
243
- isNewModel = ! refrencesCurrentlyWatchedModel ( expression )
266
+ isNewModel = ! referencesCurrentlyWatchedModel ( expression )
244
267
245
268
field . model = evalCloseToFormlyExpression ( expression , undefined , field , index )
246
269
if ( ! field . model ) {
@@ -254,7 +277,7 @@ function formlyForm(formlyUsability, formlyWarn, $parse, formlyConfig, $interpol
254
277
return isNewModel
255
278
}
256
279
257
- function refrencesCurrentlyWatchedModel ( expression ) {
280
+ function referencesCurrentlyWatchedModel ( expression ) {
258
281
return [ 'model' , 'formState' ] . some ( item => {
259
282
return formlyUtil . startsWith ( expression , `${ item } .` ) || formlyUtil . startsWith ( expression , `${ item } [` )
260
283
} )
@@ -275,7 +298,7 @@ function formlyForm(formlyUsability, formlyWarn, $parse, formlyConfig, $interpol
275
298
watchers = [ watchers ]
276
299
}
277
300
angular . forEach ( watchers , function setupWatcher ( watcher ) {
278
- if ( ! angular . isDefined ( watcher . listener ) ) {
301
+ if ( ! angular . isDefined ( watcher . listener ) && ! watcher . runFieldExpressions ) {
279
302
throw formlyUsability . getFieldError (
280
303
'all-field-watchers-must-have-a-listener' ,
281
304
'All field watchers must have a listener' , field
@@ -306,13 +329,20 @@ function formlyForm(formlyUsability, formlyWarn, $parse, formlyConfig, $interpol
306
329
307
330
function getWatchListener ( watcher , field , index ) {
308
331
let watchListener = watcher . listener
309
- if ( angular . isFunction ( watchListener ) ) {
332
+ if ( angular . isFunction ( watchListener ) || watcher . runFieldExpressions ) {
310
333
// wrap the field's watch listener so we can call it with the field as the first arg
311
334
// and the stop function as the last arg as a helper
312
335
const originalListener = watchListener
313
336
watchListener = function formlyWatchListener ( ) {
314
- const args = modifyArgs ( watcher , index , ...arguments )
315
- return originalListener ( ...args )
337
+ let value
338
+ if ( originalListener ) {
339
+ const args = modifyArgs ( watcher , index , ...arguments )
340
+ value = originalListener ( ...args )
341
+ }
342
+ if ( watcher . runFieldExpressions ) {
343
+ runFieldExpressionProperties ( field , index )
344
+ }
345
+ return value
316
346
}
317
347
watchListener . displayName = `Formly Watch Listener for field for ${ field . key } `
318
348
}
0 commit comments