Components should focus on the screen. Logic that is not about drawing, such as loading data, calculating prices or remembering the signed-in user, belongs somewhere else. In Angular that place is a service, and the way components get hold of services is called dependency injection.
What you will learn
- What a service is and why it helps
- What dependency injection means in simple terms
- How to create a service and use it with
inject()
What is a service?
A service is a plain class with a job. It has no template. Components ask for it when they need it, and Angular supplies the same shared instance every time.
Good uses for services:
- Talking to a server (you will do this in the HTTP module)
- Holding data that several components share
- Business rules that you want to test on their own
What is dependency injection?
Suppose a component needs a quote service. The component could create one itself with new QuoteService(), but then it is stuck with that exact class, and it is hard to replace it in a test. With dependency injection the component only says what it needs, and Angular provides it. This keeps components simple and easy to test.
Create a service
Generate one with ng generate service quote. The CLI creates a class marked with the @Service() decorator, which tells Angular to make it available everywhere in your app. Here it is with some content:
// src/app/quote.ts
import { Service } from '@angular/core';
@Service()
export class Quote {
private readonly quotes = [
'Make it work, then make it better.',
'Small steps every day add up.',
'Read the error message. It is usually right.',
];
random(): string {
const index = Math.floor(Math.random() * this.quotes.length);
return this.quotes[index];
}
}
By default there is one instance of the service for the whole application, shared by everyone who asks for it.
Use it with inject()
Inside a component, call inject() with the class you want:
// src/app/quote-box/quote-box.ts
import { Component, inject, signal } from '@angular/core';
import { Quote } from '../quote';
@Component({
selector: 'app-quote-box',
template: `
<blockquote>{{ text() }}</blockquote>
<button type="button" (click)="next()">Another quote</button>
`,
})
export class QuoteBox {
private readonly quote = inject(Quote);
protected readonly text = signal(this.quote.random());
protected next(): void {
this.text.set(this.quote.random());
}
}
// src/app/app.ts
import { Component } from '@angular/core';
import { QuoteBox } from './quote-box/quote-box';
@Component({
imports: [QuoteBox],
selector: 'app-root',
templateUrl: './app.html',
styleUrl: './app.css',
})
export class App {}
<!-- src/app/app.html -->
<main>
<h1>Services</h1>
<app-quote-box />
</main>
The component never writes new Quote(). It asks for it with inject(Quote), and Angular hands over the shared instance. Call inject in a field initializer or the constructor, which are the places where Angular can supply it.
The older way you will still see
Before @Service(), services were written with @Injectable and an option that makes them available everywhere. Both work, and you will see the older form in most existing projects and tutorials:
// src/app/legacy-greeting.ts
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class LegacyGreeting {
hello(name: string): string {
return `Hello, ${name}!`;
}
}
Older code also injects through the constructor, such as constructor(private quote: Quote) {}. The inject() function does the same job with less code and is easier to use in functions.
Where do instances live?
- App-wide (default): one instance for the whole app, which suits data and logic you share.
- Per component: if you add the service to a component's
providerslist, each instance of that component gets its own copy. This is useful when every card needs separate state.
Try it yourself
- Add a
count()method to theQuoteservice that returns how many quotes it knows, and show it. - Create a second component that also uses
Quote. Confirm that both work. - Create a service
Greeterwith a method that returns a greeting for a name, and use it in a component.
Quick check
- What is a service?
- What does
inject(Quote)do? - How many instances of a default service does the application have?
Next, put a service to work by sharing state in Share state with a service. The dependency injection guide has the full details.