angulartypescriptngrxngrx-store

Angular NgRx Store TypeError: Cannot assign to read only property 'primary' of object '[object Object]'


I have an array of objects in the NgRx store like so:

[ {email: 'firstemail@domain.com', primary: true, type: 'WORK'}, 
  {email: 'secondemail@domain.com', primary: true, type: 'WORK'}, 
  {email: 'thirdemail@domain.com', primary: true, type: 'WORK'} ]

On retrieval of the data from the store, I assign the above array into a property inside my component.

I use the above data to loop through HTML elements to populate them with existing information with *ngFor

When I try to change the data (such as clicking a button to turn that specific 'primary' key's value into the opposite (i.e true becomes false and false becomes true)) then the data cannot change due to the below error:

TypeError: Cannot assign to read only property 'primary' of object '[object Object]'

Below is the code:

// Get data from store and assign to local property
this.myData = this.store$.existingData;

<div class="form-element" *ngFor="let email of myData; let index = index">
    <input type="text" placeholder="Email Address" [(ngModel)]="email['email']" />
</div>

I've tried reassigning this.myData to another property, and looping through that instead as well as using Object.assign to get the data from the store and put it into the this.myData property but the same error keeps occurring.

I am fully aware that the data inside the store is immutable unless managed within the reducer (and there's no problems happening with this).

I've tried reviewing other answers of a similar nature but no-one seems to be having the exact same problem.

How do I get the data from the store, assign it to a property locally, and change that data without the above error from happening?

Update 1:

Additional Data

this.StoreSubscription = this.store.subscribe(state => {
      this.store$ = state.consumer;
    });

Solution

  • Your issue is the ngModel. Without knowing anything else about your code, you should do something like this, otherwise the ngModel directive tries to write to the value in the immutable email data object:

    <input [ngModel]="email['email']" (ngModelChange)="onEmailChange(email, $event)">
    
    
    onEmailChange(email: EmailData, newEmail: string): void {
      // call action to store to update email object with `newEmail` in store
    }
    

    To make your object not immutable anymore (shallowly), you can do the following:

    this.myData = this.store$.existingData.map((email) => ({ ...email }));