Skip to content

Commit ec59c4b

Browse files
feat(component): clear LetDirective view when replaced observable is in suspense state (#3671)
BREAKING CHANGES: The `LetDirective` view will be cleared when the replaced observable is in a suspense state. Also, the `suspense` property is removed from the `LetViewContext` because it would always be `false` when the `LetDirective` view is rendered. Instead of `suspense` property, use the suspense template to handle the suspense state. BEFORE: The `LetDirective` view will not be cleared when the replaced observable is in a suspense state and the suspense template is not passed: ```ts @component({ template: ` <!-- When button is clicked, the 'LetDirective' view won't be cleared. --> <!-- Instead, the value of 'o' will be 'undefined' until the replaced --> <!-- observable emits the first value (after 1 second). --> <p *ngrxLet="obs$ as o">{{ o }}</p> <button (click)="replaceObs()">Replace Observable</button> ` }) export class TestComponent { obs$ = of(1); replaceObs(): void { this.obs$ = of(2).pipe(delay(1000)); } } ``` AFTER: The `LetDirective` view will be cleared when the replaced observable is in a suspense state and the suspense template is not passed: ```ts @component({ template: ` <!-- When button is clicked, the 'LetDirective' view will be cleared. --> <!-- The view will be created again when the replaced observable --> <!-- emits the first value (after 1 second). --> <p *ngrxLet="obs$ as o">{{ o }}</p> <button (click)="replaceObs()">Replace Observable</button> ` }) export class TestComponent { obs$ = of(1); replaceObs(): void { this.obs$ = of(2).pipe(delay(1000)); } } ```
1 parent bdd4471 commit ec59c4b

File tree

3 files changed

+59
-17
lines changed

3 files changed

+59
-17
lines changed

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

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ class LetDirectiveTestCompleteComponent {
6666

6767
@Component({
6868
template: `
69-
<ng-container *ngrxLet="value$ as value; suspense as s">{{
70-
s ? 'suspense' : value
71-
}}</ng-container>
69+
<ng-container *ngrxLet="value$ as value">{{ value }}</ng-container>
7270
`,
7371
})
7472
class LetDirectiveTestSuspenseComponent {
@@ -338,13 +336,13 @@ describe('LetDirective', () => {
338336
expect(componentNativeElement.textContent).toBe('42');
339337
}));
340338

341-
it('should render undefined as value when a new observable NEVER was passed (as no value ever was emitted from new observable)', () => {
339+
it('should clear the view when a new observable NEVER was passed (as no value ever was emitted from new observable)', () => {
342340
letDirectiveTestComponent.value$ = of(42);
343341
fixtureLetDirectiveTestComponent.detectChanges();
344342
expect(componentNativeElement.textContent).toBe('42');
345343
letDirectiveTestComponent.value$ = NEVER;
346344
fixtureLetDirectiveTestComponent.detectChanges();
347-
expect(componentNativeElement.textContent).toBe('undefined');
345+
expect(componentNativeElement.textContent).toBe('');
348346
});
349347

350348
it('should render new value when a new observable was passed', () => {
@@ -453,12 +451,12 @@ describe('LetDirective', () => {
453451
expect(componentNativeElement.textContent).toBe('true');
454452
}));
455453

456-
it('should render suspense when next observable is in suspense state', fakeAsync(() => {
454+
it('should clear the view when next observable is in suspense state', fakeAsync(() => {
457455
letDirectiveTestComponent.value$ = of(true);
458456
fixtureLetDirectiveTestComponent.detectChanges();
459457
letDirectiveTestComponent.value$ = of(false).pipe(delay(1000));
460458
fixtureLetDirectiveTestComponent.detectChanges();
461-
expect(componentNativeElement.textContent).toBe('suspense');
459+
expect(componentNativeElement.textContent).toBe('');
462460
tick(1000);
463461
fixtureLetDirectiveTestComponent.detectChanges();
464462
expect(componentNativeElement.textContent).toBe('false');

modules/component/src/let/let.directive.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ export interface LetViewContext<PO> {
3131
* `*ngrxLet="obs$; let c = complete"` or `*ngrxLet="obs$; complete as c"`
3232
*/
3333
complete: boolean;
34-
/**
35-
* `*ngrxLet="obs$; let s = suspense"` or `*ngrxLet="obs$; suspense as s"`
36-
*/
37-
suspense: boolean;
3834
}
3935

4036
/**
@@ -119,22 +115,19 @@ export class LetDirective<PO> implements OnInit, OnDestroy {
119115
ngrxLet: undefined,
120116
error: undefined,
121117
complete: false,
122-
suspense: true,
123118
};
124119
private readonly renderEventManager = createRenderEventManager<PO>({
125120
suspense: () => {
126121
this.viewContext.$implicit = undefined;
127122
this.viewContext.ngrxLet = undefined;
128123
this.viewContext.error = undefined;
129124
this.viewContext.complete = false;
130-
this.viewContext.suspense = true;
131125

132126
this.renderSuspenseView();
133127
},
134128
next: (event) => {
135129
this.viewContext.$implicit = event.value;
136130
this.viewContext.ngrxLet = event.value;
137-
this.viewContext.suspense = false;
138131

139132
if (event.reset) {
140133
this.viewContext.error = undefined;
@@ -145,7 +138,6 @@ export class LetDirective<PO> implements OnInit, OnDestroy {
145138
},
146139
error: (event) => {
147140
this.viewContext.error = event.error;
148-
this.viewContext.suspense = false;
149141

150142
if (event.reset) {
151143
this.viewContext.$implicit = undefined;
@@ -158,7 +150,6 @@ export class LetDirective<PO> implements OnInit, OnDestroy {
158150
},
159151
complete: (event) => {
160152
this.viewContext.complete = true;
161-
this.viewContext.suspense = false;
162153

163154
if (event.reset) {
164155
this.viewContext.$implicit = undefined;
@@ -224,7 +215,7 @@ export class LetDirective<PO> implements OnInit, OnDestroy {
224215
}
225216

226217
private renderSuspenseView(): void {
227-
if (this.suspenseTemplateRef && this.isMainViewCreated) {
218+
if (this.isMainViewCreated) {
228219
this.isMainViewCreated = false;
229220
this.viewContainerRef.clear();
230221
}

projects/ngrx.io/content/guide/migration/v15.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,56 @@ AFTER:
168168
...
169169
</ng-container>
170170
```
171+
172+
#### LetDirective Behavior on Suspense Event
173+
174+
The `LetDirective` view will be cleared when the replaced observable is in a suspense state.
175+
Also, the `suspense` property is removed from the `LetViewContext` because it would always be `false` when the `LetDirective` view is rendered.
176+
Instead of `suspense` property, use [suspense template](guide/component/let#using-suspense-template) to handle the suspense state.
177+
178+
BEFORE:
179+
180+
The `LetDirective` view will not be cleared when the replaced observable is in a suspense state and the suspense template is not passed:
181+
182+
```ts
183+
@Component({
184+
template: `
185+
<!-- When button is clicked, the 'LetDirective' view won't be cleared. -->
186+
<!-- Instead, the value of 'o' will be 'undefined' until the replaced -->
187+
<!-- observable emits the first value (after 1 second). -->
188+
<p *ngrxLet="obs$ as o">{{ o }}</p>
189+
<button (click)="replaceObs()">Replace Observable</button>
190+
`
191+
})
192+
export class TestComponent {
193+
obs$ = of(1);
194+
195+
replaceObs(): void {
196+
this.obs$ = of(2).pipe(delay(1000));
197+
}
198+
}
199+
```
200+
201+
AFTER:
202+
203+
The `LetDirective` view will be cleared when the replaced observable is in a suspense state and the suspense template is not passed:
204+
205+
```ts
206+
@Component({
207+
template: `
208+
<!-- When button is clicked, the 'LetDirective' view will be cleared. -->
209+
<!-- The view will be created again when the replaced observable -->
210+
<!-- emits the first value (after 1 second). -->
211+
<p *ngrxLet="obs$ as o">{{ o }}</p>
212+
<button (click)="replaceObs()">Replace Observable</button>
213+
`
214+
})
215+
export class TestComponent {
216+
obs$ = of(1);
217+
218+
replaceObs(): void {
219+
this.obs$ = of(2).pipe(delay(1000));
220+
}
221+
}
222+
```
223+

0 commit comments

Comments
 (0)