0

I'm trying to make a form like this;

<form #testForm="ngForm" (ngSubmit)="onSubmit(testForm)" novalidate>
    <!-- X-Value -->
    <div ngModelGroup="xValue" class="blocks">
      <h3>XValue</h3>
      <mat-radio-group name="value1" [(ngModel)]="data.xValue.value">
        <mat-radio-button value="xValue1" class="child">xValue1</mat-radio-button>
        <mat-radio-button value="xValue2" class="child">xValue2</mat-radio-button>
      </mat-radio-group>
      <textarea #text1 name="note1"[(ngModel)]="data.xValue.note"></textarea>
    </div>
    <!-- Y-Value -->
    <div ngModelGroup="yValue" class="blocks">
      <h3>YValue</h3>
      <mat-radio-group name="value2" [(ngModel)]="data.yValue.value">
        <mat-radio-button value="yValue1" class="child">yValue1</mat-radio-button>
        <mat-radio-button value="yValue2" class="child">yValue2</mat-radio-button>
      </mat-radio-group>
      <textarea #text2 name="note2" [(ngModel)]="data.yValue.note"></textarea>
    </div>
</form>

the values for this form are tied to a model in my ts file which I initialise like this;

data= {
    xValue: {
      value: "xValue1",
      note: ""
    },
    yValue: {
      value: "yValue1",
      note: ""
    },
}
defaultObj= JSON.parse(JSON.stringify(this.data));

initially I have to check an api to see if the form has been stored before, if yes then I have to show the previously stored form. For that I copy the object I received to this.data and the form loads the correct values. If there are no values then I have to show the default values, which is why I stored data into defaultObj.

apiCall(){
  this.data= JSON.parse(JSON.stringify(this.existingFormValuesFromApi));
}

This shows me the correct data on page load if there are saved values. The issue is when the user cancels the edits, the form should be reset to existingFormValuesFromApi.

I tried to do this;

//TS file
this.testForm.setValue(this.existingFormValuesFromApi)

but that also throws an error in the browser saying that I must provide a value for value1. How does that work? How is the initial value being loaded correctly? Why are changes to my data object also reflecting to my existingFormValuesFromApi object?

EDIT: Nested objects cannot be copied without reference using any of the methods, assign(), create() or using the spread operator; since I used only nested objects in my data object the changes made to data would reflect in allmy nested objects as well. As seen here.

Steve Chacko
  • 95
  • 11
  • Objects are mutable in javascript :) See the documentation for object assign: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#warning_for_deep_clone – AT82 Oct 31 '21 at 18:20
  • Also see: https://stackoverflow.com/questions/38617339/is-there-an-immutable-version-of-object-assign – AT82 Oct 31 '21 at 18:23
  • @AJT82 I tried ```this.data = Object.assign({}, this.existingFormValuesFromApi)``` and the spread operator but that still changed the existingFormValuesFromApi object for some reason – Steve Chacko Oct 31 '21 at 18:38
  • At that point its already too late, if you mean to set back the initial values. – AT82 Oct 31 '21 at 18:40
  • @AJT82, I understood the issue with the objects, but I still do not understand why angular does not let me use ```this.testForm.setValue(requiredObject)```, Please help – Steve Chacko Nov 01 '21 at 03:11
  • it has something to do with the name attribute on every form control but I don't understand why it isn't a problem when setting the data initially – Steve Chacko Nov 01 '21 at 03:13
  • Ah right... you have **nested** objects. Shallow copy (what you are using with `Object.assign({}, this.existingFormValuesFromApi)` does not work for that) You need to probably write a function that does a deep clone of your object. – AT82 Nov 01 '21 at 17:35
  • Changing to reactive forms would also solve this issue, not directly answering your question though, but just putting it out there. – AT82 Nov 01 '21 at 17:41

0 Answers0