Skip to content

Commit 07b42e0

Browse files
committed
fix(lib): cleanup boundaries on destruction
1 parent 025f785 commit 07b42e0

6 files changed

+85
-31
lines changed

projects/ngx-element-boundary/src/lib/boundary-sharing-strategy/boundary-sharing-strategy.ts

+5
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,9 @@ export abstract class BoundarySharingStrategy {
2525
* Add one {@link ElementBoundary}
2626
*/
2727
abstract addBoundary(boundary: ElementBoundary): void;
28+
29+
/**
30+
* Remove one {@link ElementBoundary}
31+
*/
32+
abstract removeBoundary(boundary: ElementBoundary): void;
2833
}

projects/ngx-element-boundary/src/lib/boundary-sharing-strategy/global-boundary-sharing-strategy.ts

+24-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Injectable } from '@angular/core';
2-
import { Observable, ReplaySubject } from 'rxjs';
2+
import { Observable, ReplaySubject, BehaviorSubject } from 'rxjs';
33
import { scan, shareReplay } from 'rxjs/operators';
44

55
import { ElementBoundary } from '../types';
@@ -37,21 +37,14 @@ export class GlobalBoundarySharingStrategyOptions {
3737
*/
3838
@Injectable({ providedIn: 'root' })
3939
export class GlobalBoundarySharingStrategy implements BoundarySharingStrategy {
40-
private readonly addBoundary$ = this._boundary$;
41-
42-
private readonly boundaries$ = this.addBoundary$.pipe(
43-
scan((acc, boundary) => [...acc, boundary], [] as ElementBoundary[]),
44-
shareReplay({ bufferSize: 1, refCount: false }),
45-
);
46-
47-
private get _boundary$(): ReplaySubject<ElementBoundary> {
40+
private get boundaries$(): BehaviorSubject<ElementBoundary[]> {
4841
return (
4942
this.globalRef.global[this.options.propName] ||
50-
(this._boundary$ = new ReplaySubject(1))
43+
(this.boundaries$ = new BehaviorSubject<ElementBoundary[]>([]))
5144
);
5245
}
5346

54-
private set _boundary$(boundaries: ReplaySubject<ElementBoundary>) {
47+
private set boundaries$(boundaries: BehaviorSubject<ElementBoundary[]>) {
5548
this.globalRef.global[this.options.propName] = boundaries;
5649
}
5750

@@ -61,10 +54,28 @@ export class GlobalBoundarySharingStrategy implements BoundarySharingStrategy {
6154
) {}
6255

6356
getBoundaries(): Observable<ElementBoundary[]> {
64-
return this.boundaries$;
57+
return this.boundaries$.asObservable();
6558
}
6659

6760
addBoundary(boundary: ElementBoundary): void {
68-
this.addBoundary$.next(boundary);
61+
const boundaries = this.boundaries$.getValue();
62+
63+
boundaries.push(boundary);
64+
65+
this.boundaries$.next(boundaries);
66+
}
67+
68+
removeBoundary(boundary: ElementBoundary): void {
69+
const boundaries = this.boundaries$.getValue();
70+
71+
const idx = boundaries.indexOf(boundary);
72+
73+
if (idx === -1) {
74+
return;
75+
}
76+
77+
boundaries.splice(idx, 1);
78+
79+
this.boundaries$.next(boundaries);
6980
}
7081
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Injectable } from '@angular/core';
2-
import { Observable, ReplaySubject } from 'rxjs';
3-
import { scan, shareReplay } from 'rxjs/operators';
2+
import { BehaviorSubject, Observable } from 'rxjs';
43

54
import { ElementBoundary } from '../types';
65
import { BoundarySharingStrategy } from './boundary-sharing-strategy';
@@ -11,18 +10,31 @@ import { BoundarySharingStrategy } from './boundary-sharing-strategy';
1110
@Injectable({ providedIn: 'root' })
1211
export class SingleAppBoundarySharingStrategy
1312
implements BoundarySharingStrategy {
14-
private readonly addBoundary$ = new ReplaySubject<ElementBoundary>(Infinity);
15-
16-
private readonly boundaries$ = this.addBoundary$.pipe(
17-
scan((acc, boundary) => [...acc, boundary], [] as ElementBoundary[]),
18-
shareReplay({ bufferSize: 1, refCount: false }),
19-
);
13+
private readonly boundaries$ = new BehaviorSubject<ElementBoundary[]>([]);
2014

2115
getBoundaries(): Observable<ElementBoundary[]> {
22-
return this.boundaries$;
16+
return this.boundaries$.asObservable();
2317
}
2418

2519
addBoundary(boundary: ElementBoundary): void {
26-
this.addBoundary$.next(boundary);
20+
const boundaries = this.boundaries$.getValue();
21+
22+
boundaries.push(boundary);
23+
24+
this.boundaries$.next(boundaries);
25+
}
26+
27+
removeBoundary(boundary: ElementBoundary): void {
28+
const boundaries = this.boundaries$.getValue();
29+
30+
const idx = boundaries.indexOf(boundary);
31+
32+
if (idx === -1) {
33+
return;
34+
}
35+
36+
boundaries.splice(idx, 1);
37+
38+
this.boundaries$.next(boundaries);
2739
}
2840
}

projects/ngx-element-boundary/src/lib/cross-boundary-ng-element-strategy.ts

+13-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
} from './element-boundary-ng-element-strategy';
1010
import { ElementBoundaryService } from './element-boundary.service';
1111
import { HookableInjector } from './hookable-injector';
12+
import { ElementBoundary } from './types';
1213
import { maybeLateInitStream } from './util';
1314

1415
/**
@@ -82,6 +83,8 @@ export class CrossBoundaryNgElementStrategy implements NgElementStrategy {
8283
this.incomingOptions,
8384
);
8485

86+
private boundaryRef?: ElementBoundary;
87+
8588
private disconnect$ = new Subject<void>();
8689

8790
constructor(
@@ -108,6 +111,11 @@ export class CrossBoundaryNgElementStrategy implements NgElementStrategy {
108111
}
109112

110113
disconnect(): void {
114+
if (this.boundaryRef) {
115+
this.elementBoundaryService.removeBoundary(this.boundaryRef);
116+
this.boundaryRef = undefined;
117+
}
118+
111119
this.disconnect$.next();
112120
this.baseStrategy.disconnect();
113121
}
@@ -129,11 +137,14 @@ export class CrossBoundaryNgElementStrategy implements NgElementStrategy {
129137
return;
130138
}
131139

132-
this.elementBoundaryService.addBoundary({
140+
// Store boundary to remove it later on disconnect
141+
this.boundaryRef = {
133142
injector: componentRef.injector,
134143
element,
135144
isComponent: true,
136-
});
145+
};
146+
147+
this.elementBoundaryService.addBoundary(this.boundaryRef);
137148
}
138149
}
139150

projects/ngx-element-boundary/src/lib/element-boundary.directive.ts

+14-6
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ import {
66
OnChanges,
77
OnInit,
88
SimpleChanges,
9+
OnDestroy,
910
} from '@angular/core';
1011

1112
import { ElementBoundaryService } from './element-boundary.service';
1213
import { HookableInjector } from './hookable-injector';
14+
import { ElementBoundary } from './types';
1315

1416
/**
1517
* Directive allows to specify contextual "element boundary"
@@ -25,24 +27,26 @@ import { HookableInjector } from './hookable-injector';
2527
@Directive({
2628
selector: '[nebElementBoundary]',
2729
})
28-
export class ElementBoundaryDirective implements OnInit, OnChanges {
30+
export class ElementBoundaryDirective implements OnInit, OnChanges, OnDestroy {
2931
/** Override default {@link Injector} */
3032
@Input() nebElementBoundary?: Injector;
3133

3234
private hookableInjector = new HookableInjector(this.injector);
3335

36+
private boundaryRef: ElementBoundary = {
37+
injector: this.hookableInjector,
38+
element: this.elemRef.nativeElement,
39+
isComponent: false,
40+
};
41+
3442
constructor(
3543
private injector: Injector,
3644
private elemRef: ElementRef,
3745
private elementBoundaryService: ElementBoundaryService,
3846
) {}
3947

4048
ngOnInit(): void {
41-
this.elementBoundaryService.addBoundary({
42-
injector: this.hookableInjector,
43-
element: this.elemRef.nativeElement,
44-
isComponent: false,
45-
});
49+
this.elementBoundaryService.addBoundary(this.boundaryRef);
4650
}
4751

4852
ngOnChanges(changes: SimpleChanges): void {
@@ -54,4 +58,8 @@ export class ElementBoundaryDirective implements OnInit, OnChanges {
5458
}
5559
}
5660
}
61+
62+
ngOnDestroy(): void {
63+
this.elementBoundaryService.removeBoundary(this.boundaryRef);
64+
}
5765
}

projects/ngx-element-boundary/src/lib/element-boundary.service.ts

+7
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ export class ElementBoundaryService {
3939
this.boundarySharingStrategy.addBoundary(boundary);
4040
}
4141

42+
/**
43+
* Unregister "element boundary"
44+
*/
45+
removeBoundary(boundary: ElementBoundary): void {
46+
this.boundarySharingStrategy.removeBoundary(boundary);
47+
}
48+
4249
/**
4350
* Wait until appropriate "element boundary" exists for HTML Element
4451
*/

0 commit comments

Comments
 (0)