Angular 2’s biggest strength is the reliability of encapsulation and re-use, which means passing data to and between components can be a pain at first. You are highly discouraged from getting data from the DOM, making AJAX calls in your components is a no-no. How are you supposed to get data to your things?
This is where you start to use Angular Services. Services are an injectable class that allows you to keep all your functionality in one place. Here’s the official definition of a service in Angular 2 from the docs:
A service is a class with a focused purpose. We often create a service to implement features that are independent from any specific view, provide shared data or logic across components, or encapsulate external interactions.
You have data you need from an AJAX endpoint? Create a service.
You want to maintain state for an object that multiple components? Create a service.
Want to do anything cool with some data across your application? Create a service.
For those of you familiar with the pattern, Services in Angular 2 are really Singleton Service models. Its a single instance you pass around. It has a state, it has some methods. Its easily mocked and you know where the ‘meat’ of your application is at all times. It allows you to move the data manipulation out of the display code entirely.
Coming from a Vanilla JS background all of this may seem a little over complicated. While simplicity is something to strive for, there are good reasons for this level of abstraction:
Here’s some examples of services in action:
This is an example of a simple data service providing some data to a component. While extremely simple, it shows how to get data ‘into’ a component from an outside source:
The component itself relies on the service to provide the data to the front end. The value of ‘bar’, displayed in the component’s template actually comes from the service itself. When the component loads, it calls the “getBar” method of the service which returns a simple string.
While this example might seem very trivial, it lays some groundwork for the other examples. A service provides data external from the component in an ‘agreed’ upon way. This contract allows us to take some control of how we get the data away from the component, which should really just focus on how the data should be displayed.
This is an example of a service that allows a total of three components to interact together.
If you look at the code in the example, this small ‘app’ has three components that each include the CounterService. This extremely simple service allows us to interact with a single integer variable that can be incremented and decremented via two completely separate component’s buttons.
Again, while maintaining a ‘contract’ we can allow each one of these components to focus on the display and events rather than the actual manipulation of the data.
This is an example of an AJAX service providing data to a component. A ‘locally’ hosted JSON file is retrieved via AJAX in the service itself and then sent to the component. This component is able to interact with the data entirely through the service itself. This level of abstraction allows the component to strictly focus on the display and styling of the data provided by the service.
Promises are great and a well trod subject, I’ll leave it up to you to read more about their benefits (or you can revisit my previous blog post: http://blog.arroyolabs.com/2016/04/angularjs-2-ajax/). Observables, when compared to promises, allow you to specify not only when something is ‘done’ but when something has changed.
This most definitely comes in handy when you create a service like the example above that allows you to detect when any changes occur from your service.
While the final architecture of your application or bundled component is really a choice you need to make, I hope we were able to clear up some of the basics of using services in Angular 2.