DEV Community

Renuka Patil
Renuka Patil

Posted on

2. Services and Dependency Injection

  • Services: How to create and use services for data sharing and business logic.
  • Dependency Injection: How DI works in Angular, providers, and the injector system.
  • Singleton Services: Creating and managing singleton services.

  • Service is nothing its just a class with specific purpose.
  • Data Sharing Across multiple components.
  • It is used to apply application logic
  • We can use Services for external interactions such as connecting to a database.
  • The best solution is to write services and inject in application where we need it.
  • Services are usually implemented through dependency injection.
  • Organize and share business logic, models or data and functions with different components in angular application

  • As we all know that Angular uses the concept of components.
  • The Entire Ul of the Angular application is divided into several
  • components.
  • Sometimes all these components performing common tasks like displaying images on the view, accessing the database etc
  • To avoid writing code again and again, Angular Services comes into place.

  • These services can then be injected into the components that require that service or dependency.

  • The main objective of a service is to organize and share business logic, models, or data and functions with different components of an Angular application.

  • Services are piece of code that are used to perform a specific task, a service can contain a value or function or combination of both.

  • Services prevent us from writing same code at multiple sections of our application.

  • The best solution is to write services and inject in application where we need it.

  • Services are usually implemented through dependency injection.


Dependency Injection

Dependency Injection is a coding pattern in which a class receives its dependencies from external sources rather than creating them itself.

Image description

  1. Create service
  2. Register with injector

Use this command to generate the service:

ng g s services/studentService
Enter fullscreen mode Exit fullscreen mode

Injectable decorator (@Injectable) → injectable services

@Injectable({
  providedIn: 'root'
})
export class StudentServiceService {

  constructor() { }
}

Enter fullscreen mode Exit fullscreen mode

DI as a design pattern → in which class receives its dependency from external sources rather than creating them itself

1.studentservice


export class StudentServiceService {

  constructor() { }

  getStudent(){
    return [
       {name: "Ram", age: 21, class: 11},
       {name: "Sia", age: 22, class: 12},
       {name: "Sita", age: 23, class: 13},

     ]
   }
}


Enter fullscreen mode Exit fullscreen mode

2.Register with injector


  @Component({
  selector: 'app-first',
  templateUrl: './first.component.html',
  styleUrls: ['./first.component.css'],
  providers: [StudentService]
})

export class FirstComponent {
  public students: any;
    constructor(private std: StudentService) {
            this.students = std.getStudent();
            console.log(this.students);
    }

}
Enter fullscreen mode Exit fullscreen mode

💡 Two ways register the services

  1. App level ( app.module.ts )
  2. component level

You can add that in app.module.ts file - globally inject the service.

import { StudentService } from './services/student.service';

@NgModule({
  declarations: [],
  imports: [],
  providers: [StudentService],
  bootstrap: []
})
export class AppModule { }

Enter fullscreen mode Exit fullscreen mode

Fetching And Displaying API Data

  1. What is an API?

    • An API (Application Programming Interface) acts as a bridge between applications and databases, enabling them to interact.
    • APIs support different formats like JSON (commonly used for being lightweight) and XML for data transfer.
  2. Understanding API Usage in Applications:

    • APIs can be used across mobile, desktop, and web applications, as well as IoT devices.
    • They handle operations such as data retrieval, insertion, updates, and deletion, utilizing HTTP protocols (GET, POST, PUT, DELETE).
  3. Real-life Examples of APIs:

    • APIs for weather updates, payment systems (e.g., PayPal, Paytm), and healthcare data (e.g., COVID-19 case statistics).
    • These demonstrate the power of APIs in sharing and managing data across platforms.
  4. API Implementation in Angular:

    • Angular uses services to make API calls, where the HTTP Client Module facilitates communication with APIs.
    • The process involves creating a service that interacts with the API and connects it to Angular components.
  5. Practical Demonstration Goals:

    • Explanation of HTTP Client Module and how it works in Angular.
    • Implementation of a service to fetch data from an API and display it in an Angular application.
    • Key prerequisites include understanding services and dependency injection, as covered in previous lectures.

Key Flow in Angular:

  1. Create an Angular component where data is displayed.
  2. Create a service to handle API interactions using the HTTP Client Module.
  3. Link the service with the component to fetch and display the data from the API.

HTTP Verbs

  1. GET
  2. POST
  3. PUT
  4. DELETE

Angular app → service → APIcall → database

component → service → HTTP module → API server

API ↔ Service ←—Subscribe-—— component

1. Setting Up the Angular Project

Before fetching data, ensure your Angular project is ready. If not, create a new Angular application using:

ng new my-angular-app
cd my-angular-app
Enter fullscreen mode Exit fullscreen mode

Once done, open your project in Visual Studio Code and install all dependencies using:

npm install
Enter fullscreen mode Exit fullscreen mode

2. Importing HttpClientModule

To interact with APIs, Angular provides the HttpClientModule. Import it in your app.module.ts file as follows:

import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

This allows Angular to make HTTP requests.

3. Creating a Service for API Interaction

Services in Angular handle logic that can be reused across components. Create a service using:

ng generate service services/post
Enter fullscreen mode Exit fullscreen mode

This command creates a services folder with post.service.ts and post.service.spec.ts. Open post.service.ts and update it:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class PostService {
  private url: string = 'https://jsonplaceholder.typicode.com/posts';

  constructor(private http: HttpClient) {}

  getPosts(): Observable<any> {
    return this.http.get(this.url);
  }
}
Enter fullscreen mode Exit fullscreen mode

Here:

  • The getPosts() method fetches data from the API.

4. Injecting the Service into a Component

To use the service, inject it into a component. Open app.component.ts and modify it:

import { Component, OnInit } from '@angular/core';
import { PostService } from './services/post.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
  posts: any[] = [];

  constructor(private postService: PostService) {}

  ngOnInit(): void {
    this.postService.getPosts().subscribe(
      (data) => {
        this.posts = data;
      },
      (error) => {
        console.error('Error fetching posts', error);
      }
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

5. Displaying Data in the Template

Update app.component.html to display the fetched data:

<div *ngIf="posts.length > 0; else noData">
  <h2>Posts</h2>
  <ul>
    <li *ngFor="let post of posts">
      <h3>{{ post.title }}</h3>
      <p>{{ post.body }}</p>
    </li>
  </ul>
</div>

<ng-template #noData>
  <p>No posts available.</p>
</ng-template>
Enter fullscreen mode Exit fullscreen mode

This uses Angular's *ngFor directive to iterate over and display each post.

6. Understanding the API Response

The API returns a JSON array of posts, each containing properties like userId, id, title, and body. You can preview this data in your browser by visiting https://jsonplaceholder.typicode.com/posts.

7. Enhancing Error Handling

Add error handling in the service for robustness. Update the getPosts() method:

import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';

getPosts(): Observable<any> {
  return this.http.get(this.url).pipe(
    catchError((error) => {
      console.error('Error occurred:', error);
      return throwError(error);
    })
  );
}
Enter fullscreen mode Exit fullscreen mode

8. Styling the Data

Update app.component.css to style the posts:

h2 {
  text-align: center;
  color: #4caf50;
}

li {
  list-style: none;
  margin: 10px 0;
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 5px;
}

h3 {
  margin: 0;
  color: #333;
}

p {
  color: #555;
}
Enter fullscreen mode Exit fullscreen mode

9. Running the Application

Run the Angular application using:

ng serve
Enter fullscreen mode Exit fullscreen mode

Open the browser at http://localhost:4200 to see your application fetching and displaying posts.


Singleton Services in Angular: Creating and Managing Shared Services

In Angular, services are used to encapsulate reusable logic, data sharing, and communication between components. A singleton service is a service that is instantiated once and shared across the application, ensuring a single source of truth and efficient resource management.

This blog explores how to create and manage singleton services effectively in Angular.


What is a Singleton Service?

A singleton service is a service instance that is shared across the entire application. Angular ensures that only one instance of the service exists throughout the application lifecycle, which can be crucial for scenarios like managing global state or shared resources.


How to Create a Singleton Service

1. Use @Injectable with providedIn: 'root'

Angular provides the @Injectable decorator to make a service injectable. Setting providedIn: 'root' registers the service in the root injector, making it a singleton.

Example: Singleton Service

my-service.service.ts

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

@Injectable({
  providedIn: 'root' // Registers this service as a singleton
})
export class MyService {
  private counter = 0;

  increment() {
    this.counter++;
  }

  getCount(): number {
    return this.counter;
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Provide the Service in AppModule

Alternatively, you can declare a singleton service in the root module's providers array.

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { MyService } from './my-service.service';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  providers: [MyService], // Singleton service
  bootstrap: [AppComponent]
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

Using the Singleton Service

You can inject the singleton service into any component or another service to share its functionality and state.

app.component.ts

import { Component } from '@angular/core';
import { MyService } from './my-service.service';

@Component({
  selector: 'app-root',
  template: `
    <button (click)="increment()">Increment</button>
    <p>Counter: {{ count }}</p>
  `
})
export class AppComponent {
  count: number = 0;

  constructor(private myService: MyService) {}

  increment() {
    this.myService.increment();
    this.count = this.myService.getCount();
  }
}
Enter fullscreen mode Exit fullscreen mode

child.component.ts

import { Component } from '@angular/core';
import { MyService } from './my-service.service';

@Component({
  selector: 'app-child',
  template: `<p>Shared Counter: {{ count }}</p>`
})
export class ChildComponent {
  count: number;

  constructor(private myService: MyService) {
    this.count = this.myService.getCount();
  }
}
Enter fullscreen mode Exit fullscreen mode

Both AppComponent and ChildComponent will share the same instance of MyService, ensuring a consistent counter value.


Best Practices for Singleton Services

  1. Use providedIn: 'root'

    • Recommended for most singleton services as it simplifies registration and tree-shaking.
  2. Avoid Stateful Services When Possible

    • Stateful singleton services can introduce hard-to-track bugs. Use them only when necessary.
  3. Lazy Initialization

    • Initialize resource-heavy services only when needed to reduce application startup time.
  4. Thread-Safe Design

    • Ensure thread-safe access to shared resources in services, especially in multi-threaded environments.

When to Use Singleton Services

  1. State Management

    • Managing global states like user authentication or preferences.
  2. Shared Resources

    • Services for shared resources like HTTP clients, configuration data, or caching.
  3. Cross-Component Communication

    • Facilitating communication between unrelated components.

Conclusion

Singleton services are a cornerstone of Angular's dependency injection system. By leveraging a single instance across your application, you can simplify data sharing, improve performance, and maintain consistent application state. Understanding how to create and manage singleton services is essential for building scalable and efficient Angular applications.

Have any unique use cases or challenges with singleton services? Let us know in the comments!

You can see these blogs to cover all angular concepts:

Beginner's Roadmap: Your Guide to Starting with Angular

  1. Core Angular Concepts
  2. Services and Dependency Injection
  3. Routing and Navigation
  4. Forms in Angular
  5. RxJS and Observables
  6. State Management
  7. Performance Optimization

Happy coding!

Top comments (1)

Collapse
 
jangelodev profile image
João Angelo

Hi Renuka Patil,
Very nice and helpful !
Thanks for sharing.