Skip to content
This repository has been archived by the owner on Apr 30, 2018. It is now read-only.

Commit

Permalink
add watchAllExpressions option
Browse files Browse the repository at this point in the history
  • Loading branch information
kwypchlo committed Jan 16, 2016
1 parent 516c56a commit 5c125fc
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 109 deletions.
18 changes: 17 additions & 1 deletion src/directives/formly-field.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function formlyField($http, $q, $compile, $templateCache, $interpolate, formlyCo

// @ngInject
function FormlyFieldController($scope, $timeout, $parse, $controller, formlyValidationMessages) {
/* eslint max-statements:[2, 32] */
/* eslint max-statements:[2, 34] */
if ($scope.options.fieldGroup) {
setupFieldGroup()
return
Expand All @@ -53,6 +53,7 @@ function formlyField($http, $q, $compile, $templateCache, $interpolate, formlyCo
setDefaultValue()
setInitialValue()
runExpressions()
watchExpressions()
addValidationMessages($scope.options)
invokeControllers($scope, $scope.options, fieldType)

Expand All @@ -72,6 +73,21 @@ function formlyField($http, $q, $compile, $templateCache, $interpolate, formlyCo
}, 0, false)
}

function watchExpressions() {
if ($scope.formOptions.watchAllExpressions) {
const field = $scope.options
const currentValue = valueGetterSetter()
angular.forEach(field.expressionProperties, function watchExpression(expression, prop) {
const setter = $parse(prop).assign
$scope.$watch(function expressionPropertyWatcher() {
return formlyUtil.formlyEval($scope, expression, currentValue, currentValue)
}, function expressionPropertyListener(value) {
setter(field, value)
}, true)
})
}
}

function valueGetterSetter(newVal) {
if (!$scope.model || !$scope.options.key) {
return undefined
Expand Down
64 changes: 26 additions & 38 deletions src/directives/formly-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,39 +122,6 @@ function formlyForm(formlyUsability, formlyWarn, $parse, formlyConfig, $interpol
$scope.$watch('options.formState', onModelOrFormStateChange, true)
}

function setManualModelWatcher() {
const groupedWatchers = []

angular.forEach($scope.fields, function(field, index) {
if (field.extras && Array.isArray(field.extras.watch)) {
angular.forEach(field.extras.watch, function(expression) {
const model = field.model || $scope.model
let watcherGroup = groupedWatchers.find((watcher) => {
return watcher.expression === expression && watcher.model === model
})

if (!watcherGroup) {
watcherGroup = {model, expression, callbacks: []}
groupedWatchers.push(watcherGroup)
}

if (angular.isString(expression) && field.model) {
watcherGroup.parsedExpression = $parse(expression).bind(null, $scope, {model: field.model})
}

watcherGroup.callbacks.push(runFieldExpressionProperties.bind(null, field, index))
})
}
})

angular.forEach(groupedWatchers, function(watcher) {
const expression = watcher.parsedExpression || watcher.expression
$scope.$watch(expression, function manualFieldModelWatcher() {
angular.forEach(watcher.callbacks, (callback) => callback())
}, true)
})
}

function onModelOrFormStateChange() {
angular.forEach($scope.fields, runFieldExpressionProperties)
}
Expand Down Expand Up @@ -198,6 +165,10 @@ function formlyForm(formlyUsability, formlyWarn, $parse, formlyConfig, $interpol

setupModels()

if ($scope.options.watchAllExpressions) {
angular.forEach($scope.fields, setupExpressionWatchers)
}

angular.forEach($scope.fields, attachKey) // attaches a key based on the index if a key isn't specified
angular.forEach($scope.fields, setupWatchers) // setup watchers for all fields
}
Expand Down Expand Up @@ -275,14 +246,26 @@ function formlyForm(formlyUsability, formlyWarn, $parse, formlyConfig, $interpol
})
}

function setupExpressionWatchers(field, index) {
if (field.hideExpression) { // can't use hide with expressionProperties reliably
const model = field.model || $scope.model
// add model to extra locals to be sure the expression is evaluated in correct context
const extraLocals = angular.merge(getFormlyFieldLikeLocals(field, index), {model})
$scope.$watch(function hideExpressionWatcher() {
const val = model[field.key]
return formlyUtil.formlyEval($scope, field.hideExpression, val, val, extraLocals)
}, (hide) => field.hide = hide, true)
}
}

function initModel(field) {
let isNewModel = true

if (angular.isString(field.model)) {
const expression = field.model
const index = $scope.fields.indexOf(field)

isNewModel = !refrencesCurrentlyWatchedModel(expression)
isNewModel = !referencesCurrentlyWatchedModel(expression)

field.model = evalCloseToFormlyExpression(expression, undefined, field, index)
if (!field.model) {
Expand All @@ -296,7 +279,7 @@ function formlyForm(formlyUsability, formlyWarn, $parse, formlyConfig, $interpol
return isNewModel
}

function refrencesCurrentlyWatchedModel(expression) {
function referencesCurrentlyWatchedModel(expression) {
return ['model', 'formState'].some(item => {
return formlyUtil.startsWith(expression, `${item}.`) || formlyUtil.startsWith(expression, `${item}[`)
})
Expand Down Expand Up @@ -342,19 +325,24 @@ function formlyForm(formlyUsability, formlyWarn, $parse, formlyConfig, $interpol
return originalExpression(...args)
}
watchExpression.displayName = `Formly Watch Expression for field for ${field.key}`
} else if (field.model) {
watchExpression = $parse(watchExpression).bind(null, $scope, {model: field.model})
}
return watchExpression
}

function getWatchListener(watcher, field, index) {
let watchListener = watcher.listener
if (angular.isFunction(watchListener)) {
if (angular.isFunction(watchListener) || watcher.runFieldExpressions) {
// wrap the field's watch listener so we can call it with the field as the first arg
// and the stop function as the last arg as a helper
const originalListener = watchListener
watchListener = function formlyWatchListener() {
const args = modifyArgs(watcher, index, ...arguments)
const value = originalListener(...args)
let value
if (originalListener) {
const args = modifyArgs(watcher, index, ...arguments)
value = originalListener(...args)
}
if (watcher.runFieldExpressions) {
runFieldExpressionProperties(field, index)
}
Expand Down
Loading

0 comments on commit 5c125fc

Please sign in to comment.