Skip to content
This repository has been archived by the owner on Nov 12, 2024. It is now read-only.

Commit

Permalink
enable importedComponentReady() hook to support Observables, Signals …
Browse files Browse the repository at this point in the history
…in addition to Promises (#20)
  • Loading branch information
binarybro authored Sep 6, 2023
1 parent f889477 commit 2a07033
Show file tree
Hide file tree
Showing 20 changed files with 158 additions and 56 deletions.
9 changes: 5 additions & 4 deletions apps/imports-orchestrator-example/src/app/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ const APP_IMPORTS_ORCHESTRATION = {
home0: 1,
home1: 2,
observableInput: 3,
afterViewInit0: 2,
afterViewInit1: 6,
afterViewInit2: 7,
afterViewInit3: 5,
deferredPromise: 2,
deferredObservable: 6,
deferredSignal: 6,
alias0: 7,
alias1: 5,
home2: 3,
home3: 4,

Expand Down
41 changes: 26 additions & 15 deletions apps/imports-orchestrator-example/src/app/pages/home.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
importStandalone,
} from '@lotto24-angular/imports-orchestrator';
import { BehaviorSubject } from 'rxjs';
import {AppImportsOrchestration} from "../app.config";
import { AppImportsOrchestration } from '../app.config';

@Component({
selector: 'example-home',
Expand All @@ -22,12 +22,17 @@ import {AppImportsOrchestration} from "../app.config";
[inputs]="{testInput$}"
]
></ng-container>
<ng-container import="afterViewInit0"></ng-container>
<ng-container import="afterViewInit1"></ng-container>
<ng-container import="afterViewInit2"></ng-container>
<ng-container import="afterViewInit3"></ng-container>
<ng-container import="deferredPromise"></ng-container>
<ng-container import="deferredObservable"></ng-container>
<ng-container import="deferredSignal"></ng-container>
<ng-container import="home2"></ng-container>
<ng-container import="home3"></ng-container>
<div>
<h3>aliased</h3>
<ng-container import="alias0"></ng-container>
<ng-container import="alias1"></ng-container>
</div>
`,
imports: [ImportsOrchestratorDirective, ImportsOrchestratorComponent],
})
Expand All @@ -52,23 +57,29 @@ import {AppImportsOrchestration} from "../app.config";
home3: importNgModule(
() => import('@lotto24-angular/imports-orchestrator-examples/home3')
),

afterViewInit0: importStandalone(
() =>
import(
'@lotto24-angular/imports-orchestrator-examples-static/after-view-init-home'
)
deferredPromise: importStandalone(() =>
import(
'@lotto24-angular/imports-orchestrator-examples-static/deferred'
).then((esm) => esm.DeferredPromiseComponent)
),
deferredObservable: importStandalone(() =>
import(
'@lotto24-angular/imports-orchestrator-examples-static/deferred'
).then((esm) => esm.DeferredObservableComponent)
),
deferredSignal: importStandalone(() =>
import(
'@lotto24-angular/imports-orchestrator-examples-static/deferred'
).then((esm) => esm.DeferredSignalComponent)
),

observableInput: importStandalone(
() =>
import(
'@lotto24-angular/imports-orchestrator-examples-static/observable-input-home'
)
),
afterViewInit1: 'afterViewInit0',
afterViewInit2: 'afterViewInit0',
afterViewInit3: 'afterViewInit0',
alias0: 'home0',
alias1: 'home1',
/**
* Type-safety ensures you stay on top of your priorities:
*
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "imports-orchestrator-examples--static-after-view-init",
"name": "imports-orchestrator-examples-static-deferred",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/imports-orchestrator-examples/-static-after-view-init/src",
"sourceRoot": "libs/imports-orchestrator-examples-static/deferred/src",
"prefix": "imports-orchestrator-examples",
"tags": [],
"projectType": "library",
Expand All @@ -11,8 +11,8 @@
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": [
"libs/imports-orchestrator-examples/-static-after-view-init/**/*.ts",
"libs/imports-orchestrator-examples/home1/**/*.html"
"libs/imports-orchestrator-examples-static/deferred/**/*.ts",
"libs/imports-orchestrator-examples-static/deferred/**/*.html"
]
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './lib/deferred-promise.component';
export * from './lib/deferred-observable.component';
export * from './lib/deferred-signal.component';
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BehaviorSubject, delay, Observable } from 'rxjs';
import { ImportedComponentReady } from '@lotto24-angular/imports-orchestrator';

@Component({
selector: 'imports-orchestrator-examples-static-deferred-component',
standalone: true,
imports: [CommonModule],
template: `<div>Deferred: Observable</div>`,
styles: [],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DeferredObservableComponent
implements OnInit, ImportedComponentReady
{
private readonly readySubject = new BehaviorSubject(false);

public ngOnInit(): void {
this.readySubject.next(true);
}

public importedComponentReady(): Observable<boolean> {
return this.readySubject.pipe(delay(3000));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ImportedComponentReady } from '@lotto24-angular/imports-orchestrator';

@Component({
selector: 'imports-orchestrator-examples-static-deferred-component',
standalone: true,
imports: [CommonModule],
template: `<div>Deferred: Promise</div>`,
styles: [],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DeferredPromiseComponent implements ImportedComponentReady {
public importedComponentReady(): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, 3000);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
ChangeDetectionStrategy,
Component,
OnInit,
signal,
Signal,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { ImportedComponentReady } from '@lotto24-angular/imports-orchestrator';

@Component({
selector: 'imports-orchestrator-examples-static-deferred-component',
standalone: true,
imports: [CommonModule],
template: `<div>Deferred: Signal</div>`,
styles: [],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DeferredSignalComponent implements OnInit, ImportedComponentReady {
private readonly ready = signal(false);

public ngOnInit(): void {
setTimeout(() => {
this.ready.set(true);
}, 3000);
}

public importedComponentReady(): Signal<boolean> {
return this.ready;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Signal } from '@angular/core';
import {Observable} from "rxjs";

/**
* When implementing this interface, the queue will be interrupted until the promise returned by importedComponentReady resolves.
*/
export interface ImportedComponentReady {
importedComponentReady(): Promise<void>;
importedComponentReady(): Promise<void> | Observable<boolean> | Signal<boolean>;
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import { ImportedComponentReady } from '../imported-component-ready.interface';
import {
catchError,
filter,
from,
map,
Observable,
of,
race,
take,
timeout,
TimeoutError,
} from 'rxjs';
import { ChangeDetectorRef, ComponentRef } from '@angular/core';
import { ChangeDetectorRef, ComponentRef, Signal } from '@angular/core';

import { ImportsOrchestratorQueueItem } from '../../service';
import { assertPromise, assertSignal } from '@lotto24-angular/util';
import { toObservable } from '@angular/core/rxjs-interop';

export function deferUntilComponentReady$<T>(
componentRef: ComponentRef<any>,
Expand All @@ -26,8 +31,7 @@ export function deferUntilComponentReady$<T>(
);
componentRef.injector.get(ChangeDetectorRef).markForCheck(); // ensure Lifecycle hooks are called

const ready$ = from(instance.importedComponentReady.call(instance));
return race(ready$, item.destroy$).pipe(
return race(resolveReady(instance), item.destroy$).pipe(
timeout(item.timeout),
catchError((err) => {
if (err instanceof TimeoutError) {
Expand All @@ -49,3 +53,20 @@ export function assertImportedComponentReadyEmitter(
): type is ImportedComponentReady {
return (type as ImportedComponentReady).importedComponentReady !== undefined;
}

function resolveReady(instance: ImportedComponentReady): Observable<void> {
const callback = instance.importedComponentReady.call(instance);
if (assertPromise(callback)) {
return from(callback);
}

return (
assertSignal(callback)
? toObservable(callback as unknown as Signal<boolean>)
: (callback as unknown as Observable<boolean>)
).pipe(
filter((value) => value),
map(() => undefined),
take(1)
);
}
7 changes: 7 additions & 0 deletions libs/util/src/lib/assert/assert-promise.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function assertPromise(type: any): type is Promise<any> {
return (
type.then !== undefined &&
type.catch !== undefined &&
type.finally !== undefined
);
}
5 changes: 5 additions & 0 deletions libs/util/src/lib/assert/assert-signal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { isSignal } from '@angular/core';

export function assertSignal(type: any) {
return isSignal(type);
}
2 changes: 2 additions & 0 deletions libs/util/src/lib/assert/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from './assert-observable'
export * from './assert-promise'
export * from './assert-signal'
export * from './assert-standalone'
4 changes: 2 additions & 2 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
"@lotto24-angular/imports-orchestrator": [
"libs/imports-orchestrator/src/index.ts"
],
"@lotto24-angular/imports-orchestrator-examples-static/after-view-init-home": [
"libs/imports-orchestrator-examples-static/after-view-init/src/index.ts"
"@lotto24-angular/imports-orchestrator-examples-static/deferred": [
"libs/imports-orchestrator-examples-static/deferred/src/index.ts"
],
"@lotto24-angular/imports-orchestrator-examples-static/io": [
"libs/imports-orchestrator-examples-static/io/src/index.ts"
Expand Down

0 comments on commit 2a07033

Please sign in to comment.