Skip to content
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
@kwypchlo

Description

@kwypchlo

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)
})

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions