Skip to content

Commit

Permalink
fix: use ngOnChanges instead of effect to avoid signal-writes error
Browse files Browse the repository at this point in the history
  • Loading branch information
arturovt committed Aug 5, 2024
1 parent 4e1b5a5 commit e8c3d3c
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 18 deletions.
42 changes: 26 additions & 16 deletions projects/ngneat/overview/src/lib/teleport/teleport.directive.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { Directive, EmbeddedViewRef, OnDestroy, TemplateRef, effect, inject, input } from '@angular/core';
import {
Directive,
EmbeddedViewRef,
OnChanges,
OnDestroy,
SimpleChanges,
TemplateRef,
inject,
input,
} from '@angular/core';
import { Subscription } from 'rxjs';

import { TeleportService } from './teleport.service';
Expand All @@ -7,7 +16,7 @@ import { TeleportService } from './teleport.service';
selector: '[teleportTo]',
standalone: true,
})
export class TeleportDirective implements OnDestroy {
export class TeleportDirective implements OnChanges, OnDestroy {
readonly teleportTo = input<string | null | undefined>();

private viewRef: EmbeddedViewRef<any>;
Expand All @@ -16,20 +25,21 @@ export class TeleportDirective implements OnDestroy {
private tpl = inject(TemplateRef);
private service = inject(TeleportService);

constructor() {
effect(() => {
const teleportTo = this.teleportTo();

if (typeof teleportTo === 'string') {
this.dispose();

this.subscription = this.service.outlet$(teleportTo).subscribe((outlet) => {
if (outlet) {
this.viewRef = outlet.createEmbeddedView(this.tpl);
}
});
}
});
ngOnChanges(changes: SimpleChanges): void {
// Note: Do not use `effect` to observe changes to `teleportTo`, as
// this would result in running `createEmbeddedView` within that effect.
// `createEmbeddedView` may create a component whose constructor might
// trigger another effect or write to some signals, given that we are
// operating within a reactive context.
if (changes.teleportTo && typeof this.teleportTo() === 'string') {
this.dispose();

this.subscription = this.service.outlet$(this.teleportTo()).subscribe((outlet) => {
if (outlet) {
this.viewRef = outlet.createEmbeddedView(this.tpl);
}
});
}
}

ngOnDestroy(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import { filter, map } from 'rxjs/operators';
})
export class TeleportService {
private outlets = new BehaviorSubject<string>('');
private asObservable = this.outlets.asObservable();

outlet$(name: string) {
return this.asObservable.pipe(
return this.outlets.pipe(
filter((current) => current === name),
map((name) => this.ports.get(name))
);
Expand Down

0 comments on commit e8c3d3c

Please sign in to comment.