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

2

7

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

[ {email: '[email protected]', primary: true, type: 'WORK'}, 
  {email: '[email protected]', primary: true, type: 'WORK'}, 
  {email: '[email protected]', 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;
    });
Spanish answered 6/8, 2020 at 18:28 Comment(0)
A
10

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 }));
Aristotle answered 6/8, 2020 at 18:36 Comment(5)
Thanks for your answer Poul. Unfortunately, I've tried adding this just now and the same error continues to apply as the ngModel still exists. The ngModelChange function that I created doesn't even fire as the data refuses to change due to the previously mentioned error. During my research it would seem that the problem is that the assign of the data from the NgRx Store is copying the object, including the immutability of it (such as 'configuration: false, 'writeable: false'). I need to get a copy of the object from the store that IS writable.Spanish
@JamieBohanna can you show how you obtain the data in your component ts?Aristotle
Hey, I've added the extra data but really its just getting the data from the NgRx store.Spanish
You are an absolute god! Thank you so much! I've spent hours trying to find a solution to this! I don't need to use ngModelChange to fix this. Just the shallow clone of the object. Amazing!Spanish
Thank you so much for the answer AND the explanation. Couldn't get anything else working in my case and this ngModelChange saved the day.Turley
B
0

Had a similar problem. Managed to fix it by passing a clone of the object instead of a reference.

    this.store.select('recipes').subscribe(
    recipes=>{
      this.recipes = Object.assign({}, recipes);
    }
  );
this.route.params.subscribe(
    (params: Params)=>{
  this.recipe = Object.assign({}, this.recipes[this.selectedRecipeIndex]);
Bilabial answered 8/4, 2024 at 3:37 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.