Angular 8: Почему мой ненаблюдаемый тип обновляется всякий раз, когда обновляются данные, из которых он был скопирован? - PullRequest
0 голосов
/ 14 июня 2019

Используя 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);

      });

1 Ответ

1 голос
/ 14 июня 2019

Это не замыкание, я полагаю, вы просто делите один и тот же объект в 2 местах и ​​модифицируете его в одном месте, поэтому в другом месте он также будет обновлен.

Чтобы исправить это, попробуйте скопироватькогда вы сохраняете его в this.originalValue, вы можете сделать это, переключив эту строку:

this.originalValue = viewModel;

в следующее:

this.originalValue = {...viewModel};

Надеюсь, это поможет.

...