I am using @ ngrx / store for an Angular 2 application.
My store contains a list of Book objects. I want to update a field in one of these objects. I also have an observable copy of the book that I am looking for for an update (e.g. selectedBook ).
To perform an update, I intend to invoke the reducer using UpdateBookAction and the payload of a new book. So I make a deep copy of an existing Book object, subscribing to selectedBook , and then calling Object.assign ().
But when I try to write copies to one of the fields, I get the following error. (This happens with the same error that I get if I try to write directly to the book object in the store.)
Error
Cannot assign to read only property 'name' of object '#<Object>' at ViewWrappedError.BaseError [as constructor]
code
ngOnInit() { this.book$ = this.store.let(fromRoot.getSelectedBook); //... } someFunction() { //... this.book$.subscribe(book => { let updatedBook = Object.assign({}, book); updatedBook.name = 'something else'; // <--- THIS IS WHAT THROWS let action = new BookUpdateAction(updatedBook); this.store.dispatch(action); } }
Clarification after comments
I was on the assumption that I could have an action with a payload, which was not the whole state of the store. (In fact, this seems necessary, no?) I'm sure this is, given the documentation.
The action I'm looking for looks something like this:
Action = UPDATE, payload = {'id': 1234, 'name': 'something new'}
As already mentioned, I intend to make this call as follows:
this.store.dispatch(action);
Presumably under the hood, ngrx passes my action to the reducer along with the (immutable) current state.
So, from there everything should work fine. My logic inside the gearbox does not mutate the existing state, it just creates a new one from the existing state and the payload that I went through.
The real question here is how can I intelligently build a new "objectToUpdate" so that I can pass this as a payload.
I could do something like this:
this.book$.subscribe(book => { let updatedBook = new Book(); updatedBook.id = book.id;
But we are not just talking about two fields here ... what if my book has several fields? Do I have to manually create a new book from scratch each time only to update one field?
My solution was to make a deep copy using Object.assign({}, book) (and not mutate the old one!), And then do the update only in the field I was looking for.