Skip to content

Commit 70056a8

Browse files
Closes #3344, #3345
BREAKING CHANGES: 1. The context of `LetDirective` is strongly typed when `null` or `undefined` is passed as input. BEFORE: ```html <p *ngrxLet="null as n">{{ n }}</p> <p *ngrxLet="undefined as u">{{ u }}</p> ``` - The type of `n` is `any`. - The type of `u` is `any`. AFTER: ```html <p *ngrxLet="null as n">{{ n }}</p> <p *ngrxLet="undefined as u">{{ u }}</p> ``` - The type of `n` is `null`. - The type of `u` is `undefined`. --- 2. Arrays, iterables, generator functions, and readable streams are not treated as observable-like inputs anymore. To keep the same behavior as in v13, convert the array/iterable/generator function/readable stream to observable using the `from` function from the `rxjs` package before passing it to the `LetDirective`/`PushPipe`. BEFORE: ```ts @component({ template: ` <p *ngrxLet="numbers as n">{{ n }}</p> <p>{{ numbers | ngrxPush }}</p> `, }) export class NumbersComponent { numbers = [1, 2, 3]; } ``` AFTER: ```ts @component({ template: ` <p *ngrxLet="numbers$ as n">{{ n }}</p> <p>{{ numbers$ | ngrxPush }}</p> `, }) export class NumbersComponent { numbers$ = from([1, 2, 3]); } ```
1 parent 5188b68 commit 70056a8

File tree

14 files changed

+437
-102
lines changed

14 files changed

+437
-102
lines changed

modules/component/spec/core/potential-observable.spec.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,30 @@ describe('fromPotentialObservable', () => {
1111
};
1212
}
1313

14-
function testNullishInput(input: null | undefined): void {
15-
it(`should create observable from ${input}`, () => {
14+
function testNonObservableInput(input: any, label = input): void {
15+
it(`should create observable from ${label}`, () => {
1616
const { testScheduler } = setup();
1717

1818
testScheduler.run(({ expectObservable }) => {
1919
const obs$ = fromPotentialObservable(input);
20-
expectObservable(obs$).toBe('(x|)', { x: input });
20+
expectObservable(obs$).toBe('x', { x: input });
2121
});
2222
});
2323
}
2424

25-
testNullishInput(null);
25+
testNonObservableInput(null);
2626

27-
testNullishInput(undefined);
27+
testNonObservableInput(undefined);
2828

29-
it('should create observable from array', () => {
30-
const { testScheduler } = setup();
31-
const array = [1, 2, 3];
29+
testNonObservableInput(100, 'number');
3230

33-
testScheduler.run(({ expectObservable }) => {
34-
const obs$ = fromPotentialObservable(array);
35-
expectObservable(obs$).toBe('(xyz|)', { x: 1, y: 2, z: 3 });
36-
});
37-
});
31+
testNonObservableInput('ngrx', 'string');
32+
33+
testNonObservableInput(true, 'boolean');
34+
35+
testNonObservableInput({ ngrx: 'component' }, 'object');
36+
37+
testNonObservableInput([1, 2, 3], 'array');
3838

3939
it('should create observable from promise', (done) => {
4040
const promise = Promise.resolve(100);

modules/component/spec/helpers.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function stripSpaces(str: string): string {
2+
return str.replace(/[\n\r\s]+/g, '');
3+
}
4+
5+
export function wrapWithSpace(str: string): string {
6+
return ' ' + str + ' ';
7+
}

modules/component/spec/let/let.directive.spec.ts

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ import {
2020
EMPTY,
2121
interval,
2222
NEVER,
23-
Observable,
24-
ObservableInput,
2523
of,
2624
switchMap,
2725
take,
@@ -30,6 +28,7 @@ import {
3028
} from 'rxjs';
3129
import { LetDirective } from '../../src/let/let.directive';
3230
import { MockChangeDetectorRef, MockErrorHandler } from '../fixtures/fixtures';
31+
import { stripSpaces } from '../helpers';
3332

3433
@Component({
3534
template: `
@@ -42,7 +41,7 @@ import { MockChangeDetectorRef, MockErrorHandler } from '../fixtures/fixtures';
4241
`,
4342
})
4443
class LetDirectiveTestComponent {
45-
value$!: Observable<number>;
44+
value$: unknown;
4645
}
4746

4847
@Component({
@@ -116,7 +115,7 @@ class LetDirectiveTestRecursionComponent {
116115

117116
let fixtureLetDirectiveTestComponent: ComponentFixture<LetDirectiveTestComponent>;
118117
let letDirectiveTestComponent: {
119-
value$: ObservableInput<any> | undefined | null;
118+
value$: unknown;
120119
};
121120
let componentNativeElement: any;
122121

@@ -257,6 +256,38 @@ describe('LetDirective', () => {
257256
expect(componentNativeElement.textContent).toBe('null');
258257
});
259258

259+
it('should render initially passed number', () => {
260+
letDirectiveTestComponent.value$ = 10;
261+
fixtureLetDirectiveTestComponent.detectChanges();
262+
expect(componentNativeElement.textContent).toBe('10');
263+
});
264+
265+
it('should render initially passed string', () => {
266+
letDirectiveTestComponent.value$ = 'ngrx';
267+
fixtureLetDirectiveTestComponent.detectChanges();
268+
expect(componentNativeElement.textContent).toBe('"ngrx"');
269+
});
270+
271+
it('should render initially passed boolean', () => {
272+
letDirectiveTestComponent.value$ = true;
273+
fixtureLetDirectiveTestComponent.detectChanges();
274+
expect(componentNativeElement.textContent).toBe('true');
275+
});
276+
277+
it('should render initially passed object', () => {
278+
letDirectiveTestComponent.value$ = { ngrx: 'component' };
279+
fixtureLetDirectiveTestComponent.detectChanges();
280+
expect(stripSpaces(componentNativeElement.textContent)).toBe(
281+
'{"ngrx":"component"}'
282+
);
283+
});
284+
285+
it('should render initially passed array', () => {
286+
letDirectiveTestComponent.value$ = [1, 2, 3];
287+
fixtureLetDirectiveTestComponent.detectChanges();
288+
expect(stripSpaces(componentNativeElement.textContent)).toBe('[1,2,3]');
289+
});
290+
260291
it('should render undefined as value when initially of(undefined) was passed (as undefined was emitted)', () => {
261292
letDirectiveTestComponent.value$ = of(undefined);
262293
fixtureLetDirectiveTestComponent.detectChanges();
@@ -304,7 +335,7 @@ describe('LetDirective', () => {
304335
expect(componentNativeElement.textContent).toBe('undefined');
305336
});
306337

307-
it('should render new value as value when a new observable was passed', () => {
338+
it('should render new value when a new observable was passed', () => {
308339
letDirectiveTestComponent.value$ = of(42);
309340
fixtureLetDirectiveTestComponent.detectChanges();
310341
expect(componentNativeElement.textContent).toBe('42');
@@ -339,40 +370,23 @@ describe('LetDirective', () => {
339370
expect(componentNativeElement.textContent).toBe('2');
340371
}));
341372

342-
it('should render new value as value when a new observable was passed', () => {
343-
letDirectiveTestComponent.value$ = of(42);
373+
it('should render non-observable value when it was passed after observable', () => {
374+
letDirectiveTestComponent.value$ = of(100);
344375
fixtureLetDirectiveTestComponent.detectChanges();
345-
expect(componentNativeElement.textContent).toBe('42');
346-
letDirectiveTestComponent.value$ = of(45);
376+
expect(componentNativeElement.textContent).toBe('100');
377+
letDirectiveTestComponent.value$ = 200;
347378
fixtureLetDirectiveTestComponent.detectChanges();
348-
expect(componentNativeElement.textContent).toBe('45');
379+
expect(componentNativeElement.textContent).toBe('200');
349380
});
350381

351-
it('should render the last value when a new observable was passed', () => {
352-
letDirectiveTestComponent.value$ = of(42, 45);
382+
it('should render non-observable value when it was passed after another non-observable', () => {
383+
letDirectiveTestComponent.value$ = 'ngrx';
353384
fixtureLetDirectiveTestComponent.detectChanges();
354-
expect(componentNativeElement.textContent).toBe('45');
355-
});
356-
357-
it('should render values over time when a new observable was passed', fakeAsync(() => {
358-
letDirectiveTestComponent.value$ = interval(1000).pipe(take(3));
359-
fixtureLetDirectiveTestComponent.detectChanges();
360-
expect(componentNativeElement.textContent).toBe('');
361-
tick(1000);
362-
fixtureLetDirectiveTestComponent.detectChanges();
363-
expect(componentNativeElement.textContent).toBe('0');
364-
tick(1000);
385+
expect(componentNativeElement.textContent).toBe('"ngrx"');
386+
letDirectiveTestComponent.value$ = 'component';
365387
fixtureLetDirectiveTestComponent.detectChanges();
366-
expect(componentNativeElement.textContent).toBe('1');
367-
tick(1000);
368-
fixtureLetDirectiveTestComponent.detectChanges();
369-
expect(componentNativeElement.textContent).toBe('2');
370-
371-
tick(1000);
372-
fixtureLetDirectiveTestComponent.detectChanges();
373-
// Remains at 2, since that was the last value.
374-
expect(componentNativeElement.textContent).toBe('2');
375-
}));
388+
expect(componentNativeElement.textContent).toBe('"component"');
389+
});
376390
});
377391

378392
describe('when error', () => {

0 commit comments

Comments
 (0)