0

I have an array with questions.I have to read it and show questions dynamically.So I have few questions related to it.

1) I have no idea how to initialize controllers to FormBuilder instance.

2) how to create questions dynamically

3) how to add validations dynamically

I created this project using angular 8.

Mainly I have 4 types of questions in a survey.

  1. MCQ ( only have to select one answer)

  2. Multiple Select ( User can select multiple answers)

  3. Ranking question ( user have to give the correct order of answers)

  4. Descriptive ( Users own answer can give)

Here is my array with questions

questions: any = [
{
  id: 11,
  surveyNo: 5,
  qNo: 1,
  question: 'What is the country you would like to travel?',
  qType: 1,
  noAnswrs: 4,
  answerType: 1,
  answrs: ['America', 'Australia', 'India', 'England']
},
{
  id: 12,
  surveyNo: 5,
  qNo: 2,
  question: 'What type of credit cards do you have?',
  qType: 2,
  noAnswrs: 4,
  answerType: 1,
  answrs: ['Visa', 'Mastercard', 'American Express', 'Discover']
},
{
  id: 13,
  surveyNo: 5,
  qNo: 3,
  question: 'Please rank the following features in order of importance,where 1 is the most important to you.?',
  qType: 3,
  noAnswrs: 4,
  answerType: 1,
  answrs: ['Location', 'Confort', 'Service', 'Value for money']
},
{
  id: 14,
  surveyNo: 5,
  qNo: 4,
  question: 'What is your idea about our institute?',
  qType: 4,
  noAnswrs: 0,
  answerType: 1,
  answrs: []
}];

here is html code

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

<div class="container">
    <div class="row">
        <div class="col-md-12">
            <div class="card">
                <div class="card-header  bg-transparent border-success">
                    <h3>15 questions</h3>
                </div>
                <div class="card-body">
                    <div class="row">
                        <div class="col-md-12">
                            <form [formGroup]="surveyQuestionForm">
                                <div class="form-group">
                                    <label class="control-label"> 1) What is the country you would like to
                                        travel?</label>
                                    <div class="ml-3">
                                        <table>
                                            <th width="auto"></th>
                                            <th width="auto"></th>
                                            <tr>
                                                <td>1. America</td>
                                                <td>
                                                    <div class=" custom-radio custom-control">
                                                        <input type="radio" class="custom-control-input" id="q1_1"
                                                            name="q1" value="1" formControlName="q1" />
                                                        <label class="custom-control-label" for="q1_1">

                                                        </label>
                                                    </div>
                                                </td>
                                            </tr>
                                            <tr>
                                                <td>2. Australia </td>
                                                <td>
                                                    <div class=" custom-radio custom-control">
                                                        <input type="radio" class="custom-control-input" id="q1_2"
                                                            name="q1" value="2" formControlName="q1" />
                                                        <label class="custom-control-label" for="q1_2"></label>
                                                    </div>
                                                </td>
                                            </tr>
                                            <tr>
                                                <td>3. India </td>
                                                <td>
                                                    <div class="custom-radio custom-control">
                                                        <input type="radio" class="custom-control-input" id="q1_3"
                                                            name="q1" value="3" formControlName="q1" />
                                                        <label class="custom-control-label" for="q1_3"></label>
                                                    </div>
                                                </td>
                                            </tr>
                                            <tr>
                                                <td>4. England </td>
                                                <td>
                                                    <div class=" custom-control  custom-radio">
                                                        <input type="radio" class="custom-control-input" id="q1_4"
                                                            name="q1" value="4" formControlName="q1" />
                                                        <label class="custom-control-label" for="q1_4"></label>
                                                    </div>
                                                </td>
                                            </tr>
                                        </table>





                                    </div>
                                </div>
                               
                                <div class="form-group">
                                    <label class="control-label"> 2) What type of credit cards do you have?</label>
                                    <div class="ml-3">
                                        <table>
                                            <th width="auto"></th>
                                            <th width="auto"></th>
                                            <tr>
                                                <td>1. Visa </td>
                                                <td>
                                                    <div class="custom-control custom-checkbox">
                                                        <input type="checkbox" class="custom-control-input" id="q2_1"
                                                            value="1" formControlName="q2" />
                                                        <label class="custom-control-label" for="q2_1"></label>
                                                    </div>
                                                </td>
                                            </tr>
                                            <tr>
                                                <td>2. Mastercard</td>
                                                <td>
                                                    <div class="custom-control custom-checkbox">
                                                        <input type="checkbox" class="custom-control-input" id="q2_2"
                                                            value="2" formControlName="q2" />
                                                        <label class="custom-control-label" for="q2_2"></label>
                                                    </div>
                                                </td>
                                            </tr>
                                            <tr>
                                                <td>3. American Express</td>
                                                <td>
                                                    <div class="custom-control custom-checkbox">
                                                        <input type="checkbox" class="custom-control-input" id="q2_3"
                                                            value="3" formControlName="q2" />
                                                        <label class="custom-control-label" for="q2_3"></label>
                                                    </div>
                                                </td>
                                            </tr>
                                            <tr>
                                                <td>4. Discover</td>
                                                <td>
                                                    <div class="custom-control custom-checkbox">
                                                        <input type="checkbox" class="custom-control-input" id="q2_4"
                                                            value="4" formControlName="q2" />
                                                        <label class="custom-control-label" for="q2_4"></label>
                                                    </div>
                                                </td>
                                            </tr>
                                        </table>
                                    </div>
                                </div>
                                <div class="form-group">
                                    <label class="control-label"> 3) Please rank the following features in order of importance,where 1 is the most important to you.?</label>
                                    <div class="ml-3">
                                        <table>
                                             
                                            <tr>
                                                <td>1. Location </td>
                                                <div class="invalid-feedback"
                                                 *ngIf="surveyQuestionForm.get('q3').touched && surveyQuestionForm.get('q3').hasError('required')">Answer required</div>
                                                 <div class="invalid-feedback"
                                                 *ngIf="surveyQuestionForm.get('q3').touched && surveyQuestionForm.get('q3').hasError('max')">max value</div>
               
                                                <td><input type="number" style="width:40px;" id="q3_1"  
                                                    [ngClass]="{'is-invalid': surveyQuestionForm.get('q3').errors && surveyQuestionForm.get('q3').touched}"
                                                        formControlName="q3" class="text-center" /></td>
                                            </tr>
                                              <tr>
                                                <td>2. Confort </td>
                                                <td><input type="number" style="width:40px;" id="q3_1"  
                                                         class="text-center" /></td>
                                            </tr>
                                            <tr>
                                                <td>3. Service </td>
                                                <td><input type="number" style="width:40px;" id="q3_1"  
                                                          class="text-center" /></td>
                                            </tr>
                                            <tr>
                                                <td>4. Value for money </td>
                                                <td><input type="number" style="width:40px;" id="q3_1"  
                                                          class="text-center" /></td>
                                            </tr>
                                        </table>


                                    </div>
                                </div>
                                <div class="form-group">
                                    <label class="control-label"> 4) What is your idea about our institute?</label>
                                    <div class="ml-3">
                                        <table>
                                            <th width="auto"></th>
                                            <th></th>

                                            <tr>

                                                <td><textarea class="form-control" rows="5" id="comment" name="text"
                                                        formControlName="q4"></textarea></td>
                                            </tr>

                                        </table>


                                    </div>
                                </div>
                                
                            </form>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-md-12">
                            <button class="btn btn-primary">Submit</button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

here is typescript code

 surveyQuestionForm: FormGroup;
  constructor(private fb: FormBuilder) { }
  questions: any = [
    {
      id: 11,
      surveyNo: 5,
      qNo: 1,
      question: 'What is the country you would like to travel?',
      qType: 1,
      noAnswrs: 4,
      answerType: 1,
      answrs: ['America', 'Australia', 'India', 'England']
    },
    {
      id: 12,
      surveyNo: 5,
      qNo: 2,
      question: 'What type of credit cards do you have?',
      qType: 2,
      noAnswrs: 4,
      answerType: 1,
      answrs: ['Visa', 'Mastercard', 'American Express', 'Discover']
    },
    {
      id: 13,
      surveyNo: 5,
      qNo: 3,
      question: 'Please rank the following features in order of importance,where 1 is the most important to you.?',
      qType: 3,
      noAnswrs: 4,
      answerType: 1,
      answrs: ['Location', 'Confort', 'Service', 'Value for money']
    },
    {
      id: 14,
      surveyNo: 5,
      qNo: 4,
      question: 'What is your idea about our institute?',
      qType: 4,
      noAnswrs: 0,
      answerType: 1,
      answrs: []
    }
  ];
  ngOnInit() {
    this.createForms();
  }
  createForms(): any {
    this.surveyQuestionForm = this.fb.group({
      q1: ['', [Validators.required]],
      q2: ['', [Validators.required]],
      q3: ['', [Validators.required, Validators.min(1), Validators.max(3)]],
      q4: ['', [Validators.required]]
     });
  }

Here is the questions preview enter image description here

Here are the validators have to use

  1. required validator
  2. min value(1) and max value(4)
  3. have to check already inserted value inserted or not (no idea how to do this dynamically)

I red many articles,but those are not in dynamically create. Please help me to do this

thanks

1 Answer 1

1

it's not very clear what you're after, but it would look something like this I think....

private buildSubGroup(question) {
  switch (question.qType) {
    case 2:
      return this.fb.group(
        question.answers.reduce((subGroup, answer) => {
          return Object.assign(subGroup, {[answer]: [false]});
        }, {}), {validators: [atLeastOneRequired()]} // validation rules here unclear? is at least 1 required?
      );
    case 3:
      return this.fb.group(
        question.answers.reduce((subGroup, answer) => {
          return Object.assign(subGroup, {[answer]: ['', [Validators.required, Validators.min(1), Validators.max(3)]]});
        }, {}), {validators: [uniqueNumbersValidator()]}
      );
    case 1: // it's counter intuitive but these are actually the same structure due to how angular handles radio input
    case 4:
      return this.fb.group({answer: ['', [Validators.required]]});
    default:
      throw new Error('unhandled question type');
  }
}

this.surveyQuestionForm = this.fb.group(
  this.questions.reduce((group, question) => {
    return Object.assign(group, {['q' + question.qNo]: this.buildSubGroup(question)});
  }, {});
);

so basically, you take your questions array and reduce them to an object with 'q' plus the qNo as keys and the values are the sub form group which depends on the qType... you also need some group level custom validators that needs to be written to confirm that each number only appears once and at least one is selected, which could look like this:

   function atLeastOneRequired() {
     return (ctrl: AbstractControl) => {
       let fg = ctrl as FormGroup;
       let atLeastOneTrue = Object.values(fg.controls).some(fc => !!fc.value);
       return (atLeastOneTrue ) ? null : {atLeastOneRequired: true};
     };
   }

   function uniqueNumbersValidator() {
     return (ctrl: AbstractControl) => {
       let fg = ctrl as FormGroup;
       let allUnique = true;
       let values = [];
       Object.values(fg.controls).forEach(fc => {
         let val = fc.value;
         if (val && allUnique) {
           if (values.includes(val)) {
             allUnique = false;
             break;
           }
           values.push(val);
         }
       });
       return (allUnique) ? null : {notAllUnique: true};
     }
   }

the template binding itself would be fairly different from how you have it, but this answers how to build the form control in a dynamic fashion. You could build the question templates by iterating over the questions array and binding appropriately with formGroupName and formControlName directives and the ngSwitch directive in a similar manner as I used switch statements here to build the form groups.

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

16 Comments

thanks alot for your reply, actually I have 4 types of questions.This question is 2nd type one.So in template I want to read questions array and check the question type(qType) and generate the question. In this question I have to check qType === 2 then generate this question.Can you please help me to do this? And uniqueNumbersValidator() have to add only this type question.If you want I can give you an array with all the 4 type questions.
I’d need to see the full array of types to write a full answer but what’s here should give you an idea of what writing dynamic forms looks like
I updated question and added all the things.Please help me
i showed how to build the form groups for all the question types. past that is a new question.
Thanks alot brayan,Can you please give me an idea about how to do this in template also?
|

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.