Tantangan RxJS: Minggu 1

Bekerja dengan Angular mau tidak mau, Anda akan menggunakan RxJS, karena RxJS berada di jantung kerangka kerja. Ini adalah alat yang sangat kuat untuk menangani acara dan banyak lagi. Namun, tidak setiap proyek memanfaatkannya sepenuhnya. Seringkali ini hanya permintaan untuk dukungan, transformasi data sederhana dan langganan. Kami Roma sangat menyukai RxJS dan memutuskan untuk mengumpulkan beberapa studi kasus yang menarik dari praktik kami. Kami membuat sesuatu seperti tantangan untuk 20 masalah dari ini, yang kami usulkan untuk diselesaikan dengan RxJS dan melatih keterampilan Anda.





Setiap teka-teki akan memiliki boilerplate untuk memudahkan Anda memulai. Di bawah spoiler, saya akan meletakkan tautan ke solusi saya dan sedikit penjelasan untuk itu. Secara umum, tugas akan berubah dari yang sederhana menjadi yang rumit, dan koleksi lengkap dengan jawaban dan penjelasan dalam bahasa Inggris tersedia di GitHub.





​ #1. Observable

. , .





StackBlitz





focusin



focusout



, focus



/blur



. target



relatedTarget



, document.activeElement



body



. , null



. — . , , : defer(() => of(documentRef.activeElement))



. merge



:





@Injectable()
export class FocusWithinService extends Observable<Element | null> {
  constructor(
    @Inject(DOCUMENT) documentRef: Document,
    { nativeElement }: ElementRef<HTMLElement>
  ) {
    const focusedElement$ = merge(
      defer(() => of(documentRef.activeElement)),
      fromEvent(nativeElement, "focusin").pipe(map(({ target }) => target)),
      fromEvent(nativeElement, "focusout").pipe(
        map(({ relatedTarget }) => relatedTarget)
      )
    ).pipe(
      map(element =>
        element && nativeElement.contains(element) ? element : null
      ),
      distinctUntilChanged(),
    );

    super(subscriber => focusedElement$.subscribe(subscriber));
  }
}
      
      



StackBlitz





​ #2.

RxJS — Page Visibility API. InjectionToken.





. — . , , . defer



, , , map :





export const PAGE_VISIBILITY = new InjectionToken<Observable<boolean>>(
  "Shared Observable based on `document visibility changed`",
  {
    factory: () => {
      const documentRef = inject(DOCUMENT);

      return fromEvent(documentRef, "visibilitychange").pipe(
        startWith(0),
        map(() => documentRef.visibilityState !== "hidden"),
        distinctUntilChanged(),
        shareReplay()
      );
    }
  }
);
      
      



DI- . .





StackBlitz





​ #3. 5

, . , . , 5 . :





StackBlitz





, , . Subject



, Observable



, :





readonly submit$ = new Subject<void>();

readonly request$ = this.submit$.pipe(
  switchMapTo(this.service.pipe(startWith(""))),
  share(),
);
      
      



. share , .





. , :





readonly user$ = this.request$.pipe(retry());
      
      



, , 5 :





readonly error$ = this.request$.pipe(
  ignoreElements(),
  catchError(e => of(e)),
  repeat(),
  switchMap(e => timer(5000).pipe(startWith(e)))
);
      
      



. repeat retry: , , , . , .





StackBlitz





​ #4.

, . , RxJS fetch



:





.





StackBlitz





, , Subject



. — . :





readonly progress$ = this.response$.pipe(filter(Number.isFinite));
      
      



— , :





readonly result$ = this.response$.pipe(
  map(response => typeof response === "string" ? response : null),
  distinctUntilChanged()
);
      
      



StackBlitz





​ #5.

, , . RxJS. CSS, SMS JavaScript ​





StackBlitz





, takeWhile



:





function countdownFrom(start: number): Observable<number> {
  return timer(0, 1000).pipe(
    map(index => start - index),
    takeWhile(Boolean, true)
  );
}
      
      



, 0



, , . switchMapTo



Subject



, , . :





<ng-container *ngIf="countdown$ | async as value else resend">
  Resend code in {{ value }} sec.
</ng-container>
<ng-template #resend>
  <button (click)="resend$.next()">Resend code</button>
</ng-template>
      
      



0 ngIf .





CSS- :active



. CSS- :





StackBlitz





. 15 RxJS. .








All Articles