1

Firstly sorry for creating a long post but I had no option other than this as I need to explain where am facing issue.

I have a form where a control is an array of JSON. I've created a reactive form wrt that. Below is my JSON and my TS code:

JSON (got from backend request)

{
    "questionList": [
        {
            "questionCategory": {
                "questionCategoryName": "JAVA",
                "id": 40,
                "isActive": true,
                "timestamp": "2020-06-12 14:06:47.325"
            },
            "difficultyLevel": 0,
            "options": [
                {
                    "answer": false,
                    "id": 2,
                    "optionText": "method",
                    "timestamp": "2020-06-18 17:17:11.75"
                },
                {
                    "answer": false,
                    "id": 3,
                    "optionText": "name",
                    "timestamp": "2020-06-18 17:17:11.753"
                },
                {
                    "answer": false,
                    "id": 4,
                    "optionText": "class",
                    "timestamp": "2020-06-18 17:17:11.758"
                },
                {
                    "answer": true,
                    "id": 1,
                    "optionText": "variable",
                    "timestamp": "2020-06-18 17:17:11.663"
                }
            ],
            "section": {
                "marksPerQuestion": 3,
                "id": 8,
                "isActive": true
            },
            "id": 1,
            "isActive": true,
            "questionText": "What is a variable ?",
            "timestamp": "2020-06-18 17:17:10.946"
        },
        {
            "questionCategory": {
                "questionCategoryName": "APTITUDE",
                "id": 41,
                "isActive": true
            },
            "difficultyLevel": 0,
            "options": [
                {
                    "answer": true,
                    "id": 6,
                    "optionText": "xyz",
                    "timestamp": "2020-06-17 21:50:48.975"
                },
                {
                    "answer": true,
                    "id": 5,
                    "optionText": "abc",
                    "timestamp": "2020-06-17 21:50:48.907"
                }
            ],
            "section": {
                "marksPerQuestion": 2,
                "id": 7,
                "isActive": true,
                "timestamp": "2020-06-12 14:08:14.181"
            },
            "id": 2,
            "isActive": true,
            "questionText": "What is def",
            "timestamp": "2020-06-17 21:50:48.6"
        }
    ],
    "empty": false
}

TS Code for this JSON

updateQuestionForm = this.fb.group({
  id: [], isActive: [], difficultyLevel: [0], questionText: [''],
  questionCategory: this.fb.group({
    id: [],
    questionCategoryName: ['']
  }),
  section: this.fb.group({
    id: [],
    marksPerQuestion: ['']
  }),
  options: new FormArray([])
});

optionForm = this.fb.group({
  id: [], optionText: [''], answer: []
});

onEdit(e) {
  const formArray: FormArray = this.updateQuestionForm.get('options') as FormArray;
  this.updateQuestionForm.controls['id'].setValue(e.id);
  this.updateQuestionForm.controls['isActive'].setValue(e.isActive);
  this.updateQuestionForm.controls['questionText'].setValue(e.questionText);
  this.updateQuestionForm.controls['questionCategory'].setValue({
    id: e.questionCategory.id,
    questionCategoryName: e.questionCategory.questionCategoryName
  });
  this.updateQuestionForm.controls['section'].setValue({
    id: e.section.id,
    marksPerQuestion: e.section.marksPerQuestion
  });
  for(let i of e.options) {
    this.optionForm.controls['id'].setValue(i.id);
    this.optionForm.controls['optionText'].setValue(i.optionText);
    this.optionForm.controls['answer'].setValue(i.answer);
    formArray.push(new FormControl(this.optionForm.value));
  }
  console.log(this.updateQuestionForm.value);
}

get Status() {
  return this.updateQuestionForm.get('isActive');
}

get Options(): FormArray {
  return this.updateQuestionForm.get('options') as FormArray;
}

Let me explain what the TS states: Firstly, I am creating a form of updateQuestionForm which is the main form for the JSON. The second form of optionForm is for the options FormArray of updateQuestionForm. I've created this second form because I need certain controls from the array. So this stuck in my mind. The onEdit() method is triggered by a button click which fetches the JSON from a Mat-Table.

The HTML form

<form [formGroup]="updateQuestionForm" (submit)="onUpdateQuestionForm()">
  <div class="row">
    <div class="col-md-4">
      <mat-form-field>
        <mat-label>Enter Question</mat-label>
        <input matInput formControlName="questionText">
      </mat-form-field>
    </div>
    <div class="col-md-3">
      <mat-form-field formGroupName="questionCategory">
        <mat-label>Question Category</mat-label>
        <mat-select formControlName="id">
          <ng-container *ngFor="let q of QuestionCategory;">
            <mat-option [value]="q.id">{{ q.questionCategoryName }}</mat-option>
          </ng-container>
        </mat-select>
      </mat-form-field>
    </div>
    <div class="col-md-3">
      <mat-form-field formGroupName="section">
        <mat-label>Marks</mat-label>
        <mat-select formControlName="id">
          <ng-container *ngFor="let m of Marks;">
            <mat-option [value]="m.id">{{ m.marksPerQuestion }}</mat-option>
          </ng-container>
        </mat-select>
      </mat-form-field>
    </div>
    <div class="col-md-2">
      <mat-label>Status</mat-label><br>
      <mat-slide-toggle color="primary" formControlName="isActive">{{ Status ? 'Active' : 'Inactive' }}</mat-slide-toggle>
    </div>
  </div>
  <h3>Options & Answers</h3>
  <div formArrayName="options">
    <div class="row" *ngFor="let o of Options.value; index as i" [formGroupName]="i">
      <div class="col-md-6">
        <mat-form-field>
          <mat-label>Option</mat-label>
          <input matInput formControlName="optionText">
        </mat-form-field>
      </div>
      <div class="col-md-3">
        <mat-label>Answer</mat-label><br>
        <mat-slide-toggle color="primary" formControlName="answer">
           {{ answer ? 'True' : 'False' }}
        </mat-slide-toggle>
      </div>
    </div>
  </div>
  <button mat-flat-button type="submit" style="background-color: #28a745; color: white;">Update</button>
</form>

This is the form of the JSON. I'm successfully able to fetch and store the value for the controls questionCategory, section, isActive, questionText. The problem is occurring for the options control. There I have 4 options (with 4 optionText, 4 answer each fetched from the database; refer the sample JSON above). But I am not able to display the controls. Looks like the ngFor inside formArrayName="options" is not working. After the h2, nothing is coming.

Please help me. FYI I was following this link for the formArrayName looping part.

Here's the initial view

8
  • Correct me if I am wrong, With the updateQuestionForm you are trying to create the JSON structure you have mentioned above? Or are you trying to take answers from the user for the given questions list? Commented Jun 18, 2020 at 13:19
  • @Harish yes. Actually this is an update form, the onEdit() method is fetching values and initializing it in the updateQuestionForm controls. These values will be retrieved in the view part with the controls. And then if the value gets changed the Update button will send the values to the backend which I'll integrate later for timing I need the options to get rendered to view. Commented Jun 18, 2020 at 13:24
  • So basically, you are using this form to update the questions and the options, right? If yes, the structure of your form is complex and can be simplified. Firstly you don't need the optionForm. Commented Jun 18, 2020 at 13:29
  • yes, I am using this as an update form. Then please suggest me the simplified approach Commented Jun 18, 2020 at 13:30
  • Don't mind these multiple questions I am asking. Are you using this form to update a single question or multiple questions at once? I am trying to write the code on stackbliz for you to easily understand the fix. Commented Jun 18, 2020 at 13:34

1 Answer 1

1

For your use case, you don't need two forms to update the question data and your code looks complex.

I have simplified your code and it is working fine for me. You can check it out here.

What did I do?

1) Basically, I have created a simple form structure in ngOnInit() based on your code samples.

2) I have written updateQuestionData() function where I am patching the form with the JSON data. I have iterated over the options and created a form group for each option.

You can modify the values on the form and see the how updateQuestionForm is updating.

I hope this simplifies your use case and optimizes your code.

Sign up to request clarification or add additional context in comments.

1 Comment

thanks, brother. It's working fine. You have made the code so simple :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.