Angular xizmatlar va DI


Xizmatlar qayta foydalanish mumkin bo‘lgan mantiqni tartibga soladi va tarkibiy qismlardan tashqari holat.


ULASHISH

Xizmatlar va DI Essentials

  • Nima: Xizmat qayta foydalanish mumkin bo‘lgan mantiq/holatga ega. DI (qaramlik kiritish) kerak bo‘lganda misollarni ta’minlaydi.
  • Qo‘llanish doirasi: Umumiy singl uchun root da taqdim eting yoki alohida misollar uchun komponentni taqdim eting.
  • Foydalanish holatlari: ma’lumotlarni olish, keshlash, biznes qoidalari, o‘zaro componentlar holati.
  • Aqliy model: DI quvvat manbaiga o‘xshaydi: siz ulang va Angular sizga tayyor namunani beradi.
  • Dekorator: Boshqa xizmatlarni kiritadigan classlarda @Injectable() dan foydalaning.
import { Injectable } from '@angular/core';

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

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

Eslatmalar:

  • Tegishli: Xizmatlarni iste’mol qilish uchun componentlar, xizmatlardan foydalanadigan qo‘riqchilar uchun Router va ma’lumotlarni oladigan xizmatlar uchun HTTP-ga qarang.
  • Ilova miqyosidagi singletonlar uchun @Injectable({ providedIn: 'root' }) dan foydalaning.
  • Izolyatsiya qilingan misollar kerak bo‘lganda komponentni taqdim eting.
  • Konstruktorlardan tashqari bog‘liqliklarni olish uchun marshrut qo‘riqchilari kabi funksiyalarda inject() dan foydalaning.

Xizmat asoslari

  • Darslarni @Injectable() bilan bezang (agar ular boshqa xizmatlarni kiritsa, talab qilinadi).
  • Komponentlarda foydalanish uchun xizmatlarni konstruktorlarga kiriting.
  • Umumiy singleton uchun providedIn: 'root'’dan foydalaning.
@Injectable({ providedIn: 'root' })
export class DataService {}

// class App { constructor(private data: DataService) {} }

Misol

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);
<app-root></app-root>

Misolni ishga tushirish »

Misol tushuntirildi

  • @Injectable({ providedIn: 'root' }): Ilova bo‘ylab mavjud bo‘lgan singleton xizmatini ro‘yxatdan o‘tkazadi.
  • Inject in konstruktor: constructor(public counter: CounterService) xizmatni shablonga ochib beradi.
  • Metodlar: Umumiy holatni yangilash uchun inc() / dec() / reset() metodlarini chaqiring.

Eslatmalar:

  • In’ektsiya paytida metama’lumotlar talab qilinadi: Agar xizmat boshqa xizmatlarni kiritsa, DI metadata yaratishi uchun @Injectable() ni qo‘shing.
  • Minimal holatni saqlang: xizmatlarda katta umumiy o‘zgaruvchan holatdan saqlaning; Aniq usullardan foydalaning va qiymatlarni qaytaring.
  • Mustaqil yuklash: Provayderlar kerak bo‘lganda ro‘yxatdan o‘tganligiga ishonch hosil qiling va funktsional konstruktsiyalarda (masalan, qo‘riqchilar) inject() dan foydalaning.


componentlar bo‘yicha umumiy xizmat

  • providedIn: 'root' butun ilova bo‘ylab bitta nusxani ulashadi.
  • Bitta komponentda yangilanish boshqalarda xuddi shu xizmatdan foydalanishni aks ettiradi.
<counter-a></counter-a>
<counter-b></counter-b>
<!-- Both use the same service instance -->

Misol

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);
<app-root></app-root>

Misolni ishga tushirish »

Misol tushuntirildi

  • providedIn: 'root' butun ilova bo‘ylab bitta nusxani ulashadi.
  • Umumiy holat: Bir komponentda +/− tugmasini bosish ikkinchisida ko‘rsatilgan qiymatni yangilaydi.
  • Shablonga kirish: Shablon counter.value ni o‘qiy olishi va metodlarni chaqira olishi uchun public sifatida kiritilgan.

Eslatmalar:

  • Singleton va mahalliy: providedIn: 'root' bitta umumiy misolni beradi; komponentda taqdim etish har bir kichik daraxt uchun alohida misollarni yaratadi.
  • Qamrash haqida o‘ylang: kutilmagan hodisalarga yo‘l qo‘ymaslik uchun ulashish ehtiyojlaringizga mos keladigan darajada taqdim eting.

Komponent taqdim etgan servis (ierarxik DI)

  • Komponentning providers-da uning pastki daraxti uchun mahalliy misol yaratish uchun xizmatni taqdim eting.
  • Qardosh pastki daraxtlar alohida misollarni oladi.
@Component({ providers: [LocalCounterService] })
export class Panel {}

Misol

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);
<app-root></app-root>

Misolni ishga tushirish »

Misol tushuntirildi

  • providers: [LocalCounterService] : Har bir panel komponenti o‘zining pastki daraxti uchun o‘z xizmat namunasini oladi.
  • Panel ichida: Bir nechta CounterView bolalari bir xil mahalliy misolni baham ko‘radi.
  • Panellar o‘rtasida: Panel A va Panel B turli misollarga ega (turli id ​​qiymatlarini ko‘ring).

Eslatmalar:

  • Kutilayotgan bir nechta misollar: Har bir taqdim etilgan component quyi daraxti o‘z namunasini oladi; birodarlar buni baham ko‘rmaydilar.
  • Doiraviy bog‘liqlikdan saqlaning: bir-birini in’ektsiya qiladigan ikkita xizmat muvaffaqiyatsiz bo‘ladi; uchinchi xizmatga umumiy mantiqni ajratib oling yoki qayta loyihalash.

Xizmatni loyihalash bo‘yicha maslahatlar

Xizmatlarni diqqat markazida tuting va oson sinovdan o‘tkazing:

  • Komponentlarni ulashdan saqlaning: komponentlarni xizmatlarga kiritmang; xizmatlarni UI-agnostik holda saqlang.
  • Aniq API’larni ko‘rsatish: Oddiy qiymatlarni yoki Kuzatiladiganlarni qaytaruvchi kichik usullardan foydalaning; ichki holatni maxfiy saqlang.
  • Tokenlar orqali konfiguratsiya: Sinov va qayta foydalanishni soddalashtirish uchun sozlanishi qiymatlar uchun inyeksion tokenlardan (noyob qidirish kaliti, odatda class yoki InjectionToken obyekti) foydalaning.
  • Qasddan qamrov: Ilova miqyosidagi singletonlar uchun providedIn: 'root' dan foydalaning; alohida holatlar uchun komponentni taqdim eting.


W3Schools Pathfinder

Yutuqlaringizni kuzating – bu bepul!