Невозможно назначить свойство «закрыто» только для чтения объекта «[object Object]»

Уже несколько дней ломаю голову над этим, но не могу найти причину, почему это происходит.

Итак, я получаю следующее сообщение об ошибке:

TypeError: Cannot assign to read only property 'closed' of object '[object Object]'

Невозможно назначить свойство «закрыто» только для чтения объекта «[object Object]»

Итак, как видите, это происходит в Civilliability-step3.component.ts в функции sendProposal:

civilliability-step3.component.ts

@Component({
  selector: 'app-civilliability-step3',
  templateUrl: './civilliability-step3.component.html',
  styleUrls: ['./civilliability-step3.component.scss']
})
export class CivilliabilityStep3Component implements OnInit, OnDestroy {
  @Output() modelChange = new EventEmitter<CivilLiabilityRequestType>();
  @Output() onCloseForm = new EventEmitter();
  @Input() model: CivilLiabilityRequestType;

  public formGroup: FormGroup;

  private closedProposalSub: Subscription;

  constructor(private formBuilder: FormBuilder, private store: Store) {}

  ngOnInit() {
    this.buildForm();

    if (this.model !== undefined && this.model.details.closed) {
      disableFormGroup(this.formGroup);
    }

    this.closedProposalSub = this.store
      .select(ProposalsState.closedProposalResult)
      .subscribe(val => {
        if (val !== undefined) {
          this.modelChange.emit(val);
          this.onCloseForm.emit();
        }
      });
  }

  ngOnDestroy() {
    if (this.closedProposalSub && !this.closedProposalSub.closed) {
      this.closedProposalSub.unsubscribe();
    }
    this.store.dispatch(new ResetClosedProposalResult());
  }  

  sendProposal() {
    this.model.details.closed = true;
    this.store.dispatch(new CloseProposal(this.model));
  }

  closeForm() {
    disableFormGroup(this.formGroup);
  }

  private buildForm() {
    this.formGroup = this.formBuilder.group({});
  }
}

Использование компонента:

civilliability-detail.component.html

<app-civilliability-step3
          (onCloseForm) = "step1.closeForm(); step2.closeForm(); step3.closeForm()"
          [(model)] = "model"
          #step3></app-civilliability-step3>

Я пытался присвоить истинное значение по-другому, потому что я подумал, что, возможно, я не могу добавить его непосредственно в модель, которая является Input. Но и это не помогло.

  sendProposal() {
    const detailsModel = this.model.details;
    detailsModel.closed = true; // <-- same error
    this.model.details = detailsModel;

    const tmpModel = this.model;
    tmpModel.details.closed = true; // <-- same error
    this.model = tmpModel;

    // this.model.details.closed = true;
    this.store.dispatch(new CloseProposal(this.model));
  }

ОБНОВЛЕНИЕ 1: Добавлен тип запроса гражданской ответственности

export interface CivilLiabilityRequestType extends IRequestData {
  details: CivilLiabilityDetailsModel;
  questionnaire: CivilLiabilityQuestionnaireModel;
  comments: CivilLiabilityCommentsModel;
}

export class CivilLiabilityDetailsModel {
  baseReqId: number;

  startDate: string;
  branch: NamedResource;
  fractioning: NamedResource;
  closed: boolean;
}

ОБНОВЛЕНИЕ 2: Показать происхождение этой модели:

civilliability-detail.component.ts

export class CivilliabilityProposalDetailComponent implements OnInit, OnDestroy {
  @Input() model: CivilLiabilityRequestType;
  @Input() tab: Tab;
  @Input() tabs: Tab[] = [];
  @Input() selectedTabIndex;
  @Input() idx: number;

  constructor() {}

  ngOnInit() {}

  ngOnDestroy() {
    this.model = getEmptyCivilLiabilityRequest();
  }
}

detail.component.html

<mat-tab *ngFor = "let tab of tabs; let idx = index">
...
<app-civilliability-proposal-detail
  [model] = "tab.tabData.data"
  [tab] = "tab"
  [tabs] = "tabs"
  [selectedTabIndex] = "selectedTabIndex"
  [idx] = "idx"
>
</app-civilliability-proposal-detail>
...
</mat-tab>

detail.component.ts

@Component({
  selector: 'app-detail',
  templateUrl: './detail.component.html',
  styleUrls: ['./detail.component.scss']
})
export class DetailComponent implements OnInit {
  public tabs: Tab[] = [];
  public selectedTabIndex = 0;
  public quote?: QuoteData;
  public quoteModel: QuoteData;
  public originalModel: any[];
  public readonly = false;
  @Input() public requestType;

  constructor(private activeRoute: ActivatedRoute) {}

  ngOnInit() {
    const snapshot = this.activeRoute.snapshot;

    this.originalModel = snapshot.data['model'];
    if (this.originalModel) {
      this.tabs = this.createTabsFromQuoteModel(this.originalModel);
    }
  }

  private createTabsFromQuoteModel(model: any): Tab[] {
    let tabs: Tab[] = [];

    for (const key of Object.keys(model)) {
      const element = model[key];
      let type: RequestTypes;
      let proposalData: IRequestData = {};

      if (key === 'civilLiability') {
        type = RequestTypes.CivilLiability;
        proposalData.type = RequestTypes.CivilLiability;
        proposalData.data = element;
      }

      tabs = [...tabs, { type: type, name: '', tabData: proposalData }];
      proposalData = {};
    }

    return tabs;
  }
}

И просто чтобы дать обзор структуры, чтобы держать нас в здравом уме:

<app-detail>
  <mat-tab *ngFor = "let tab of tabs; let idx = index">
    <app-civilliability-proposal-detail [model] = "tab.tabData.data">
      <app-civilliability-step3 [(model)] = "model" ></app-civilliability-step3>
      </app-civilliability-step3
    </app-civilliability-proposal-detail>
  </mat-tab
</app-detail>

ОБНОВЛЕНИЕ 3: Добавить данные вкладок: Невозможно назначить свойство «закрыто» только для чтения объекта «[object Object]»

Свойство CivilLiabilityRequestTypeclosed доступно только для чтения, поэтому его нельзя назначить. Не могли бы вы показать тип модели?

briosheje 09.04.2019 10:01

Добавил модель. Но я не уверен, что это свойство доступно только для чтения. Я могу ошибаться.

Jordec 09.04.2019 10:05

ошибка довольно очевидна с этой точки зрения: TypeError: Cannot assign to свойство только для чтения "закрыто" of object '[object Object]''. Это означает, что тот, кто создает экземпляр CivilLiabilityRequestType, устанавливает для этого свойства значение только для чтения. Где он создается?

briosheje 09.04.2019 10:06

Было бы полезно, если бы вы разместили civilliability-detail.component.ts, где model изменяется каким-либо образом.

Sebastian Kaczmarek 09.04.2019 10:24

Добавлен код, который может помочь

Jordec 09.04.2019 10:28

Хорошо, не могли бы вы предоставить нам пример объекта из массива tabs после вызова this.createTabsFromQuoteModel()?

Sebastian Kaczmarek 09.04.2019 10:35

Добавленные вкладки приводят к обновлению 3

Jordec 09.04.2019 10:43
this.model.details выглядит неопределенным или нечитаемым, думаю, больше нечего сказать
Cristian Traìna 09.04.2019 10:45

Вы должны распечатать this.model.details и попытаться получить доступ closed

Cristian Traìna 09.04.2019 10:46
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
23
9
39 270
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я считаю, что это происходит потому, что вы не можете изменить объект, который хранится в состоянии (ngRx), вместо этого вы можете попробовать что-то вроде этого:

sendProposal() {
  this.store.dispatch(new CloseProposal(Object.assign({}, this.model, {
    details: { closed: true }
  })));
}

Я собираюсь отметить это как правильное решение, потому что это каким-то образом решило проблему в другом месте. Но вы были правы, вы не можете изменить объект, поступающий из состояния.

Jordec 09.04.2019 14:17

Я не знал, что состояние NgRx доступно только для чтения..... спасибо за помощь....

Alexander Sasha Shcherbakov 30.12.2019 14:32

Гений! Спасибо. Целый день мучился.

Abhijeet Khangarot 31.08.2020 14:37

Недавно я столкнулся с этой же ошибкой, и мне потребовалась минута, чтобы понять, что незаконно не только изменять объект I получать из хранилища ngrx, но и продолжать изменять объект после сохранения в ngrx. После передачи объекта в ngrx для хранения (эквивалент вашего this.model здесь) я должен сделать новую локальную копию, чтобы не изменять объект, который ngrx хранит как состояние.

Matthew Marichiba 05.10.2020 23:27

«Правило номер один NgRx, неизменность. Эта проверка strictStateImmutability проверяет, пытается ли разработчик изменить объект состояния». ngrx.io/guide/store/configuration/… Вы можете отключить его, но тогда вам следует подумать, действительно ли вы этого хотите. Пример в документации также может быть очень полезен при определении редьюсера для изменения состояния.

Albert-Jan Verhees 06.03.2021 09:24

Вы должны использовать метод Object.assign для изменения значения объекта следующим образом:

 Object.assign(target, source);

Другие вопросы по теме