I've been cracking my head on this for a few days now, but I can't find the reason why this is happening.
So I'm getting the following error message:
TypeError: Cannot assign to read only property 'closed' of object '[object Object]'
So as you can see, it happens in the civilliability-step3.component.ts at the sendProposal function:
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({}); } }
Useage of the component:
civilliability-detail.component.html
<app-civilliability-step3 (onCloseForm)="step1.closeForm(); step2.closeForm(); step3.closeForm()" [(model)]="model" #step3></app-civilliability-step3>
I've tried assigning the true value differently, because I figured maybe I can't add it directly to the model, which is an Input
. But that didn't help either.
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)); }
UPDATE 1: Added CivilLiabilityRequestType
export interface CivilLiabilityRequestType extends IRequestData { details: CivilLiabilityDetailsModel; questionnaire: CivilLiabilityQuestionnaireModel; comments: CivilLiabilityCommentsModel; } export class CivilLiabilityDetailsModel { baseReqId: number; startDate: string; branch: NamedResource; fractioning: NamedResource; closed: boolean; }
UPDATE 2: Show origin of this.model:
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; } }
And just to give an overview of the structure, to keep us sane:
<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>
UPDATE 3: Add tabs data:
The error "Cannot assign to read only property of object" occurs when we try to change a property of an object that has been frozen or when a property has been defined with Object. defineProperties() . To solve the error, create a copy of the object or array, or set the property to writable .
Readonly is a typescript keyword that makes the property read-only in a class, interface, or type alias. We make a property read-only by prefixing the property as readonly . We can assign a value to the readonly property only when initializing the object or within a constructor of the class.
I believe this happens because you cannot modify an object that is stored in the state (ngRx), you could try something like this instead:
sendProposal() { this.store.dispatch(new CloseProposal(Object.assign({}, this.model, { details: { closed: true } }))); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With