فهرست سرفصل‌های Angular
خانه (Home) معرفی (Intro) شروع سریع (Get Started) اولین اپ (First App) قالب ها (Templates) جای گذاری (Interpolation) متغیرهای ارجاعی (Reference Variables) ناوبری امن از نال (?.) (Null-Safe Navigation (?.)) دستورهای ساختاری (Structural Directives) ngTemplateOutlet (ngTemplateOutlet) عبارات و $event (Statements and $event) نام مستعار (Alias) پایپ ها (|) (Pipes (|)) بایندینگ ویژگی (Attribute Binding) TrackBy (TrackBy) کامپوننت ها (Components) دیتا بایندینگ (Data Binding) دایرکتیوها (Directives) رویدادها (Events) رندر شرطی (Conditional) لیست ها (Lists) فرم ها (Forms) روتر (Router) سرویس ها و تزریق وابستگی (Services & DI) کلاینت HTTP (HTTP Client) پایپ ها (Pipes) قلاب های چرخه حیات (Lifecycle Hooks) استایل دهی (Styling) راه اندازی برنامه (App Bootstrap) کنترل جریان (Control Flow) سیگنال ها (Signals) تشخیص تغییر (Change Detection) کامپوننت های پویا (Dynamic Comp) تزریق وابستگی پیشرفته (Advanced DI) روتر پیشرفته (Router Advanced) اینترسپتورهای HTTP (HTTP Interceptors) فرم های پیشرفته (Forms Advanced) مدیریت وضعیت (State Management) انیمیشن ها (Animations) تست (Testing) امنیت (Security) SSR و هیدریشن (SSR & Hydration) کامپایلر (Compiler) تمرین ها (Exercises) آزمون (Quiz) سرور (Server)
نتیجه‌ای برای جستجو یافت نشد.
Angular

Angular — سرویس ها و تزریق وابستگی (Services & DI)

آخرین بروزرسانی: 1404/08/21

سرویس ها و تزریق وابستگی (Services & DI)

«سرویس ها در انگولار» منطقِ تکراری را جدا نگه می دارند. «تزریق وابستگی (Dependency Injection)» یعنی گرفتنِ آماده سرویس، مثل برقِ پریز. بنابراین کدها تمیزتر می شوند و بین کامپوننت ها به راحتی اشتراک دارند.

مبانی سرویس و DI

«سرویس (Service)» کلاس منطق و وضعیت اشتراکی است. «DI» نمونه سرویس را هرجا بخواهی می دهد. برای اشتراک سراسری از providedIn: 'root' استفاده کن. برای نمونه جدا، سرویس را داخل یک کامپوننت providers بده.

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

@Injectable({ providedIn: 'root' })
export class CounterService {
  value = 0;
  inc() {
    this.value++;
  }
}

// Inject in a component
// constructor(public counter: CounterService) {}

مشاهده در ادیتور

نکته: اگر سرویسی سرویس دیگر می گیرد، حتماً @Injectable() بگذار تا DI کار کند.

سرویس پایه با singleton ریشه

با @Injectable({ providedIn: 'root' }) یک نمونه سراسری بساز. سپس آن را در سازنده کامپوننت تزریق کن. در نتیجه، وضعیت بین نماها مشترک می ماند.

import { bootstrapApplication } from '@angular/platform-browser';
import { Component, Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class CounterService {
  value = 0;
  inc() {
    this.value++;
  }
  dec() {
    this.value--;
  }
  reset() {
    this.value = 0;
  }
}

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <h3>Services</h3>
    <p>Counter: {{ counter.value }}</p>
    <button (click)="counter.inc()">+</button>
    <button (click)="counter.dec()">-</button>
    <button (click)="counter.reset()">Reset</button>
  `
})
export class App {
  constructor(public counter: CounterService) {}
}

bootstrapApplication(App);

مشاهده در ادیتور

اشتراک سرویس بین کامپوننت ها

وقتی سرویس در ریشه است، همه کامپوننت ها همان نمونه را می بینند. بنابراین تغییر در یکی، در دیگری هم دیده می شود. مثل scoreboard مشترک در یک بازی.

import { bootstrapApplication } from '@angular/platform-browser';
import { Component, Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class CounterService {
  value = 0;
  inc() {
    this.value++;
  }
  dec() {
    this.value--;
  }
}

@Component({
  selector: 'counter-a',
  standalone: true,
  template: `
    <h4>Counter A</h4>
    <p>Value: {{ counter.value }}</p>
    <button (click)="counter.inc()">+1</button>
    <button (click)="counter.dec()">-1</button>
  `
})
export class CounterA {
  constructor(public counter: CounterService) {}
}

@Component({
  selector: 'counter-b',
  standalone: true,
  template: `
    <h4>Counter B</h4>
    <p>Value: {{ counter.value }}</p>
    <button (click)="counter.inc()">+1</button>
    <button (click)="counter.dec()">-1</button>
  `
})
export class CounterB {
  constructor(public counter: CounterService) {}
}

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CounterA, CounterB],
  template: `
    <h3>Shared Service Across Components</h3>
    <counter-a></counter-a>
    <counter-b></counter-b>
    <p><em>Both components use the same CounterService instance.</em></p>
  `
})
export class App {}

bootstrapApplication(App);

مشاهده در ادیتور

DI سلسله مراتبی با providers کامپوننت

اگر سرویس را داخل یک کامپوننت providers بدهی، هر زیر درخت نمونه جدا می گیرد. بنابراین دو پنل مجزا، مقدارهای مستقل دارند. این برای جداسازی عالی است.

import { bootstrapApplication } from '@angular/platform-browser';
import { Component, Injectable } from '@angular/core';
import { CommonModule } from '@angular/common';

@Injectable()
export class LocalCounterService {
  id = Math.floor(Math.random() * 10000);
  value = 0;
  inc() {
    this.value++;
  }
}

@Component({
  selector: 'counter-view',
  standalone: true,
  template: `
    <p>Service #{{ svc.id }} value: {{ svc.value }}</p>
    <button (click)="svc.inc()">+1</button>
  `
})
export class CounterView {
  constructor(public svc: LocalCounterService) {}
}

@Component({
  selector: 'panel-a',
  standalone: true,
  imports: [CommonModule, CounterView],
  providers: [LocalCounterService],
  template: `
    <h4>Panel A (own provider)</h4>
    <counter-view></counter-view>
    <counter-view></counter-view>
  `
})
export class PanelA {}

@Component({
  selector: 'panel-b',
  standalone: true,
  imports: [CommonModule, CounterView],
  providers: [LocalCounterService],
  template: `
    <h4>Panel B (own provider)</h4>
    <counter-view></counter-view>
    <counter-view></counter-view>
  `
})
export class PanelB {}

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, PanelA, PanelB],
  styles: [`
    .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; }
    h4 { margin: 0 0 8px; }
    button { margin-top: 6px; }
  `],
  template: `
    <h3>Component-Provided Service (Hierarchical DI)</h3>
    <p>Each panel provides its own service instance.</p>
    <p>Counters inside the same panel share the instance.</p>
    <p>Different panels do not.</p>
    <div class="grid">
      <panel-a></panel-a>
      <panel-b></panel-b>
    </div>
  `
})
export class App {}

bootstrapApplication(App);

مشاهده در ادیتور

هشدار: وابستگیِ حلقه ای نساز. اگر دو سرویس هم دیگر را می خواهند، منطق مشترک را جدا کن.

گام های عملی سریع

  1. یک کلاس سرویس با @Injectable() بساز.
  2. برای singleton، providedIn: 'root' تنظیم کن.
  3. سرویس را در سازنده کامپوننت تزریق کن.

جمع بندی سریع

  • سرویس ها منطق مشترک را متمرکز می کنند.
  • DI نمونه سرویس را آماده می دهد.
  • ریشه برای اشتراک، کامپوننت برای جداسازی است.
  • @Injectable برای متادیتای تزریق ضروری است.

نکته: برای مسیرها به روتر در انگولار برو. برای دریافت داده به HTTP در انگولار سر بزن.