Currently utilizing @ngrx/store within my Angular 2 application.
The store contains a collection of Book
objects. I aim to modify a specific field within one of those objects. Additionally, there is an Observable representing the Book instance I wish to update (referred to as selectedBook
).
To execute the update, my plan is to invoke the reducer with an UpdateBookAction
, supplying it with the new Book payload. Therefore, I create a deep copy of the current Book object by subscribing to selectedBook
and employing Object.assign().
However, when attempting to edit a property of the copied object, an error arises. This error mirrors the one encountered if trying to directly modify 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 previously assumed that an action could have a payload not encompassing the entire store state. This notion appears necessary according to the documentation. The action I wish to perform looks like this:
Action = UPDATE, payload = {'id': 1234, 'name': 'something new'}
Hence, I intend to make the call in this manner:
this.store.dispatch(action);
Naturally, behind the scenes, ngrx forwards my action to the reducer alongside the immutable current state. Subsequently, everything should proceed smoothly. Inside the reducer, my logic doesn't mutate the existing state but rather generates a new one based on the current state and passed-in payload.
The main concern here is constructing the "objectToUpdate" effectively to serve as the payload.
One approach I considered involves:
this.book$.subscribe(book => {
let updatedBook = new Book();
updatedBook.id = book.id;
//manually set other fields...
updatedBook.name = 'something else';
let action = new BookUpdateAction(updatedBook);
this.store.dispatch(action);
}
Yet, what if the Book has numerous fields? Must I laboriously build an entirely new Book from scratch each time just for updating a single field?
To address this dilemma, I opted for a deep copy using Object.assign({}, book)
(ensuring no mutation occurs on the original) followed by making updates solely to the targeted field.