בספרית rxjs יש מספר סוגים של subject , כל אחד והיעוד שלו (והיתרון שלו).
הפעם אנחנו נראה איך להשתמש ב-behaviorSubject בקובץ service.
היתרון של behaviorSubject הוא העובדה שהוא דורש איתחול כבר בהתחלה, כך שאנחנו יכולים לשלוט מה ערך ברירת המחדל שלו עוד לפני שהגיע המידע האמיתי.
כך ניתן להשען על מידע זה בקומפוננטות שמשתמשות בשירות שלו.
אם ברירת המחדל שלו זה מערך ריק אנחנו נוכל להפעיל בקומפוננטה ngIf שיראה תגית מסויימת רק אם יש מידע (המערך גדול יותר מ-0).
הנה דוגמא ליצירה של שירות כזה:
import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; import { IData } from './interfaces/my-interface.interface'; import { serverData } from './serverData.mock'; @Injectable({ providedIn: 'root' }) export class MyService { private serverDataSubject: BehaviorSubject<IData[]> = new BehaviorSubject<IData[]>([]); public serverDataSubject$: Observable<IData[]> = this.serverDataSubject.asObservable(); constructor() { } getServerData(){ setTimeout(() => { this.serverDataSubject.next(serverData); }, 1000); } }
אפשר לראות שאין גישה ישירה ל-behaviorSubject שמחזיק במידע עצמו, אלא למשתנה שמסתכל עליו בשם serverDataSubject$.
הקומפוננטה שרוצה למשוך מידע מהשירות תיצור חיבור ל- serverDataSubject$ ועל ידי הרצה של הפונקציה getServerData , היא תתעדכן.
גם הפונקציה getServerData חשופה לכל הקומפוננטות בפרויקט וכל קומפוננטה שתריץ אותה תגרום לעדכון של כל מי שמחובר ל-serverDataSubject$.
כרגע המידע נלקח מקובץ mock המשמש תחליף לקיראה של AJAX ולכן הוא גם עטוף ב- setTimeout כדי להמחיש התנהגות של קריאה לשרת > המתנה עד לקבלת תשובה > המידע עצמו.
בתוך ההשהיה ניתן לראות את העדכון שהוא מבוצע ע"י קריאה ל-next עם תוכן של מידע – serverData.
עכשיו נראה איך צד מבקש השירות ניראה:
import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { IData } from './interfaces/my-interface.interface'; import { MyService } from './my-service.service'; @Component({ selector: 'app-my-comp', templateUrl: './my-comp.component.html', styleUrls: ['./my-comp.component.scss'] }) export class MyCompComponent implements OnInit { myData$: Observable<IData[]>; constructor(private myDataService: MyService) { } ngOnInit() { this.myData$ = this.myDataService.serverDataSubject$; this.myDataService.getServerData(); } }
בשורה 13 הקמנו Observable כדי לחבר אותו למידע שמגיע מהשירות.
בשורה 15 הוספנו את השירות עצמו.
בשורה 18 חיברנו בין המשתנה המקומי של הקומפוננטה לבין המשתנה של השירות.
בשורה 19 הפעלנו את הפונקציה של השירות כדי שתעדכן את המידע מה-mock. כמובן שלא חייבים מידי להפעיל אותה אלא אפשר בלחיצת כפתור של המשתמש או מקומפוננטה אחרת…
זהו זה! עכשיו כל מה שאנחנו צריכים לעשות הוא להשתמש במשתנה המקומי שלנו בשביל להציג מידע או להעביר אותו לקומפוננטות אחרות או לשנות אותו.
המלצה:
אני אוהב להשתמש ב- myData$ בצד ה-HTML בצורה הבאה:
<div> <app-child-comp *ngIf="myData$|async as myData" [inputData]="myData"></app-child-comp> </div>
כך אני מודא שרק כאשר המידע מגיע, הקומפוננטה תוצג ובנוסף אני משנה את השם (לאיזה שם שארצה) למשהו יותר נוח.
במקרה הזה, אני מעביר את המידע מהאבא לילד.