Mam stan, który zawiera kolekcję przedmiotów:
import { State, Action, StateContext } from "@ngxs/store";
import {AddItem} from "./app.actions";
export interface Item {
id: number;
name: string;
}
export interface AppStateModel {
items: Item[];
}
@State<AppStateModel>({
name: "app",
defaults: {
items: []
}
})
export class AppState {
@Action(AddItem)
addItem(ctx: StateContext<AppStateModel>, action: AddItem){
const state = ctx.getState();
ctx.patchState({
items: [
...state.items,
{ id: action.id, name: action.name}
]
});
}
}
Mój komponent jest zasubskrybowany do listy elementów w sklepie, gdy dodaję nowy element, który jest odzwierciedlony na wyświetlonej liście (wszystko dobrze).
Obserwowane zachowanie
Następnie wiążę ten wyświetlany element do input
pole - kiedy wpisuję to pole wejściowe, wydaje mi się, że modyfikuję stan tego elementu, tzn. zmienia się również wygląd "Wyświetl nazwę" elementu.
<ng-container *ngIf="app$ | async as app">
Name: <input #name />
<button (click)="addItem(name.value)">Add Item </button>
<br/>
<br/>
Items List:
<div *ngFor="let item of app.items">
View Name: <span>{{item.name}}</span>
</div>
<br/>
Items List 2 with updates:
<div *ngFor="let item of app.items">
Update Name: <input [(ngModel)]="item.name" />
</div>
</ng-container>
Czy to oczekiwane zachowanie? Spodziewałem się, że zmiana nie zostanie odzwierciedlona na liście "tylko widok".
A może to tylko przypadek, w którym robię coś, czego nie powinienem robić? Wiem, że naprawdę powinienem wysłać tę zmianę przez akcję do sklepu w ten sposób:
Update Name: <input [ngModel]="item.name" (ngModelChange)="updateItem(item.name)" />
updateItem(value) {
this.store.dispatch(new UpdateItemAction(value));
}
Testuję to za pomocą
* ngxs: 3.0.1
* @angular/core: 6.0.0
Zobacz pełne repo próbki tutaj https://github.com/garthmason/ngxs
Dzięki!
Odpowiedzi:
1 dla odpowiedzi № 1To nie jest błąd, to jest funkcja ;)
Wybierając kawałek stanu, on faktycznie zwróci obiekt, który jest stanem.
Co oznacza, że jeśli zmienisz właściwość na coś innego, stan zostanie zaktualizowany.
To, co chciałbym zasugerować podczas pracy z formularzem, polega na tym, że tworzysz kopię danych przed rozpoczęciem zmiany za pomocą ngModel.
podczas korzystania z formularzy reaktywnych istnieje funkcja o nazwie PatchValue, która to zrobi. https://angular.io/guide/reactive-forms#patchvalue
Jeśli chodzi o zwykłe formularze, musisz to zrobić ręcznie.
lodash ma funkcję o nazwie cloneDeep, która powinna ci pomóc https://lodash.com/docs#cloneDeep
var objects = [{ "a": 1 }, { "b": 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false