Уже несколько дней ломаю голову над этим, но не могу найти причину, почему это происходит.
Итак, я получаю следующее сообщение об ошибке:
TypeError: Cannot assign to read only property 'closed' of 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>
Добавил модель. Но я не уверен, что это свойство доступно только для чтения. Я могу ошибаться.
ошибка довольно очевидна с этой точки зрения: TypeError: Cannot assign to свойство только для чтения "закрыто" of object '[object Object]''. Это означает, что тот, кто создает экземпляр CivilLiabilityRequestType
, устанавливает для этого свойства значение только для чтения. Где он создается?
Было бы полезно, если бы вы разместили civilliability-detail.component.ts
, где model
изменяется каким-либо образом.
Добавлен код, который может помочь
Хорошо, не могли бы вы предоставить нам пример объекта из массива tabs
после вызова this.createTabsFromQuoteModel()
?
Добавленные вкладки приводят к обновлению 3
this.model.details
выглядит неопределенным или нечитаемым, думаю, больше нечего сказать
Вы должны распечатать this.model.details
и попытаться получить доступ closed
Я считаю, что это происходит потому, что вы не можете изменить объект, который хранится в состоянии (ngRx), вместо этого вы можете попробовать что-то вроде этого:
sendProposal() {
this.store.dispatch(new CloseProposal(Object.assign({}, this.model, {
details: { closed: true }
})));
}
Я собираюсь отметить это как правильное решение, потому что это каким-то образом решило проблему в другом месте. Но вы были правы, вы не можете изменить объект, поступающий из состояния.
Я не знал, что состояние NgRx доступно только для чтения..... спасибо за помощь....
Гений! Спасибо. Целый день мучился.
Недавно я столкнулся с этой же ошибкой, и мне потребовалась минута, чтобы понять, что незаконно не только изменять объект I получать из хранилища ngrx, но и продолжать изменять объект после сохранения в ngrx. После передачи объекта в ngrx для хранения (эквивалент вашего this.model
здесь) я должен сделать новую локальную копию, чтобы не изменять объект, который ngrx хранит как состояние.
«Правило номер один NgRx, неизменность. Эта проверка strictStateImmutability проверяет, пытается ли разработчик изменить объект состояния». ngrx.io/guide/store/configuration/… Вы можете отключить его, но тогда вам следует подумать, действительно ли вы этого хотите. Пример в документации также может быть очень полезен при определении редьюсера для изменения состояния.
Вы должны использовать метод Object.assign для изменения значения объекта следующим образом:
Object.assign(target, source);
Свойство
CivilLiabilityRequestType
closed
доступно только для чтения, поэтому его нельзя назначить. Не могли бы вы показать тип модели?