ngrx / platform

Reactive State for Angular
https://ngrx.io
Other
7.96k stars 1.95k forks source link

computed not re-calculating if signal is inside function #4368

Closed dreamstar-enterprises closed 1 month ago

dreamstar-enterprises commented 1 month ago

Which @ngrx/* package(s) are the source of the bug?

signals

Minimal reproduction of the bug/regression with instructions

For some reason,

withComputed((store) => {
    const utilityService = inject(UtilityService)
    return {
      flattenedContractTouched: computed(()=> {
        const contract = store.contractTouched()
        console.log(contract)
        return utilityService.flattenObject(contract)
      }),
    }
  }), 

Does not properly calculate a new flattenedContractTouched() when store.contractTouched() changes. When I call it, it keeps returning the old contract (the one when the store initialised)

This works perfectly fine (I get the updated contract in the store, but not flattened)

withComputed((store) => {
    const utilityService = inject(UtilityService)
    return {
      flattenedContractTouched: computed(()=> {
        const contract = store.contractTouched()
        console.log(contract)
        return contract
      }),
    }
  }), 

The flattenObject function is just this, in the service: UtilityService

 public flattenObject(obj: { [key: string]: any } | undefined, parentKey = '', result: { [key: string]: any } = {}
  ): { [key: string]: any } {
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        const newKey = parentKey ? `${parentKey}.${key}` : key;
        if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) {
          this.flattenObject(obj[key], newKey, result);
        } else if (Array.isArray(obj[key])) {
          obj[key].forEach((item: any, index: number) => {
            this.flattenObject(item, `${newKey}[${index}]`, result);
          });
        } else {
          result[newKey] = obj[key];
        }
      }
    }
    return result;
  }

Running this line in a component works perfectly fine, it returns the updated contract, flattened too

console.log(utilityService.flattenObject(this.contractStore.contractTouched())

which is why I narrowed down to an ngrx withComputed bug:

Expected behavior

Shouldn't computed just work, in ngRX even if using an injected service function

Versions of NgRx, Angular, Node, affected browser(s) and operating system(s)

latest ngrx

Other information

n/a

I would be willing to submit a PR to fix this issue

dreamstar-enterprises commented 1 month ago

I think I fixed it. I had to update my set function to this:

   setContractTouched(contract: AnyContractDTO): void {
        const newContract = { ...contract } --> added
        patchState(store,{ contractTouched: newContract } );
      },

That's the only way I could re-trigger the computed signal in the withComputed block