Используя Angular 8 и Ngrx 8 (не имеет значения, но здесь для полноты), у меня есть служба состояний, которая управляет моим состоянием модели представления. В нем у меня есть свойство viewModel $, которое является субъектом поведения. Когда служба изначально получает свои данные, viewModel $ .next () вызывается с новым значением модели представления, и этому свойству модели представления также присваивается другое свойство с именем originalValue. Это отлично работает.
То, что я хочу, и то, что, как я думал, я закодировал, заключается в том, чтобы исходное значение оставалось неизменным, поэтому, если мой пользователь хочет отменить изменения, я просто отбрасываю обновленную модель представления и возвращаю ей исходное значение.
На самом деле происходит то, что всякий раз, когда обновляется моя модель представления, свойство originalValue также (ошибочно) обновляется. Это озадачивает, поскольку свойство originalValue не является наблюдаемым. Я предполагаю, что это как-то связано с замыканиями, но я недостаточно искусен, чтобы разобраться в этом.
Суть вопроса - почему это происходит и как я могу это исправить? Как я могу достичь желаемой функциональности, то есть сохранить старую версию данных, чтобы при необходимости ее можно было восстановить? (Вы можете задаться вопросом, почему я не могу просто восстановить данные из хранилища. Я мог / могу это сделать, и это сработало бы, но я бы хотел понять, что здесь происходит не так, как есть. У меня есть другие части "Проекта" «это необходимо отменить одновременно, и я не хочу нести дополнительные затраты времени / средств на преобразование моделей состояний для просмотра моделей, если я могу избежать этого.)
Вот соответствующий код:
На государственной службе,
свойства:
public viewModel$: BehaviorSubject<ProjectCoreViewModel>;
public viewModelLoaded$: BehaviorSubject<boolean> = new BehaviorSubject(false);
public originalValue: ProjectCoreViewModel;
public isPristine$: BehaviorSubject<boolean> = new BehaviorSubject(true);
private isInitialized = false;
первоначальный выбор данных (через фасад для извлечения из хранилища)
public selectData() {
this.facade.getProjectCore()
.subscribe(core => this.fromStoreStateModel(core));
}
преобразование из модели состояния в модель представления, после чего вызывается метод updateViewModel $:
fromStoreStateModel(projectCore: ProjectCore) {
if (projectCore) {
const viewModel: ProjectCoreViewModel = {
projectId : projectCore.projectId,
studioId : this.facade.studioId,
ravelryProjectId : projectCore.ravelryProjectId,
ravelryLink : projectCore.ravelryLink,
isPrivate : false,
title : projectCore.projectTitle,
startedDate : projectCore.startedDate,
completedDate : projectCore.completedDate,
warpingMethod : projectCore.warpingMethodId,
weavingTechnique : projectCore.weavingTechniqueId,
reedId : projectCore.reedId,
loomId : projectCore.loomId,
itemCategory : projectCore.itemCategoryId,
itemQuantity : projectCore.quantity,
designName : projectCore.designName,
sourcePublicationId : projectCore.sourcePublicationId,
itemWidth : projectCore.itemWidth,
itemLength : projectCore.itemLength,
widthHeightRatio : this.getSizeRatio(projectCore),
coreNotes : projectCore.coreNotes,
sourcePublicationReference: projectCore.sourcePublicationReference,
};
this.updateViewModel$(viewModel);
}
}
метод updateViewModel $:
updateViewModel$(value: ProjectCoreViewModel) {
if (value) {
if (!this.viewModel$) {
if (!this.isInitialized) {
this.setOriginalValue(value);
this.viewModel$ = new BehaviorSubject(value);
this.viewModel$.pipe(
skip(1)).subscribe(model => {
console.log('changed core view model', model);
console.log('original value in state service', this.originalValue); // this has changed too!
this.isPristine$.next(false);
});
this.isInitialized = true;
}
} else {
this.isPristine$.next(false);
this.viewModel$.next(value);
}
this.setLoadedStatus(true);
} else {
this.setLoadedStatus(false);
}
}
Метод setOriginalValue:
private setOriginalValue(viewModel: ProjectCoreViewModel) {
this.originalValue = viewModel;
this.isPristine$.next(true);
}
В моем компоненте эта часть обновляет модель вида:
this.coreForm.valueChanges.pipe(debounceTime(1000))
.subscribe(value => {
model.title = value.name;
model.startedDate = value.startedDate;
model.completedDate = value.completedDate;
model.itemCategory = value.itemType;
model.weavingTechnique = value.weavingTechnique;
model.warpingMethod = value.warpingMethod;
model.reedId = value.reed;
model.loomId = value.loom;
model.itemQuantity = value.quantity;
model.designName = value.designName;
model.sourcePublicationId = value.designSource;
model.sourcePublicationReference = value.designSourceReference;
model.itemWidth = value.itemWidth;
model.itemLength = value.itemLength;
this.projectCoreViewModel$.next(model);
});