Skip to content

Instantly share code, notes, and snippets.

@baflo
Last active July 1, 2020 08:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save baflo/ac708c5f0c4d0c0e47c7eb96661431d6 to your computer and use it in GitHub Desktop.
Save baflo/ac708c5f0c4d0c0e47c7eb96661431d6 to your computer and use it in GitHub Desktop.
Handling placeholders after delay with RxJS
<ng-container *ngIf="listEntities$ | async as listEntities">
<div class="label-context-panel" *ngIf="listEntities.length > 0">
<ul>
<ng-container *ngFor="let entity of listEntities">
<ng-container [ngSwitch]="entity.type">
<li *ngSwitchCase="'content'" [ngClass]="{ property: true, enabled: !entity.disabled }" (click)="selectReturnValue(entity)">{{ entity.propertyType }} <span class="name">{{ entity.propertyName }}</span>
<div [ngClass]="'tooltip'">
<div class="errorHeading" *ngIf="entity.tooltip.errorHeading">{{ entity.tooltip.errorHeading }}</div>
{{ entity.tooltip.message }}
</div>
</li>
<li *ngSwitchCase="'placeholder'">
<div class="placeholder" [ngStyle]="{ 'width.%': entity.width }">&nbsp;</div>
</li>
</ng-container>
</ng-container>
</ul>
</div>
</ng-container>
@Component({})
class Test {
/** List entities representing placeholders that may be shown if `bitReturnValues` were received too slowly. */
protected readonly loadingPlaceholders = Array.from({ length: 3 }).map(() => ({
type: "placeholder" as const,
width: 60 + Math.floor(Math.random() * 40),
}));
/** Target for the fetched data. Contains entities to be displayed in popup list. */
protected readonly bitReturnValues$ = new BehaviorSubject<Array<{ type: "content"; propertyName: string; propertyType: string }>>([]);
/** Show placeholders if not `bitReturnValues` were received within one second. */
protected readonly showPlaceholdersTimer$ = timer(1000);
/** If placeholders were opened, show them for at least one second (timestamp 2000ms). */
protected readonly hidePlaceholdersTimer$ = timer(2000);
/** List entities to render in template. This emits either placeholder entities or `bitReturnValues` */
protected readonly listEntities$: Observable<
Array<{ type: "placeholder"; width: number } | { type: "content"; propertyName: string; propertyType: string }>
> = merge(
// Initialize with empty array.
of([] as []),
// Wait for some time, if no `bitReturnValues` were received meanwhile, emit `loadingPlaceholders`.
this.showPlaceholdersTimer$.pipe(takeUntil(this.bitReturnValues$), mapTo(this.loadingPlaceholders)),
// Try to take `bitReturnValues` until the placeholders are fed into the observable...
this.bitReturnValues$.pipe(takeUntil(this.showPlaceholdersTimer$)),
// ...in that case, wait for the minimum time after which the placeholders may be closed, or as long as
// it takes to receive a value, then emit the `bitReturnValues`.
combineLatest(this.bitReturnValues$, this.hidePlaceholdersTimer$).pipe(map(([bitReturnValues]) => bitReturnValues))
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment