development

Sharing Data in AngularJS 1.X The Right Way

by Jamal on June 02, 2016

AngularJS is my favorite JS framework of the moment, dating all the way back to my starting out with MV* frameworks in JS. I like Angular so much because unlike the other frameworks out there, it is much more flexible and less opinionated. Of course when you have flexibility, the question of what is the best way to do something is sure to come up.

Which is why I’m writing this article, and we’re going to start this discussion with something very critical to your app’s success. Sharing data!

To give a little more context into the content here, take a look at an earlier article on setting up a global value service.

*Editor Note: This article was something I half way completed early last year, and decided to finish it and publish it because I liked the article idea. In the future, expect some cool stuff on Angular 2!

Lets Clear Up $rootScope

When you mention proper data sharing and Angular 1.X, you can not have $rootScope come up. The majority consensus of $rootScope is that its an inappropriate place to store your apps global data. That is the right thinking to have too. However, there are small instances where I will be inclined to use it. For me, it’s mostly with notifiers for my apps.

As an example, let’s take a look at an app that has an online and offline component. To check and see if a user is online you’d use the Window navigator object. Precisely, navigator.onLine. As a way to watch if a user goes online or offline, you’d set up a couple of event listeners for both states. View below for code example.

So for me this is a perfect example of where $rootScope comes in handy. So let’s say instead of using $rootScope, we’d use something on the lines of a service handler where a $scope injection takes place at each controller/directive level. Without writing any code, just think for a second. Which would actually be more overhead in our app. Writing a service to handle the $scope injection on every declared controller or directive, or using the above code sample with $rootScope. Not a really hard sell, huh?

Now with our understanding on that clear, let’s move deeper into our architectural discussion.

Interacting with Directives, Services, and Controllers

Controllers, Directives, and Services

Having an understanding of how these three components work together is important in any Angular 1.X app you could be building. So now let’s get a briefer on what each actually are.

Controller

Think of a controller as a page. This is where the logic specifically needed for this page/view will be found. It can be composed of logic explicitly written in this JS file, or several injectable logic modules(more on that in a bit).

Unlike the other two components we’ll go over later, a controller isn’t injectable between different apps. Its logic is architecturally tied to whatever app it has been defined in.

Directive

If you’re familiar with more server-side languages, other JS frameworks, or just things as simple as jQuery plugins to a degree, you have some idea of what a directive is. A directive is a self containing code module that has its own scope, template(if applicable), and can have other values from outside containers(i.e. controllers) and access them.

A directive is injectable to any other directive, or controller inside of the app it’s been loaded into. Services can be injected into directives, but not the other way around.

Services

A service is the best sharer out of the three components we’re going to go over, which perfectly sums up its role. The role of a service is to have logic written in it that can be accessed, altered, or store information. Of course this information can be data, logic, functions, etc. In short, they come in handy to have.

A service is completely injectable. It can be injected to any number of controllers, directives, or other services. It is always a good idea to keep your logic that needs to be in a lot of places inside a service for easy reuse.

Let’s Now Look At How To Use Them

Now that the overview is over on the three main components of passing data in your Angular 1.X app, let’s move onto with how to use them together. Now, let’s look at core concepts in how we achieve our ideal data sharing architecture.

Only Keep controllers app dedicated. What this means is that out of all three of the components, the only the controller needs to be dedicated to the app. The other two should be interchangeable for any other 1.X app.

Keep directive scope variables set through inputs.  The most important thing I’ve always found with writing directives is to make sure your app related values are set through inputs. That gives you the optimal amount of flexibility with injecting them from app to app.

Limit service interplay as much as possible. Because services are meant to hold interchangeable logic, it’s important to not make them much reliant on other services. A key to remember, the injections in your service the more of a headache it will be to inject it elsewhere.

What Is The Actual Data Flow

What is the actual data flow

We’ve now reached the point in the article where we actual take time to look at how the data actually is meant to flow throughout your app. From the actual overview we’ve given on the three components we went over, and how to use them, it might be pretty obvious as to how we’re organizing things here.

To best explains we’re going to break down the hierarchy into three levels.

Top Level

Here is where the importance of services come from. At the top-level services lies because this is where we put all our Globally accessed data. By this, I means creating a service made to handle the access, manipulation, removal, or whatever other operation you need. This way it can be injected wherever it’s needed, and only there.

Summary: Your service needs to act as the highest point in your data storage architecture, acting as the holder for the majority of your app related data pertaining to your user.

Middle Ground

From the descriptions we went over about the last two components, it could easily be a toss up between which one goes before the other. However, if you’ve really been paying attention it might be pretty obvious. Well in case it isn’t, the answer is controllers.

Controllers go before directives because of one very important reason, controllers are app dedicated and directives should be built app independent. So your controller does a lot of interacting with other core app functionality and data expectations only to pass them into its own view and/or use of a directive.

Ground Level

Now after talking about 2 of 3 of our components it should be easy to guess which one goes here. Directives are here because unlike services they don’t store and act as an access point app data. They also are build app independent, which means unlike controllers they have no real ties to whatever app they are being injected in.

Now don’t take this the wrong way, a directive has the ability to manipulate data being held on the controller $scope, $rootScope, and the global data store you built with your service. Powerful stuff right! No, the reason why directives are the ground level is because they only have the ability to do these things with what is being passed down into it by a controller, or even an outside service.

Brining It All Together

So there you have it! My take on what it means to have a proper data flow in your Angular 1.X application. If you learned something, or want to share a different opinion on what I wrote, share on social media and mention me. Always up for good convo 🙂