From c9e9c94e029eb70bdd9efcbc23c6134749ff560d Mon Sep 17 00:00:00 2001 From: AlirezaEbrahimkhani Date: Thu, 14 Dec 2023 20:32:10 +0330 Subject: [PATCH] feat(template): accept subscribable on rxLet input resolves #1541 --- .../src/lib/create-template-notifier.ts | 9 ++- libs/template/let/src/lib/let.directive.ts | 3 +- .../tests/let.directive.subscribable.spec.ts | 72 +++++++++++++++++++ 3 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 libs/template/let/src/lib/tests/let.directive.subscribable.spec.ts diff --git a/libs/cdk/notifications/src/lib/create-template-notifier.ts b/libs/cdk/notifications/src/lib/create-template-notifier.ts index 70eba655f8..1afe99aea5 100644 --- a/libs/cdk/notifications/src/lib/create-template-notifier.ts +++ b/libs/cdk/notifications/src/lib/create-template-notifier.ts @@ -5,6 +5,7 @@ import { Observable, ObservableInput, ReplaySubject, + Subscribable, } from 'rxjs'; import { distinctUntilChanged, @@ -91,11 +92,13 @@ const handleSuspenseAndLastValueInNotifications = () => { */ export function createTemplateNotifier(): { values$: Observable>; - next(observable: ObservableInput | U): void; + next(observable: ObservableInput | U | Subscribable): void; withInitialSuspense(withInitialSuspense: boolean): void; } { // A Subject driven from the outside, it can contain Observables, static values null and undefined on purpose of from unassigned properties - const observablesSubject = new ReplaySubject | U>(1); + const observablesSubject = new ReplaySubject< + ObservableInput | U | Subscribable + >(1); let emittedValueOnce = false; @@ -121,7 +124,7 @@ export function createTemplateNotifier(): { ); return { - next(observable: ObservableInput | U) { + next(observable: ObservableInput | U | Subscribable) { observablesSubject.next(observable); }, withInitialSuspense(withInitialSuspense: boolean) { diff --git a/libs/template/let/src/lib/let.directive.ts b/libs/template/let/src/lib/let.directive.ts index c9bbe9c41f..8bbeb65cc7 100644 --- a/libs/template/let/src/lib/let.directive.ts +++ b/libs/template/let/src/lib/let.directive.ts @@ -39,6 +39,7 @@ import { ObservableInput, ReplaySubject, Subject, + Subscribable, Subscription, } from 'rxjs'; import { filter, map } from 'rxjs/operators'; @@ -130,7 +131,7 @@ export class RxLet implements OnInit, OnDestroy, OnChanges { * * @param { ObservableInput | U | null | undefined } rxLet */ - @Input() rxLet: ObservableInput | U | null | undefined; + @Input() rxLet: ObservableInput | Subscribable | U | null | undefined; /** * @description diff --git a/libs/template/let/src/lib/tests/let.directive.subscribable.spec.ts b/libs/template/let/src/lib/tests/let.directive.subscribable.spec.ts new file mode 100644 index 0000000000..9087a6e6a7 --- /dev/null +++ b/libs/template/let/src/lib/tests/let.directive.subscribable.spec.ts @@ -0,0 +1,72 @@ +import { RxLet } from '../let.directive'; +import { TestBed, fakeAsync } from '@angular/core/testing'; +import { + ChangeDetectorRef, + Component, + TemplateRef, + ViewContainerRef, +} from '@angular/core'; +import { Subscribable, BehaviorSubject, Observable } from 'rxjs'; +import { MockChangeDetectorRef } from './fixtures'; +import { RX_RENDER_STRATEGIES_CONFIG } from '@rx-angular/cdk/render-strategies'; +import { mockConsole } from '@test-helpers/rx-angular'; + +@Component({ + template: ` + +
{{ val }}
+
+ `, +}) +class LetDirectiveTestComponent { + value$: Subscribable = new BehaviorSubject(0); +} + +let fixtureLetDirectiveTestComponent: any; +let letDirectiveTestComponent: { + strategy: string; + value$: Observable | unknown | undefined | null; +}; +let componentNativeElement: any; + +const setupLetDirectiveTestComponent = (): void => { + TestBed.configureTestingModule({ + declarations: [LetDirectiveTestComponent], + imports: [RxLet], + providers: [ + { provide: ChangeDetectorRef, useClass: MockChangeDetectorRef }, + TemplateRef, + ViewContainerRef, + { + provide: RX_RENDER_STRATEGIES_CONFIG, + useValue: { + primaryStrategy: 'native', + }, + }, + ], + teardown: { destroyAfterEach: true }, + }); + fixtureLetDirectiveTestComponent = TestBed.createComponent( + LetDirectiveTestComponent + ); + letDirectiveTestComponent = + fixtureLetDirectiveTestComponent.componentInstance; + componentNativeElement = fixtureLetDirectiveTestComponent.nativeElement; +}; + +describe('RxLet Directive with Subscribable input', () => { + beforeAll(() => mockConsole()); + beforeEach(setupLetDirectiveTestComponent); + + it('should be instantiable', () => { + expect(fixtureLetDirectiveTestComponent).toBeDefined(); + expect(letDirectiveTestComponent).toBeDefined(); + expect(componentNativeElement).toBeDefined(); + }); + + it('should display value from Subscribable', fakeAsync(() => { + letDirectiveTestComponent.value$ = 42; + fixtureLetDirectiveTestComponent.detectChanges(); + expect(componentNativeElement.textContent.trim()).toBe('42'); + })); +});