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."
providedIn: 'root' → Service is Singleton (one instance in entire app)Step 2: Inject Service in Component
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 Operation1. 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,
datais the successful response.Object syntax
this.productService.getProducts() .subscribe({ next: (data) => { console.log(data); }, error: (err) => { console.log(err); }, complete: () => { console.log('Completed'); } });Here:
Property Meaning nextData successfully received errorSomething went wrong completeObservable has finished Modify ProductService.ts fileimport { 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.tsimport { 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
HttpClientis configuredIf 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 injectsUserServiceinto constructor.
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:

0 Comments
POST Answer of Questions and ASK to Doubt