Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeError: Cannot assign to read only property '0' of object '[object Array]' in typescript

I am working on angular 8.

  1. I have a page that displays a table. The table displays data from an object array taskList which the component gets as an @Input().
  2. I have a sorting function on the columns of this table.
  3. I also have a delete option on each row. When I click on the delete option it makes api call to delete the row and then another call to fetch the tasklist array. This is the effect that for the same
  @Effect()
  DeleteTask$: Observable<Action> = this.actions$.pipe(
    ofType(importActions.DELETE_TASK),
    switchMap(params =>
      this.globalService
        .deleteTask(params)
        .mergeMap(deleteSuccess => {
          return from([
            new importActions.DeleteTaskSuccess(deleteSuccess),
            new importActions.LoadTaskList(),
          ]);
        })
        .catch((error, caught) => {
          return Observable.of(new GlobalError(error));
        }),
    ),
  );

My problem is that the sorting function works fine when I do on first page load. But if I delete a row and then fetch the tasklist post-delete, I get the following error:

ERROR Error: Uncaught (in promise): TypeError: Cannot assign to read only property '0' of object '[object Array]'
TypeError: Cannot assign to read only property '0' of object '[object Array]'

The as per the error message the following function in my code gives the error

  exchange(a, b) {
    const temp = this.taskList[a];
    this.taskList[a] = this.taskList[b]; //this line gives error
    this.taskList[b] = temp;
  }

This function is the part of a sorting code that uses the tasklist array and sorts it.
The flow being ngOnchanges(detects change is taskList array) calls --> this.taskChange('export_name', 'asc') based on some condition calls --> this. exchange(a, b)

Following is my ngOnchanges method

ngOnChanges(changes: SimpleChanges) {
    if (this.taskList !== null && this.taskList !== undefined) {
      this.taskChange('export_name', 'asc');
    }
  }

Following is the main sorting method

  async taskChange(value, taskOrder) {
    this.sortOrder = taskOrder;
    this.selectedValue = value;
    const expr = {
      asc: (a, b) => a > b,
      desc: (a, b) => a < b,
    };
    for (let i = 0; i < this.taskList.length; i++) {
      for (let j = i + 1; j < this.taskList.length; j++) {
        switch (value) {
          case 'export_name':
            if (
              expr[this.sortOrder](this.taskList[i].name, this.taskList[j].name)
            ) {
              this.exchange(i, j);
            }
            break;
          case 'file_type':
            let type1;
            let type2;
            type1 = this.exportType.transform(this.taskList[i].code, []);
            type2 = this.exportType.transform(this.taskList[j].code, []);
            if (expr[this.sortOrder](type1, type2)) {
              this.exchange(i, j);
            }
            break;
        }
      }
    }
  }

I am not sure what exactly is causing this error when the array changes the second time. I have tried a bunch of things but none of them worked. From what I found online this might be happening because I'm trying to mutate an array received as @Input. But the above code, which mutates the 'tasklist` array works on initial page load. And only stops working when the array changes. Could someone help me out?

like image 938
Amruta Avatar asked Nov 22 '20 18:11

Amruta


People also ask

How do you assign a value to a readonly property in typescript?

Readonly is a typescript keyword that makes the property read-only in a class, interface, or type alias. We make a property read-only by prefixing the property as readonly . We can assign a value to the readonly property only when initializing the object or within a constructor of the class.

Can not assign to read only property of object?

The error "Cannot assign to read only property of object" occurs when we try to change a property of an object that has been frozen or when a property has been defined with Object. defineProperties() . To solve the error, create a copy of the object or array, or set the property to writable .


2 Answers

Try creating a copy of the array before trying to sort it. Like using a spread operator.

arrayForSort = [...this.taskList]

Then after sorting you could assign it back to the taskList field

like image 78
Jan Fiołka Avatar answered Sep 27 '22 17:09

Jan Fiołka


For those coming to this issue with this error message using React/Redux, it might be that you're trying to mutate state directly which isn't allowed.

In my case I had this setup for getting state within a thunk (simplified):

import store from "./myStore";

const state = store.getState();
const getItems = state => state.user.items;
const items = getItems(state);
// ↓ this blew up as it was attempting to manipulate `state`
items.sort((a, b) => a.order - b.order);

This was fixed for me by:

import store from "./myStore";

const state = store.getState();
const getItems = state => state.user.items;
// ↓ in my case items is an array, so I create a new array by spreading state here
const items = [...getItems(state)];
// ↓ which means we're not manipulating state, but just our `items` array alone
items.sort((a, b) => a.order - b.order);
like image 39
fredrivett Avatar answered Sep 27 '22 15:09

fredrivett