I have an Akita store that gets populated with data from server. I am trying to get an object from the store and edit it using angular two way binding [()].
Any time I try to change the value of the object (in the template HTML by typing in a field or in component Typescript after data load from service) I get an error about the property not being editable.
I have tried adding ImmerJS in the Akita EntityStore and tried using {...data} in the component. Same result.
Some code...
Akita store:
export interface GradingMetaState extends EntityState<Grading, number>, ActiveState {
loading: boolean;
gradings: Grading[];
}
@StoreConfig({ name: 'gradingMetaStore', producerFn: produce})
export class GradingMetaStore extends EntityStore<GradingMetaState> {
constructor() {
super();
}
}
Bit from the service, this is returning data to the component:
public get gradings$(): Observable<Grading[]> {
return this.gradingMetaQueries.selectAll();
}
From the component:
ngOnInit(): void {
this.gradings = new Array<Grading>();
this.busy = true;
this.service.gradings$.subscribe((gradings) => {
// this.gradings = {...gradings}; - error about can only be array/iterable
this.gradings = gradings;
if (this.gradings.length > 0) {
// Data is present, but this code produces error in browser console
// "ERROR TypeError: "firstName" is read-only"
this.log.debug('changing Albert Einstein to william Einstein');
this.gradings[1].examiners[1].firstName = 'william'; // ERR line
this.log.debug('changing Albert Einstein to william Einstein DONE');
}
this.busy = false;
});
}
The component above errors as described, but if I remove the name setting from there I get the same result if I try to edit the value in an input field:
<mat-form-field>
<mat-label>First name</mat-label>
<input matInput [disabled]="busy" (blur)="saveGrading(grading)"
[(ngModel)]="examiner.firstName" placeholder="First name">
</mat-form-field>
The value is populated on the page when template loads.
Now it's very possible I've missed some crucial aspect of Angular and/or Akita, feel free to tell me so!
EDIT - potential solution So Immer in the store doesn't seem to be doing what I hoped returning 'draft' objects, which I took to mean mutable (https://datorama.github.io/akita/docs/immer/).
In my service I have code to fetch data from the store via queries. I tried changing the service (added code below is horrible, acknowledged) to copy datastore objects and return the copy. That seems to allow end to end functionality to work.
However I'm not sure that's the right thing to do...
Old service method:
public get gradings$(): Observable<Grading[]> {
return this.gradingMetaQueries.selectAll();
}
New service method:
public get gradings$(): Observable<Grading[]> {
const observable = new BehaviorSubject([]);
this.gradingMetaQueries.selectAll().subscribe((gradings: Grading[]) => {
// not nice, but seems to do the job.
// Probably better ways available to copy object into mutable.
const thing = JSON.parse(JSON.stringify(gradings));
observable.next(thing);
});
return observable;
}