Ersch
Ersch

Reputation: 315

Angular signal effect, try to reset a form and get "Writing to signals is not allowed in a computed or an effect"

I have a problem with angular 17 signal effect. I try to reset a form in the effect when the facilities signal is updated.

I have this message error in the browser console:

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.

If I remove from the effect the this_form. Reset, no error in the console. If I add the effect option to allowSignalWrites it works, but I don't understand why as I don't write a signal, I just reset a form.

formResetEffect = effect(() => {
if (this.facilities()) {
    this._form.reset({
        disabled: false,
        value: null
    });
}}, {allowSignalWrites: true});

Could you help me to understand this behavior?

Thanks

UPDATE:

It appears that the issue appear only when I use the p-dropdown component from PrimeNG. I've examined the code of the p-dropdown in the GitHub repository, and this component now uses signals.

primeng dropdown github

Do you think the signal writing into the p-dropdown component could be the cause of the problem?

Here a stackblitz to reproduce the problem: stackblitz

Upvotes: 3

Views: 5883

Answers (1)

jaheraho
jaheraho

Reputation: 550

Do you think the signal writing into the p-dropdown component could be the cause of the problem?

Yes. At least from my understanding. effect() works as intended.

Why?

effect() (as well as computed()) magically check deep down all function-calls if there is a any interaction with signals. Even if it's "hidden" in some functions.

I assume that FormGroup.reset() calls Dropdown() which triggers the set() of signals (see line 861-865 of primeng dropdown github).

Imagine it likes this:

- effect()           // ✅ no signals
-- FormGroup.reset() // ✅ no signals
--- Dropdown()       // ❌ calls "set()" of signals

Here as a example which makes it clear:

mySignal = signal("");
effReturn = effect(()=>{
   this.method1();
}); // ❌ throws NG0600 without {allowSignalWrites: true}

method1(): void {
   this.method2();
}

method2(): void {
   mySignal.set("hello world");
}

So, again: effect() works as intended and allowSignalWrites flag has to be set here.

Some could ask now: why isn't allowSignalWrites flag set to true by default in the first place?

What I think: angular-devs want to (a) manual signal-sets as small as possible (rather use computed() to calculate signals) because (b) signals-sets will decrease readability your code.

In other words: calling set() within effect() should be the exception!

Anyways, in your example I think it's totally fine using effect() with allowSignalsWrites.

By the way: The if-condition of the dropdown-basic-demo.ts:25 in your stackblitz-example is obsolete. cities() is always set per definition.

Upvotes: 3

Related Questions