Skip to content

Commit

Permalink
fix(lib): simulate late initialization of events stream on element st…
Browse files Browse the repository at this point in the history
…rategies
  • Loading branch information
gund committed Jul 9, 2020
1 parent e67bd28 commit ed3d8d5
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { ComponentRef, Injector, Type } from '@angular/core';
import {
NgElementStrategy,
NgElementStrategyEvent,
NgElementStrategyFactory,
} from '@angular/elements';
import { NgElementStrategy, NgElementStrategyFactory } from '@angular/elements';
import {
ElementBoundaryNgElementStrategy,
ElementBoundaryNgElementStrategyFactory,
maybeLateInitStream,
} from 'ngx-element-boundary';
import { Observable } from 'rxjs';

import {
DefaultNgElementStrategyFactory,
Expand Down Expand Up @@ -64,13 +60,10 @@ export class DefaultElementBoundaryNgElementStrategyOptionsDefault
*/
export class DefaultElementBoundaryNgElementStrategy
implements ElementBoundaryNgElementStrategy {
get events() {
return this.defaultStrategy.events;
}

set events(events: Observable<NgElementStrategyEvent>) {
this.defaultStrategy.events = events;
}
// HACK: In Angular Elements before v10 `events` property was not set
// before `this.connect()` was not called resulting in `undefined`
// so we are using late initialization of stream
events = maybeLateInitStream(this.defaultStrategy, 'events');

private options: DefaultElementBoundaryNgElementStrategyOptionsDefault;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ import {
NgElementStrategyEvent,
NgElementStrategyFactory,
} from '@angular/elements';
import { Observable, of, Subject } from 'rxjs';
import { take, takeUntil, timeoutWith } from 'rxjs/operators';
import { Observable, of, Subject, ReplaySubject } from 'rxjs';
import { take, takeUntil, timeoutWith, switchAll } from 'rxjs/operators';

import {
ElementBoundaryNgElementStrategy,
ElementBoundaryNgElementStrategyFactory,
} from './element-boundary-ng-element-strategy';
import { ElementBoundaryService } from './element-boundary.service';
import { HookableInjector } from './hookable-injector';
import { maybeLateInitStream } from './util';

/**
* Options for {@link CrossBoundaryNgElementStrategy}
Expand Down Expand Up @@ -67,13 +68,10 @@ export class CrossBoundaryNgElementStrategyOptionsDefault
* To disable the timeout you may set it to `0` (zero, number)
*/
export class CrossBoundaryNgElementStrategy implements NgElementStrategy {
get events() {
return this.baseStrategy.events;
}

set events(events: Observable<NgElementStrategyEvent>) {
this.baseStrategy.events = events;
}
// HACK: In Angular Elements before v10 `events` property was not set
// before `this.connect()` was not called resulting in `undefined`
// so we are using late initialization of stream
events = maybeLateInitStream(this.baseStrategy, 'events');

private elementBoundaryService: ElementBoundaryService = this.hookableInjector.get(
ElementBoundaryService,
Expand Down
32 changes: 32 additions & 0 deletions projects/ngx-element-boundary/src/lib/util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,36 @@
import { ReplaySubject, Observable, ObservedValueOf } from 'rxjs';
import { switchAll } from 'rxjs/operators';

/** @internal */
export function isDefined<T>(value: T): value is NonNullable<T> {
return value !== null && value !== undefined;
}

/**
* Allows to defer initialization of the stream
* by creating initial stream before hand and intercept the value
* once it's available in setter and switch to it from initial stream
*
* @internal
*/
export function maybeLateInitStream<
T,
P extends keyof T,
R = ObservedValueOf<T[P]>
>(object: T, prop: P): Observable<R> {
if (object[prop]) {
return object[prop] as any;
}

const setValue$ = new ReplaySubject<Observable<R>>(1);
const value$ = setValue$.pipe(switchAll());

Object.defineProperty(object, prop, {
configurable: true,
enumerable: true,
get: () => value$,
set: (value) => setValue$.next(value),
});

return value$;
}
3 changes: 3 additions & 0 deletions projects/ngx-element-boundary/src/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ export * from './lib/component-selector-strategy/regex-component-selector-strate
export * from './lib/boundary-sharing-strategy/boundary-sharing-strategy';
export * from './lib/boundary-sharing-strategy/single-app-boundary-sharing-strategy';
export * from './lib/boundary-sharing-strategy/global-boundary-sharing-strategy';

// Internal shared utils
export * from './lib/util';

0 comments on commit ed3d8d5

Please sign in to comment.