1

When I try setting a signal value from within an Observable that gets piped to async, I get the error:

Error: NG0600: Writing to signals is not allowed in a computed or an effect by default. Use allowSignalWrites in the CreateEffectOptions to enable this inside effects.

But I'm not inside a computed or an effect, I'm inside an Observable. I also only get this through the async pipe; if I subscribe to the Observable and set my data in the next handler, it works as expected. Is this by design, or is it a bug?

refreshTrigger = new BehaviorSubject<void>(undefined);
refreshing = signal(false);
data = this.refreshTrigger.pipe(
  tap(() => {
    console.log("Refreshing");
    this.refreshing.set(true);
  }),
  map(() => "Doing real work here"),
  shareReplay(1)
);
{{refreshing() ? "Refreshing" : "Not refreshing"}} {{data | async}}
Trevortni
  • 688
  • 8
  • 23
  • I didn't see any signal code in the linked stackblitz? – DeborahK May 25 '23 at 23:49
  • It seems unnecessary to have a `BehaviorSubject` and a `signal` and react to one to set the other. You should be able to react directly to the signal value. So whatever code is setting `refreshTrigger.next(x)` could just do `refreshing.set(x)`. – DeborahK May 25 '23 at 23:52
  • @DeborahK: I would think that the names of the objects would make it perfectly clear that the signal is a side effect of the real action. But I'll take a look at the stackblitz, I definitely had code in it. – Trevortni May 26 '23 at 16:53
  • Okay, I have no idea what happened to the stackblitz. I guess I'll just go ahead and remove it since I seem to have received an answer without it. – Trevortni May 26 '23 at 16:58
  • Oops, I thought I had the return from a different rxjs function than the tap, let me fix that. – Trevortni May 26 '23 at 17:00

1 Answers1

2

Update

 The bug has been fixed in the Angular 16.1.0-next.3.

It works fine when you make the observable asynchronous, as mentioned by @matthieu-riegler on GitHub.

You can workaround this issue by adding rxjs delay operator

data = this.refreshTrigger.pipe(
    delay(1),
    tap(() => {
      console.log('Refreshing');
      this.refreshing.set(true);
      return 'hello';
    }),
    shareReplay(1)
);
Chellappan வ
  • 23,645
  • 3
  • 29
  • 60
  • Sounds promising, I'll try it after the weekend. – Trevortni May 20 '23 at 20:54
  • I got pulled to another project before I could try this, and it looks like it will be a while before I can return, but I just wanted to update that the GitHub issue you created has been marked as Completed, so it should theoretically be fixed once the next release is ready, which isn't something I've had a need to wait for with Angular before, so I don't know what kind of timeframe that might be. – Trevortni Jun 01 '23 at 16:11
  • Also, run-on sentences FTW. – Trevortni Jun 01 '23 at 16:12