in Javascript

Keeping Angular “service” list data in sync with controllers.

Learning Angular has been one of the greatest productivity boosts for rapid application development in my career. However, some of the common strategies implemented can be improved in my opinion.

In AngularJS, there is a great deal of importance placed on separation of concerns. One of the most practiced patterns for holding application state is move this data into angular services or factories. Which one of the former to use is totally a personal preference in my opinion (I opt for factories most of the time).

The purpose of this post is aimed at services that hold collections that update from remote data calls.

Targeted AngularJS version at time of writing: 1.2.19

Too many times, I have run across angular controllers bringing in the $scope service just to $watch a service collection:

The bad:

I know what you are thinking “why doesn’t this just work by default?” We are clearly updating the DataFactory.items.

The reason that angular does not “watch” this value is because when it set’s up the implicit $watch from a view, it references the original array from the DataFactory. But when the data comes back through $http, it replaces the property with a different array reference. Thus Angular can’t watch the collection without adding nasty $watch functions in your controllers.

So why is the $watch a bad thing in the controller?

It adds to the cognitive load needed to understand what is going on in the controller. When we look at code that others (or ourselves 6 months from now) wrote, being able to easily understand the what without spending a lot of time parsing the how is very beneficial. Any bindings in you view cause implicit watches to be set. Also, all  $watch  functions are executed for every  $digest  which may occur many times in a “digest cycle” (angular kicks these off with most interactions). Adding yet another watch is a pattern that may get you into performance issues in the future.

Surely we can remove the dependency on $scope just to watch this collection. Let us look at a very simple example of this separation adapted from Todd Motto.

The better:

Now I’m not hating on this format. Here after every call to update the service data source, both the source and controller reference get updated. It works for what it is intended for and it is fairly easy to understand what is going on. However, it does not really address controllers other than the one calling the service updated being notified.

How about this:

Doesn’t this just read so much cleaner?

Enter angular.copy. What angular.copy does when given a new array and a source array is empty the source (by setting length to 0 i think..) and then repopulate the array with the new array items.

Our end result:

Need a hand?