Ad Code

✨🎆 JOIN MERN, JAVA, PYTHON, AI, DEVOPS, SALESFORCE Courses 🎆✨

Get 100% Placement Oriented Program CLICK to new more info click

Services & Dependency Injection

Dependency Injection (DI) in Angular 21

Dependency Injection is a design pattern where Angular creates and provides the objects/services that a component or another class needs, instead of the class creating those objects itself.

What is a Service in Angular?

A Service is a class used to share data, logic, or functionality across components.

👉 Common uses:

  • API calls (HttpClient)

  • Business logic

  • Data sharing between components

  • Utility functions

  • Authentication

Why Do We Need Dependency Injection?

Imagine you have:

StudentComponent
       ↓
StudentService
       ↓
HttpClient
       ↓
Backend API

The component doesn't need to know how to create the service or its dependencies.

Angular manages the dependencies.

This gives you:

  • Loose coupling
  • Reusable services
  • Easier testing
  • Centralized dependency management
  • Better application architecture

5. Real-Life Example

Think about a car.

You need an engine:

Car
 ↓
Engine

Instead of the car having to manufacture an engine itself, someone provides the engine.

Similarly:

Component
    ↓
Angular DI
    ↓
Service

The component says:

"I need StudentService."

Angular says:

"Here is an instance of StudentService."

Syntax to create services:

ng generate service services/user

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

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

  private userName: string = "Shiva";

  constructor() { }

  getUserName() {
    return this.userName;
  }

  setUserName(name: string) {
    this.userName = name;
  }
}


✅ providedIn: 'root' → Service is Singleton (one instance in entire app)

Step 2: Inject Service in Component

import { Component } from '@angular/core';
import { UserService } from '../services/user.service';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html'
})
export class HomeComponent {

  name: string = '';

  constructor(private userService: UserService) { }

  ngOnInit() {
    this.name = this.userService.getUserName();
  }

  changeName() {
    this.userService.setUserName("Rahul");
    this.name = this.userService.getUserName();
  }
}

home.component.html

<h2>User Name: {{ name }}</h2>
<button (click)="changeName()">Change Name</button>


Step 2: Create API Service

ng generate service services/product

📌 product.service.ts

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

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

private apiUrl = 'https://jsonplaceholder.typicode.com/posts';

constructor(private http: HttpClient) {}

getProducts(): Observable<any> {
return this.http.get(this.apiUrl);
}
}

📌 Step 3: Inject in Component

import { Component } from '@angular/core';
import { ProductService } from '../services/product.service';

@Component({
selector: 'app-products',
template: `
<h3>Product List</h3>
<ul>
<li *ngFor="let item of products">
{{ item.title }}
</li>
</ul>
`
})
export class ProductsComponent {

products: any[] = [];

constructor(private productService: ProductService) {}

ngOnInit() {
this.productService.getProducts()
.subscribe(data => {
this.products = data;
});
}
}


Full Example for CRUD Operation

1. What is subscribe()?

Your service returns an Observable:

getProducts(): Observable<any[]> {
  return this.http.get<any[]>(this.apiUrl);
}

An Observable doesn't immediately give you the data. You need to subscribe to it.

this.productService.getProducts()
  .subscribe(data => {
    console.log(data);
  });

Think of it like:

Observable = I will give you data when it is available.
subscribe() = I am listening; give me the data when it arrives.


2. What is next?

You can write subscribe() in two ways.

Simple syntax

this.productService.getProducts()
  .subscribe(data => {
    console.log(data);
  });

Here, data is the successful response.

Object syntax

this.productService.getProducts()
  .subscribe({
    next: (data) => {
      console.log(data);
    },

    error: (err) => {
      console.log(err);
    },

    complete: () => {
      console.log('Completed');
    }
  });

Here:

PropertyMeaning
nextData successfully received
errorSomething went wrong
completeObservable has finished



Modify ProductService.ts file

import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root', }) export class Productservice { private apiUrl = 'https://jsonplaceholder.typicode.com/posts'; constructor(private http: HttpClient) {} // GET - Get all products getProducts(): Observable<any[]> { return this.http.get<any[]>(this.apiUrl); } // GET - Get product by ID getProductById(id: number): Observable<any> { return this.http.get<any>(`${this.apiUrl}/${id}`); } // POST - Add product addProduct(product: any): Observable<any> { return this.http.post<any>(this.apiUrl, product); } // PUT - Update complete product updateProduct(id: number, product: any): Observable<any> { return this.http.put<any>(`${this.apiUrl}/${id}`, product); } // DELETE - Delete product deleteProduct(id: number): Observable<any> { return this.http.delete<any>(`${this.apiUrl}/${id}`); } }


modify product.ts

import { Component, OnInit } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { Productservice } from '../../services/productservice'; @Component({ selector: 'app-product', imports: [FormsModule], templateUrl: './product.html', styleUrl: './product.css', }) export class Product implements OnInit { products: any[] = []; // Form fields title: string = ''; body: string = ''; userId: number = 1; // Used for update editId: number | null = null; constructor(private productService: Productservice) {} ngOnInit(): void { this.getProducts(); } // ============================ // GET ALL PRODUCTS // ============================ getProducts(): void { this.productService.getProducts() .subscribe({ next: (data) => { console.log(data); this.products = data; }, error: (error) => { console.error('Error:', error); } }); } // ============================ // ADD PRODUCT // ============================ addProduct(): void { if (!this.title || !this.body) { alert('Please enter title and body'); return; } const product = { title: this.title, body: this.body, userId: this.userId }; this.productService.addProduct(product) .subscribe({ next: (data) => { console.log('Added Product:', data); // JSONPlaceholder returns id 101 this.products.push(data); alert('Product Added Successfully'); this.clearForm(); }, error: (error) => { console.error('Error:', error); } }); } // ============================ // EDIT PRODUCT // ============================ editProduct(product: any): void { this.editId = product.id; this.title = product.title; this.body = product.body; this.userId = product.userId; } // ============================ // UPDATE PRODUCT // ============================ updateProduct(): void { if (this.editId === null) { return; } const product = { id: this.editId, title: this.title, body: this.body, userId: this.userId }; this.productService.updateProduct(this.editId, product) .subscribe({ next: (data) => { console.log('Updated Product:', data); // Find product index const index = this.products.findIndex( p => p.id === this.editId ); // Update local array if (index !== -1) { this.products[index] = data; } alert('Product Updated Successfully'); this.clearForm(); }, error: (error) => { console.error('Error:', error); } }); } // ============================ // DELETE PRODUCT // ============================ deleteProduct(id: number): void { if (!confirm('Are you sure you want to delete this product?')) { return; } this.productService.deleteProduct(id) .subscribe({ next: () => { console.log('Deleted Product:', id); // Remove from local array this.products = this.products.filter( p => p.id !== id ); alert('Product Deleted Successfully'); }, error: (error) => { console.error('Error:', error); } }); } // ============================ // CLEAR FORM // ============================ clearForm(): void { this.title = ''; this.body = ''; this.userId = 1; this.editId = null; } }


modify product.html file

<div class="container"> <h2>Product CRUD Operation</h2> <!-- ========================= --> <!-- PRODUCT FORM --> <!-- ========================= --> <div class="form"> <h3> {{ editId === null ? 'Add Product' : 'Update Product' }} </h3> <!-- User ID --> <div class="form-group"> <label>User ID</label> <input type="number" [(ngModel)]="userId" placeholder="Enter User ID" /> </div> <!-- Title --> <div class="form-group"> <label>Title</label> <input type="text" [(ngModel)]="title" placeholder="Enter Product Title" /> </div> <!-- Body --> <div class="form-group"> <label>Description</label> <textarea [(ngModel)]="body" placeholder="Enter Product Description"> </textarea> </div> <!-- Buttons --> <div class="buttons"> @if (editId === null) { <button class="add" (click)="addProduct()"> Add Product </button> } @else { <button class="update" (click)="updateProduct()"> Update Product </button> <button class="cancel" (click)="clearForm()"> Cancel </button> } </div> </div> <!-- ========================= --> <!-- PRODUCT LIST --> <!-- ========================= --> <h3>Product List</h3> <table> <thead> <tr> <th>ID</th> <th>User ID</th> <th>Title</th> <th>Description</th> <th>Actions</th> </tr> </thead> <tbody> @for (item of products; track item.id) { <tr> <td> {{ item.id }} </td> <td> {{ item.userId }} </td> <td> {{ item.title }} </td> <td> {{ item.body }} </td> <td> <button class="edit" (click)="editProduct(item)"> Edit </button> <button class="delete" (click)="deleteProduct(item.id)"> Delete </button> </td> </tr> } </tbody> </table> </div>


modify product.css file
.container { width: 90%; margin: 30px auto; font-family: Arial, sans-serif; } h2 { text-align: center; margin-bottom: 30px; } .form { width: 500px; margin: auto; padding: 20px; border: 1px solid #ddd; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); } .form h3 { margin-top: 0; } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: bold; } input, textarea { width: 100%; padding: 10px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 5px; } textarea { height: 80px; resize: none; } button { border: none; padding: 8px 14px; margin-right: 5px; border-radius: 5px; cursor: pointer; } .add { background: green; color: white; } .update { background: blue; color: white; } .cancel { background: gray; color: white; } .edit { background: orange; color: white; } .delete { background: red; color: white; } table { width: 100%; margin-top: 20px; border-collapse: collapse; } th, td { border: 1px solid #ddd; padding: 10px; text-align: left; } th { background: #f2f2f2; }

Make sure HttpClient is configured

If you are using a modern Angular standalone application, check your app.config.ts.

import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient()
  ]
};

3️⃣ Real Example – Authentication Service (Login)

📌 auth.service.ts

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

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

private isLoggedIn = false;

login(username: string, password: string) {
if (username === 'admin' && password === '1234') {
this.isLoggedIn = true;
}
}

logout() {
this.isLoggedIn = false;
}

isAuthenticated() {
return this.isLoggedIn;
}
}

📌 Use in Multiple Components

constructor(private authService: AuthService) {}

login() {
this.authService.login('admin', '1234');
}

✅ This is Dependency Injection
Angular automatically injects UserService into constructor.
it creates
import { Injectable } from '@angular/core';

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

  constructor() { }

  getUsers() {
    return ['Shiva', 'Ram', 'Sita'];
  }
}

What is providedIn: 'root'?

It means:

  • Service is available application-wide

  • Only one instance is created (Singleton)

  • Tree-shakable (removed if not used)

Dependency Injection (DI) in Angular

Dependency Injection means: Angular automatically creates and provides required dependencies.

Instead of doing this:

const userService = new UserService(); ❌ 

Angular does this internally:

constructor(private userService: UserService) {}

Why Dependency Injection is Important?
Without DI: Tight coupling Hard to test Hard to maintain With DI: Loose coupling Easy testing (Mock service) Better architecture Scalable apps

How to use Service in Component?


import { Component } from '@angular/core'; import { UserService } from './services/user.service'; @Component({ selector: 'app-home', standalone: true, template: ` <h2>User List</h2> <div *ngFor="let user of users"> {{ user }} </div> ` }) export class HomeComponent { users: string[] = []; constructor(private userService: UserService) { this.users = this.userService.getUsers(); } }

Types of Service Providers in Angular 21

Root Level (Global Singleton)
@Injectable({ providedIn: 'root' })

Component Level (New Instance per Component)

@Component({

providers: [UserService] })

Each component gets its own instance. Use when: You want isolated state Component-specific logic

Injecting Service using inject()

(Modern Angular 21 Way)

Instead of constructor injection:

import { inject } from '@angular/core'; export class HomeComponent { private userService = inject(UserService); users = this.userService.getUsers(); }

✔ Cleaner
✔ Works well with signals
✔ Recommended in modern Angular





Post a Comment

0 Comments