This repository was archived by the owner on Apr 12, 2024. It is now read-only.
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
$watch - group watcher callbacks that have the same watch expression and context #13731
Open
Description
I was wondering if you guys ever considered grouping watchers that have same watch expression and context into one watcher with multiple concurrent callback. I have implemented it for angular-formly and I'm wondering if this was good idea and maybe I missed something.
Check the example below how I've done it manually. It could be probably implemented in the core in similar way. Of course there are some holes as it should know if the watcher is deep or shallow and I didn't implement unwatching of single watcher because I had no use case for that but it all could be managed.
const groupedWatchers = []
// iterate through all form fields
angular.forEach($scope.fields, function(field, index) {
// check if this field has watchers
if (field.extras && Array.isArray(field.extras.watch)) {
// iterate through field watchers
angular.forEach(field.extras.watch, function(expression) {
// model can be global modal (from $scope) or one that is manually passed to field (field.model)
const model = field.model || $scope.model
// find an already existing watcher with the same expression and context
let watcherGroup = groupedWatchers.find((watcher) => {
return watcher.expression === expression && watcher.model === model
})
// if this is unique or first of it's kind expression, create a group for it
if (!watcherGroup) {
watcherGroup = {model, expression, callbacks: []}
groupedWatchers.push(watcherGroup)
}
// if this is string expression and the field overrides model, parse this expression to use model from field
if (angular.isString(expression) && field.model) {
watcherGroup.parsedExpression = $parse(expression).bind(null, $scope, {model: field.model})
}
// push a callback to callbacks list
watcherGroup.callbacks.push(runFieldExpressionProperties.bind(null, field, index))
})
}
})
// iterate through watcher groups
angular.forEach(groupedWatchers, function(watcher) {
// set up single watcher for each group
$scope.$watch(expression, function manualFieldModelWatcher() {
// run registered callbacks one by one
angular.forEach(watcher.callbacks, (callback) => callback())
}, true)
})