Why does Angular need a service
- Components should be focused on the presentation layer, so services are needed to fetch and save data.
- Communication between components requires services to assist.
Angular uses dependency injection for services. What is dependency injection?
Why dependency injection
Let’s start with a small example
exportclass Car { public engine: Engine; // Engine tires: Tires; / / tireconstructor() { this.engine = new Engine(); this.tires = new Tires(); }} // If you change the engine constructor, pass in the number of cylinders, and the constructor changes accordinglyconstructor() {
this.engine = new Engine(12);
this.tires = new Tires();
}
Copy the code
A car class is created above, but this class is not robust at all. If the constructor of the Engine changes and we need to pass a parameter when building the Engine, we need to change the use of new Engine() in the car class. It might be acceptable to change just two things, but if the engine class relies on other parts, the layers of dependencies, and one of the constructors changes, could lead to a cascade of changes that would make the code completely unmaintainable. The same is true of tires. Different cars need different tires, so writing like this is not flexible and has no universality.
So dependency injection is needed
export class Car {
constructor(public engine: Engine, public tires: Tires) { }
}
let car = new Car(new Engine(), new Tires());
Copy the code
Engine is separated from tire and car classes, and the car is okay as long as the engine and tire you pass in meet the requirements.
Class Engine2 {constructor(public cylinders: number) {}} class Engine2 {constructor(public cylinders: number) {}}let bigCylinders = 12;
let car = new Car(new Engine2(bigCylinders), new Tires());
Copy the code
The dependency injection pattern also makes it easy to write test cases where you don’t have to worry about the tire details when testing a CAR class, just give a working tire.
The above explained what dependency injection is and why it is needed. That is, a class receives the dependencies it needs from the outside world rather than creating them itself. But for consumers, the problem is again. If you want a car, you have to have a factory to assemble a car
import { Engine, Tires, Car } from './car';
export class CarFactory {
createCar() {
let car = new Car(this.createEngine(), this.createTires());
car.description = 'Factory';
return car;
}
createEngine() {
return new Engine();
}
createTires() {
returnnew Tires(); }}Copy the code
This pattern may seem fine, but it is simply a simplification of dependencies. Similar engine factory classes, tire factory classes, call each other and depend on each other, resulting in an unmaintainable πΈοΈ
This is where a dependency injection framework is needed. The framework has something called an injector, and when you need a Car, you just need it
let car = injector.get(Car);
Copy the code
So consumers don’t have to maintain the factory class that produces car. And the Car class itself doesn’t care where the tires and engine came from. Everybody’s happy.
Dependency injection pattern in Angular
Angular uses hierarchical dependency injection
An Angular application is a tree of components, and each component instantiation has its own injector providers.
Components will bubble up looking for a Service until they find an error when the root AppComponent has not been found.
The benefits of this design:
- Facilitate communication between components. A component at the top level can uniformly control the operations of multiple sub-components on the same data.
- Increase reuse. Services that can be extracted and reused by multiple underlying components can be written to the upper component.
Angular service tips
- Generate a Module service. ng g service test –module=app
- Use the @Injectable() decorator, which tells Angular that the service class might inject a dependency itself,
- The component itself is regardless of how the service works internally.
- Service must be injected via providers.
- It is possible to call some business functions in the constructor of a service, but this is not a best practice.
- The service is singleton within the app.
src/app/test.service.ts
import { Injectable } from '@angular/core';
@Injectable()
export class TestService {
constructor() {}}Copy the code