Web-Angular Services and Injectables dependencies

Services

        Services are a way of packaging the basic operations of an application. They are designed to provide reusable and modular code for deep processing of applications. In contrast, components (see above) should focus more on the user view. The application's logic is contained in services. Note that the Angular system does not enforce this concept and you need to move the logic into your application's services yourself.
Services are plain Typescript code, they don't have any Angular decorators. However, there are also special types of services that come with Angular code decorators, such as injectors which we will discuss in the next section.
        So far we have used very simple application examples where the application logic is simple and can be easily included in components. Angular services should contain detailed logic and provide interfaces to one or more components as well as other services in the application. A normal service is just a Typescript class. For example, the service below has a very simple interface that returns a random color string. You can probably imagine how this interface might interact as a server when retrieving a color string from a remote server. This is a bit tricky and we'll discuss server interaction separately.
        Let's implement a simple service that provides a method that returns a pseudo-random string representing a color. The following code implements the service (note this is pure Typescript, without any Angular code).

export class ColourService {
  private static colours = ["red", "green", "blue", "black", "pink"];
  public getColour(): string {
    return ColourService.colours[Math.floor(Math.random() * ColourService.colours.length)];
  }
}

        This code selects a random string from an array of color strings.
        We can implement a component that uses this service as shown below.

import { Component } from '@angular/core';
import { ColourService } from './colour.service';

@Component({
  selector: 'app-root',
  template: `<h1>Random Colours</h1>
             <p>My colour is:
             <span [style.color]="colour">{
   
   {colour}}</span>
             </p>
             <button (click)="change()">New Colour</button>
            `
})
export class AppComponent {
  colour: string;
  private colourServer: ColourService;
  
  constructor() {
    this.colourServer = new ColourService();
    this.colour = this.colourServer.getColour();
  }
  
  change() {
    this.colour = this.colourServer.getColour();
  }
}

        The following points need to be noted:

  1. We imported the ColourService type using Typescript's import statement.
  2. The main component class creates a new instance of the ColourService class in its constructor and selects an initial random value. This is bad Angular practice and will be explained below.
  3. Use an event handler to change the color every time the user clicks the button. Note that the assignment of the [style.color] CSS style selector is used to change the color of the text. Remember to use the American pronunciation color here.
    When the red string is selected, the actual application looks like this.

        As mentioned above, it is not good practice to create new instances of service classes. This raises a number of issues, including reusability between components, determining which component initializes it, and how other components know whether it has been initialized. To solve these potential programming problems, Angular introduced injectable components, which we will look at next.

Dependency InjectionDependency Injection

        Dependency Injection is a method used in Angular to control service behavior. You may have realized that we need to set up a service in our application to access the remote website. For example, who starts the web service, how the web service is managed (errors, slow responses, etc.) and other service-related issues are handled by the Angular runtime. It does this by decorating our TypeScript service with the @Injectable decorator and providing some hooks to the Angular runtime system.

        We can make the service in the previous section injectable by adding an Angular decorator, the code is as follows:

import { Injectable } from '@angular/core';

@Injectable()
export class ColourService {
  private static colours = ["red", "green", "blue", "black", "pink"];
  
  public getColour(): string {
    return ColourService.colours[Math.floor(Math.random() * ColourService.colours.length)];
  }
}

For the service code, the only change here is to import the Angular decorator and insert it on the line before the service code. This decorator has no parameters but is inserted into the class definition.

Now, after defining an injectable service, we need to use it in an Angular way so that Angular can manage the service. In our case, we want to use an injectable service in the main application component. Angular identifies services by looking at the component constructor parameters (the constructor is where Angular automatically initializes the service). We can add the following constructor to our component:

export class AppComponent {
  colour: string;
  
  constructor(private colourServer: ColourService) {
    this.colour = this.colourServer.getColour();
  }
  
  change() {
    this.colour = this.colourServer.getColour();
  }
}

        The changes to the AppComponent code here are as follows:

  1. Constructors now take private service variables as constructor parameters instead of existing as separate properties in the class.
  2. The constructor no longer creates the ColourService object, this work is now handled by the Angular runtime.
  3. We still need to initialize in the constructor so that the first color is displayed.

        There is one final step required to use this injectable service. Angular uses a declaration to keep track of all providers of a service provider. In our case, we can make the appComponent component a provider by adding the following to the parameters of the @Component decorator:

providers: [ColourService]

        We can also attach injectable services to module definitions. The @NgModule decorator will contain the above providers attribute and the constructor of the module class can be used just like in the component. We will see more complete examples in future lab sessions.

        Angular also provides "hooks" that allow us to execute code at different stages of the lifecycle of an injectable service. In the above example, we called the getColour() method of the service in the constructor. While this seems reasonable in our example, imagine if our service was connected to a remote server, the call would not complete until the connection was completed. This is a problem for our component because it is responsible for updating the display area, so the user will notice part of the display when accessing the server. In other words, service initialization will hinder the smooth display of the application interface. Angular allows us to delay the execution of code until the injectable service initialization is complete, while allowing the component view to complete.

        OnInit hooks are a way to wrap code to execute after the service is fully initialized. It works by adding a method to your component that contains code that the Angular runtime will remember to call after the service is initialized.

        The complete code for our application now looks like this:

import { Component, OnInit } from '@angular/core';
import { ColourService } from './colour.service';

@Component({
  selector: 'app-root',
  template: `
    <h1>Random Colours</h1>
    <p>My colour is:
      <span [style.color]="colour">{
   
   {colour}}</span>
    </p>
    <button (click)="change()">New Colour</button>
  `,
  providers: [ColourService]
})
export class AppComponent implements OnInit {
  colour: string;

  constructor(private colourServer: ColourService) {}

  ngOnInit(): void {
    this.colour = this.colourServer.getColour();
  }

  change() {
    this.colour = this.colourServer.getColour();
  }
}

        Please note the following about this code:

  1. We now import OnInit from the Angular core module.
  2. The hook is the ngOnInit method, which now contains the code to initialize the colors in the view.
  3. The constructor is now empty. Normally, we should try to reduce the amount of code in the constructor so that Angular can update the view as quickly as possible.

        In addition to the OnInit hook, there are several other hooks. Some examples are:

  • ngOnChanges - Called when the component receives an input property.
  • ngAfterViewInit - Called once after the component view is initialized.
  • ngOnDestroy - Called before Angular destroys a component or other Angular object. This allows for cleanup, such as freeing objects to save space or handling things like closing connections.

        They are used in the same way as ngOnInit shown above.

Guess you like

Origin blog.csdn.net/qq_54813250/article/details/133816338