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

Created on 20 Dec 2017  路  7Comments  路  Source: ngrx/platform

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[ x] Bug report 
[ ] Feature request
[ ] Documentation issue or request

What is the current behavior?

I upgraded my Angular packages and this started happening.

When I look at the object in the chrome console I see this:
Value below was evaluated

Trying to do something with the object fails with this:
TypeError: Cannot assign to read only property 'expanded' of object '[object Object]'

Expected behavior:

No error when I try to change the property on the click event after the ngFor with async pipe loads.

Minimal reproduction of the problem with instructions:

I am calling the store:
this.threads$ = this.store.select(fromEvents.selectAllEvents);
I am binding to the template:

 <div *ngIf="(threads$ | async)?.length>0">
                <div class="thread-list">
                        <div *ngFor="let thread of threads$ | async">
                                <app-thread [thread]="thread"></app-thread>
                        </div>
                </div>
        </div>

My app-thread.component.ts is here and notice the click event, because that is where it fails.
@Input() thread: Thread;

My app-thread.component.hmtl is here and notice the click event, because that is where it fails.

....

I try to change a propery on the thread model after it has rendered and this is where it fails:

    public showQuestionFullDetail(item: Thread) {
        item.expanded = ! item.expanded;
    }

My Thread model:

export interface IThread {
    id: string;
    dateTime: Date;
    question: string;
    channel: string;
    category: string;
    expanded: boolean;
    newContent: boolean;
}

export class Thread implements IThread {
    constructor(public id: string, public dateTime: Date,
                public question: string, public channel: string,
                public category: string,
                public expanded: boolean,
                public newContent: boolean) {
        this.id = id;
        this.question = question;
        this.channel = channel;
        this.dateTime = dateTime;
        this.category = category;
        this.expanded = expanded;
        this.newContent = newContent;
    }
}

Version of affected browser(s),operating system(s), npm, node and ngrx:

Angular: 5.1.1
... animations, common, compiler, compiler-cli, core, forms
... http, platform-browser, platform-browser-dynamic, router
... service-worker

@angular/cli: 1.6.0-rc.2
@angular/language-service: 5.0.2
@angular-devkit/build-optimizer: 0.0.36
@angular-devkit/core: 0.0.22
@angular-devkit/schematics: 0.0.42
@ngtools/json-schema: 1.1.0
@ngtools/webpack: 1.9.0-rc.2
@schematics/angular: 0.1.11
@schematics/schematics: 0.0.11
typescript: 2.4.2
webpack: 3.10.0

Other information:

Object is showing Value below was evaluated in chrome console
image

 "dependencies": {
    "@angular/animations": "^5.0.0",
    "@angular/common": "^5.0.0",
    "@angular/compiler": "^5.0.0",
    "@angular/core": "^5.0.0",
    "@angular/forms": "^5.0.0",
    "@angular/http": "^5.0.0",
    "@angular/platform-browser": "^5.0.0",
    "@angular/platform-browser-dynamic": "^5.0.0",
    "@angular/router": "^5.0.0",
    "@angular/service-worker": "^5.0.0",
    "@ngrx/entity": "^4.1.1",
    "@ngrx/store": "^4.1.1",
    "@ngrx/store-devtools": "^4.1.1",
    "core-js": "^2.4.1",
    "moment": "^2.19.3",
    "rxjs": "^5.5.2",
    "zone.js": "^0.8.14"
  },
  "devDependencies": {
    "@angular/cli": "1.6.0-rc.2",
    "@angular/compiler-cli": "^5.0.0",
    "@angular/language-service": "^5.0.0",
    "@types/jasmine": "~2.5.53",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "~6.0.60",
    "codelyzer": "~3.2.0",
    "jasmine-core": "~2.6.2",
    "jasmine-spec-reporter": "~4.1.0",
    "karma": "~1.7.0",
    "karma-chrome-launcher": "~2.1.1",
    "karma-cli": "~1.0.1",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "ngrx-store-freeze": "^0.2.0",
    "protractor": "~5.1.2",
    "ts-node": "~3.2.0",
    "tslint": "~5.7.0",
    "typescript": "~2.4.2"
  }

Most helpful comment

Check your module settings, do you have something like this?

StoreModule.forRoot(reducers, {
        metaReducers,
        runtimeChecks: {
            strictStateImmutability: true,
            strictActionImmutability: false,
            strictStateSerializability: true,
            strictActionSerializability: true
        }
    })

I disabled the strictActionImmutability property, another alternative is to run ng serve --prod with the --prod flag, if you only run ng serve you need to set to false the strictActionImmutability property in your runtimeChecks object

All 7 comments

Ok, the issue is with store freeze
export const metaReducers: MetaReducer<State>[] = []; // !environment.production ? [storeFreeze] : [];

When I comment out storeFreeze in the line of code above it works. What is not compatible with store Freeze in my set up?

I am not using @ngrx/router-store so this shouldnt be an issue for me per this thread:
https://github.com/ngrx/platform/issues/183

You shouldn't alter store values instead changes to store values should be handled with actions. Values should be immutable.

shoot, that is a dang good point. Got ahead of myself it seems. I will go back and do that!

Also you should probably have expandedMap as thread.id array instead of individual thread.expanded. This would keep the "db" of thread entities clean of presentational values.

Depending on other needs, like persistence of expanded property when going back and forth in views you could leave that expandedMap in container component instead.

@MattiJarvinen-BA that is a good point. I was wondering about that and makes sense to keep presentational value out of entities db. Good suggestion, I will look into that.

You shouldn't alter store values instead changes to store values should be handled with actions. Values should be immutable.

use {...object}

Check your module settings, do you have something like this?

StoreModule.forRoot(reducers, {
        metaReducers,
        runtimeChecks: {
            strictStateImmutability: true,
            strictActionImmutability: false,
            strictStateSerializability: true,
            strictActionSerializability: true
        }
    })

I disabled the strictActionImmutability property, another alternative is to run ng serve --prod with the --prod flag, if you only run ng serve you need to set to false the strictActionImmutability property in your runtimeChecks object

Was this page helpful?
0 / 5 - 0 ratings

Related issues

shyamal890 picture shyamal890  路  3Comments

hccampos picture hccampos  路  3Comments

doender picture doender  路  3Comments

smorandi picture smorandi  路  3Comments

mappedinn picture mappedinn  路  3Comments