Create Dynamic Row With Custom MultiSelect Dropdowns In Angular 8

Introduction

 
In this article, we will learn how to create dynamic row and custom multiselect dropdowns, using Angular 8. 
 
How it will work 
 
Angular multiselect dropdown component for web applications is easy to integrate and use.  It can bind to any custom data source.  Multi dropdown checkbox is already available in Angular, called ng-multiselect-dropdown, but here we are not using that.  We are creating our own, plus we will give the functionality to select only two values in a checkbox.  This means, when we try to select more than two values it will remove the first value and a select third.
 
Prerequisite
  • Basic knowledge of Angular
  • Visual Studio Code must be installed
  • Angular CLI must be installed
  • Node JS must be installed
Step 1 
 
Let us create an Angular project, using the following npm command.
  1. ng new multiSelectCheckbox   
Step 2
 
Open the newly created project in visual studio code and install bootstrap in this project.
  1. npm install bootstrap --save  
Now, open styles.css file and add Bootstrap file reference.  To add reference in styles.css file add this line.
  1. @import '~bootstrap/dist/css/bootstrap.min.css';  
Step 3 Now, let's create a new component, by using following command.
  1. ng g c home   
Step 4
 
Now create a new class, to create class use the following command. 
  1. ng generate class blankRow  
Now, open the class and add the following code.
  1. export class BlankRow {  
  2.     RollNo:number;  
  3.     Name:string;  
  4.     Medium:any;  
  5.     Class:any;  
  6.     Section:any;  
  7.     Books:any=[];  
  8.     SelectedBooks:any=[];  
  9.     Subject=[];  
  10.     SelectedSubject=[];  
  11. }  
Step 5
 
Now, open home component.ts file and add the following code in this file. 
  1. import {  
  2.     Component,  
  3.     OnInit  
  4. } from '@angular/core';  
  5. import {  
  6.     BlankRow  
  7. } from '../models/blankRow';  
  8. @Component({  
  9.     selector: 'app-home',  
  10.     templateUrl: './home.component.html',  
  11.     styleUrls: ['./home.component.css']  
  12. })  
  13. export class HomeComponent implements OnInit {  
  14.     blankRowArray: Array < BlankRow > = [];  
  15.     blankRowData = new BlankRow();  
  16.     hideMultiSelectDropdownAll: boolean[] = [];  
  17.     hideMultiSelectDropdown: boolean[] = [];  
  18.     hideMultiSelectedSubjectDropdown: boolean[] = [];  
  19.     hideMultiSelectedSubjectDropdownAll: boolean[] = [];  
  20.     tempData = [];  
  21.     savedSubjects = [];  
  22.     Books = [];  
  23.     Subject = [];  
  24.     constructor() {}  
  25.     ngOnInit() {  
  26.         this.Subject = [{  
  27.             value: "English",  
  28.             IsChecked: false  
  29.         }, {  
  30.             value: "History",  
  31.             IsChecked: false  
  32.         }, {  
  33.             value: "Geography",  
  34.             IsChecked: false  
  35.         }, {  
  36.             value: "Hindi",  
  37.             IsChecked: false  
  38.         }, {  
  39.             value: "Marathi",  
  40.             IsChecked: false  
  41.         }, {  
  42.             value: "Civics",  
  43.             IsChecked: false  
  44.         }, {  
  45.             value: "Science",  
  46.             IsChecked: false  
  47.         }, {  
  48.             value: "Mathematics",  
  49.             IsChecked: false  
  50.         }];  
  51.         this.Books = [{  
  52.             value: "CBSE Class 10 English Literature Reader Book",  
  53.             IsChecked: false  
  54.         }, {  
  55.             value: "CBSE Class 10 English Book",  
  56.             IsChecked: false  
  57.         }, {  
  58.             value: "CBSE Class 10th Maths Book",  
  59.             IsChecked: false  
  60.         }, {  
  61.             value: "CBSE Class 10th Hindi Book",  
  62.             IsChecked: false  
  63.         }, {  
  64.             value: "CBSE Class 10 Science Book",  
  65.             IsChecked: false  
  66.         }, {  
  67.             value: "Class 10 CBSE Geography Book",  
  68.             IsChecked: false  
  69.         }, {  
  70.             value: "Class 10th Economics Book",  
  71.             IsChecked: false  
  72.         }, {  
  73.             value: "CBSE Class 10 Sanskrit Book",  
  74.             IsChecked: false  
  75.         }];  
  76.     }  
  77.     addBlankRow() {  
  78.         const blankRowData = new BlankRow();  
  79.         blankRowData.RollNo = 0,  
  80.             blankRowData.Name = '',  
  81.             blankRowData.Medium = 0,  
  82.             blankRowData.Class = 0,  
  83.             blankRowData.Section = 0,  
  84.             blankRowData.Books = [],  
  85.             blankRowData.Subject = [],  
  86.             blankRowData.SelectedSubject = [{  
  87.                 IsChecked: false  
  88.             }, {  
  89.                 IsChecked: false  
  90.             }, {  
  91.                 IsChecked: false  
  92.             }, {  
  93.                 IsChecked: false  
  94.             }, {  
  95.                 IsChecked: false  
  96.             }, {  
  97.                 IsChecked: false  
  98.             }, {  
  99.                 IsChecked: false  
  100.             }, {  
  101.                 IsChecked: false  
  102.             }],  
  103.             blankRowData.SelectedBooks = [{  
  104.                 IsChecked: false  
  105.             }, {  
  106.                 IsChecked: false  
  107.             }, {  
  108.                 IsChecked: false  
  109.             }, {  
  110.                 IsChecked: false  
  111.             }, {  
  112.                 IsChecked: false  
  113.             }, {  
  114.                 IsChecked: false  
  115.             }, {  
  116.                 IsChecked: false  
  117.             }, {  
  118.                 IsChecked: false  
  119.             }],  
  120.             this.blankRowArray.push(blankRowData)  
  121.     }  
  122.     openMultiSelectDD(i) {  
  123.         for (var x = 0; x < this.blankRowArray.length; x++) {  
  124.             this.hideMultiSelectDropdownAll[x] = false;  
  125.             this.hideMultiSelectedSubjectDropdownAll[x] = false;  
  126.             this.hideMultiSelectedSubjectDropdown[x] = false;  
  127.         }  
  128.         this.hideMultiSelectDropdownAll[i] = true;  
  129.         this.hideMultiSelectDropdown[i] = !this.hideMultiSelectDropdown[i];  
  130.     }  
  131.     openMultiSelectDDForSubject(i) {  
  132.         for (var x = 0; x < this.blankRowArray.length; x++) {  
  133.             this.hideMultiSelectedSubjectDropdownAll[x] = false;  
  134.             this.hideMultiSelectDropdownAll[x] = false;  
  135.             this.hideMultiSelectDropdown[x] = false;  
  136.         }  
  137.         this.hideMultiSelectedSubjectDropdownAll[i] = true;  
  138.         this.hideMultiSelectedSubjectDropdown[i] = !this.hideMultiSelectedSubjectDropdown[i];  
  139.     }  
  140.     //MultiSelect DropDown For Books    
  141.     booksChecked(list: any, i, x, isChecked: boolean) {  
  142.         let selectedBooks = list.value;  
  143.         if (isChecked) {  
  144.             this.blankRowArray[i].Books.push(selectedBooks);  
  145.             this.blankRowArray[i].SelectedBooks[x].IsChecked = true;  
  146.         } else {  
  147.             this.blankRowArray[i].Books = this.blankRowArray[i].Books.filter(obj => obj !== selectedBooks);  
  148.             this.blankRowArray[i].SelectedBooks[x].IsChecked = false;  
  149.         }  
  150.     }  
  151.     //On Subject Checked    
  152.     onSubjectChecked(list: any, i, x, isChecked: boolean) {  
  153.         let selectedSubject = list.value;  
  154.         if (this.blankRowArray[i].Subject.length < 2) {  
  155.             if (isChecked) {  
  156.                 if (this.blankRowArray[i].Subject.length == 0) {  
  157.                     this.tempData = [];  
  158.                 }  
  159.                 if (this.tempData.length < 2) {  
  160.                     this.tempData.push(x);  
  161.                 }  
  162.                 if (this.tempData.length == 2) {  
  163.                     let saveSub = this.tempData.join(',');  
  164.                     this.savedSubjects[i] = saveSub;  
  165.                     console.log(this.savedSubjects[i]);  
  166.                 }  
  167.                 this.blankRowArray[i].Subject.push(selectedSubject);  
  168.                 this.blankRowArray[i].SelectedSubject[x].IsChecked = true;  
  169.                 this.Subject[x].IsChecked = true;  
  170.             } else {  
  171.                 this.tempData.filter(obj => obj !== x);  
  172.                 this.blankRowArray[i].Subject = this.blankRowArray[i].Subject.filter(obj => obj !== selectedSubject)  
  173.                 this.blankRowArray[i].SelectedSubject[x].IsChecked = false;  
  174.             }  
  175.         } else {  
  176.             if (isChecked) {  
  177.                 this.blankRowArray[i].Subject[0] = this.blankRowArray[i].Subject[1];  
  178.                 this.blankRowArray[i].SelectedSubject[x].IsChecked = true;  
  179.                 let saveSub0 = this.savedSubjects[i].split(',')[0] ? this.savedSubjects[i].split(',')[0] : this.tempData[0];  
  180.                 let saveSub1 = this.savedSubjects[i].split(',')[1] ? this.savedSubjects[i].split(',')[1] : this.tempData[1];  
  181.                 var temp = saveSub0;  
  182.                 this.tempData[0] = saveSub1;  
  183.                 this.tempData[1] = x;  
  184.                 this.blankRowArray[i].SelectedSubject[temp].IsChecked = false;  
  185.                 this.Subject[x].IsChecked = true;  
  186.                 this.blankRowArray[i].Subject[1] = selectedSubject;  
  187.                 this.savedSubjects[i] = this.tempData.join(',');  
  188.             } else {  
  189.                 var temp = this.tempData.find(a => a == x);  
  190.                 this.tempData = [];  
  191.                 this.tempData[0] = temp;  
  192.                 this.blankRowArray[i].Subject = this.blankRowArray[i].Subject.filter(obj => obj !== selectedSubject)  
  193.                 this.blankRowArray[i].SelectedSubject[x].IsChecked = false;  
  194.             }  
  195.         }  
  196.     }  
  197.     deleteRow(index) {  
  198.         this.blankRowArray.splice(index, 1);  
  199.     }  
  200. }  
  1. deleteRow(index) {    
  2.    this.blankRowArray.splice(index, 1);    
  3.  }    
deleteRow method is use to delete created row. 
  1. addBlankRow() {  
  2.     const blankRowData = new BlankRow();  
  3.     blankRowData.RollNo = 0,  
  4.         blankRowData.Name = '',  
  5.         blankRowData.Medium = 0,  
  6.         blankRowData.Class = 0,  
  7.         blankRowData.Section = 0,  
  8.         blankRowData.Books = [],  
  9.         blankRowData.Subject = [],  
  10.         blankRowData.SelectedSubject = [{  
  11.             IsChecked: false  
  12.         }, {  
  13.             IsChecked: false  
  14.         }, {  
  15.             IsChecked: false  
  16.         }, {  
  17.             IsChecked: false  
  18.         }, {  
  19.             IsChecked: false  
  20.         }, {  
  21.             IsChecked: false  
  22.         }, {  
  23.             IsChecked: false  
  24.         }, {  
  25.             IsChecked: false  
  26.         }],  
  27.         blankRowData.SelectedBooks = [{  
  28.             IsChecked: false  
  29.         }, {  
  30.             IsChecked: false  
  31.         }, {  
  32.             IsChecked: false  
  33.         }, {  
  34.             IsChecked: false  
  35.         }, {  
  36.             IsChecked: false  
  37.         }, {  
  38.             IsChecked: false  
  39.         }, {  
  40.             IsChecked: false  
  41.         }, {  
  42.             IsChecked: false  
  43.         }],  
  44.         this.blankRowArray.push(blankRowData)  
  45. }  
addBlankRow method is used to add a new blank row on the click of the Add new Row button.
  1. openMultiSelectDD(i) {  
  2.     for (var x = 0; x < this.blankRowArray.length; x++) {  
  3.         this.hideMultiSelectDropdownAll[x] = false;  
  4.         this.hideMultiSelectedSubjectDropdownAll[x] = false;  
  5.         this.hideMultiSelectedSubjectDropdown[x] = false;  
  6.     }  
  7.     this.hideMultiSelectDropdownAll[i] = true;  
  8.     this.hideMultiSelectDropdown[i] = !this.hideMultiSelectDropdown[i];  
  9. }  
openMultiSelectDD method is used to open dropdowns (related to books) when it gets clicked.  I used "for" loop here, to close all particular dropdowns and open only selected ones.
  1. openMultiSelectDDForSubject(i) {  
  2.     for (var x = 0; x < this.blankRowArray.length; x++) {  
  3.         this.hideMultiSelectedSubjectDropdownAll[x] = false;  
  4.         this.hideMultiSelectDropdownAll[x] = false;  
  5.         this.hideMultiSelectDropdown[x] = false;  
  6.     }  
  7.     this.hideMultiSelectedSubjectDropdownAll[i] = true;  
  8.     this.hideMultiSelectedSubjectDropdown[i] = !this.hideMultiSelectedSubjectDropdown[i];  
  9. }  
openMultiSelectDDForSubject method is used to open dropdown (related to subject) when it gets clicked. I used "for" loop here to close all particular dropdowns and opened only the selected one. 
  1. //MultiSelect DropDown For Books    
  2. booksChecked(list: any, i, x, isChecked: boolean) {  
  3.     let selectedBooks = list.value;  
  4.     if (isChecked) {  
  5.         this.blankRowArray[i].Books.push(selectedBooks);  
  6.         this.blankRowArray[i].SelectedBooks[x].IsChecked = true;  
  7.     } else {  
  8.         this.blankRowArray[i].Books = this.blankRowArray[i].Books.filter(obj => obj !== selectedBooks);  
  9.         this.blankRowArray[i].SelectedBooks[x].IsChecked = false;  
  10.     }  
  11. }  
In the above code, I have used some parameters, which I will explain one by one.
  • list :It Stores the selected value from the checkbox. 
  • i :It stores the current blank row index value.
  • x :It stores the current checkbox index value.
  • isChecked :It stores the boolean value of the checkbox (for checked 'true' and for unchecked 'false' ).
If Checked, then it will push into an array and assign SelectedBooks.Ischecked as true.  It can check or uncheck all checkboxes:
  1. //On Subject Checked    
  2. onSubjectChecked(list: any, i, x, isChecked: boolean) {  
  3.     let selectedSubject = list.value;  
  4.     if (this.blankRowArray[i].Subject.length < 2) {  
  5.         if (isChecked) {  
  6.             if (this.blankRowArray[i].Subject.length == 0) {  
  7.                 this.tempData = [];  
  8.             }  
  9.             if (this.tempData.length < 2) {  
  10.                 this.tempData.push(x);  
  11.             }  
  12.             if (this.tempData.length == 2) {  
  13.                 let saveSub = this.tempData.join(',');  
  14.                 this.savedSubjects[i] = saveSub;  
  15.                 console.log(this.savedSubjects[i]);  
  16.             }  
  17.             this.blankRowArray[i].Subject.push(selectedSubject);  
  18.             this.blankRowArray[i].SelectedSubject[x].IsChecked = true;  
  19.             this.Subject[x].IsChecked = true;  
  20.         } else {  
  21.             this.tempData.filter(obj => obj !== x);  
  22.             this.blankRowArray[i].Subject = this.blankRowArray[i].Subject.filter(obj => obj !== selectedSubject)  
  23.             this.blankRowArray[i].SelectedSubject[x].IsChecked = false;  
  24.         }  
  25.     } else {  
  26.         if (isChecked) {  
  27.             this.blankRowArray[i].Subject[0] = this.blankRowArray[i].Subject[1];  
  28.             this.blankRowArray[i].SelectedSubject[x].IsChecked = true;  
  29.             let saveSub0 = this.savedSubjects[i].split(',')[0] ? this.savedSubjects[i].split(',')[0] : this.tempData[0];  
  30.             let saveSub1 = this.savedSubjects[i].split(',')[1] ? this.savedSubjects[i].split(',')[1] : this.tempData[1];  
  31.             var temp = saveSub0;  
  32.             this.tempData[0] = saveSub1;  
  33.             this.tempData[1] = x;  
  34.             this.blankRowArray[i].SelectedSubject[temp].IsChecked = false;  
  35.             this.Subject[x].IsChecked = true;  
  36.             this.blankRowArray[i].Subject[1] = selectedSubject;  
  37.             this.savedSubjects[i] = this.tempData.join(',');  
  38.         } else {  
  39.             var temp = this.tempData.find(a => a == x);  
  40.             this.tempData = [];  
  41.             this.tempData[0] = temp;  
  42.             this.blankRowArray[i].Subject = this.blankRowArray[i].Subject.filter(obj => obj !== selectedSubject)  
  43.             this.blankRowArray[i].SelectedSubject[x].IsChecked = false;  
  44.         }  
  45.     }  
  46. }  
In this method, we can only check a maximum of two values.  If we select a third value, then the first value replaces with the third and so on.   
 
Step 6 
 
Now, open home.component.html file and add the following code in this file.
  1. <div>  
  2.   <button style="margin: 10px;" class="btn btn-primary" (click)="addBlankRow()">Add Blank Row</button>  
  3. </div>  
  4. <div class="col-12 col-md-12">  
  5.   <div class="card">  
  6.     <div class="card-body">  
  7.       <div class="table-responsive cnstr-record">  
  8.         <table class="table table-bordered">  
  9.           <thead>  
  10.             <tr>  
  11.               <th width="30">Roll No</th>  
  12.               <th width="100">Student Name</th>  
  13.               <th width="50">Medium</th>  
  14.               <th width="70">Class</th>  
  15.               <th width="50">Section</th>  
  16.               <th width="80">Books</th>  
  17.               <th width="60">Subject</th>  
  18.               <th width="50">Delete Row</th>  
  19.             </tr>  
  20.           </thead>  
  21.           <tbody>  
  22.             <tr *ngFor="let row of blankRowArray; let i = index">  
  23.               <td>  
  24.                 <input type="text" class="form-control wp-30" [(ngModel)]="blankRowArray[i].RollNo"  
  25.                   [ngModelOptions]="{standalone: true}">  
  26.               </td>  
  27.               <td>  
  28.                 <input type="text" class="form-control wp-30" [(ngModel)]="blankRowArray[i].Name"  
  29.                   [ngModelOptions]="{standalone: true}">  
  30.               </td>  
  31.               <td>  
  32.                 <select [(ngModel)]="blankRowArray[i].Medium" [ngModelOptions]="{standalone: true}"  
  33.                   class="form-control wp-70">  
  34.                   <option [ngValue]="0" disabled selected>--Choose--  
  35.                   </option>  
  36.                   <option [value]="1">Emglish</option>  
  37.                   <option [value]="2">Hindi</option>  
  38.                   <option [value]="2">Marathi</option>  
  39.                 </select>  
  40.               </td>  
  41.               <td>  
  42.                 <select name="crown" [(ngModel)]="blankRowArray[i].Class" (ngModelChange)="setPonticFlagTrue($event,i)"  
  43.                   class="form-control wp-80">  
  44.                   <option [ngValue]="0" disabled selected>--Choose--</option>  
  45.                   <option value="1">Fifth</option>  
  46.                   <option value="2">Sixth</option>  
  47.                   <option value="3">Seventh</option>  
  48.                   <option value="4">Eight</option>  
  49.                   <option value="3">Ninth</option>  
  50.                   <option value="4">Tenth</option>  
  51.                 </select>  
  52.               </td>  
  53.               <td>  
  54.                 <select [(ngModel)]="blankRowArray[i].Section" (ngModelChange)="setPonticType($event,i)"  
  55.                   [ngModelOptions]="{standalone: true}" class="form-control wp-80">  
  56.                   <option [ngValue]="0" disabled selected>--Choose--  
  57.                   </option>  
  58.                   <option value="1">Section A</option>  
  59.                   <option value="2">Section B</option>  
  60.                   <option value="3">Section C</option>  
  61.                   <option value="4">Section D</option>  
  62.                   <option value="5">Section E</option>  
  63.                 </select>  
  64.               </td>  
  65.               <td>  
  66.                 <input class="form-control wp-70" type="text" autocomplete="off" name="{{blankRowArray[i].Books}}"  
  67.                   (click)="openMultiSelectDD(i)" title="{{blankRowArray[i].Books}}"  
  68.                   placeholder="{{blankRowArray[i].Books}}">  
  69.   
  70.                 <div style="width: 329px!important;"  
  71.                   *ngIf="hideMultiSelectDropdown[i]==true && hideMultiSelectDropdownAll[i]==true" class="tooltip">  
  72.                   <div class="body">  
  73.                     <div *ngFor="let bookList of Books;let x =index" class="body">  
  74.                       <input name="bookListName" autocomplete="off" type="checkbox"  
  75.                         [checked]="this.blankRowArray[i].SelectedBooks[x].IsChecked==true"  
  76.                         (change)="booksChecked(bookList, i,x,$event.target.checked)">   
  77.                       <label>{{bookList.value}}</label><br>  
  78.                     </div>  
  79.                   </div>  
  80.                 </div>  
  81.               </td>  
  82.               <td>  
  83.                 <input type="text" autocomplete="off" name="{{blankRowArray[i].Subject}}"  
  84.                   (click)="openMultiSelectDDForSubject(i)" title="{{blankRowArray[i].Subject}}"  
  85.                   placeholder="{{blankRowArray[i].Subject}}" class="form-control wp-70">  
  86.                 <div style="width: 162px!important;"  
  87.                   *ngIf="hideMultiSelectedSubjectDropdown[i]==true && hideMultiSelectedSubjectDropdownAll[i]==true"  
  88.                   #insideElement class="tooltip">  
  89.                   <div class="body">  
  90.                     <div *ngFor="let subjectList of Subject;let x =index" class="body">  
  91.                       <input name="subject" autocomplete="none" type="checkbox"  
  92.                         [checked]="this.blankRowArray[i].SelectedSubject[x].IsChecked==true"  
  93.                         (change)="onSubjectChecked(subjectList, i,x,$event.target.checked)">   
  94.                       <label>{{subjectList.value}}</label><br>  
  95.                     </div>  
  96.                   </div>  
  97.                 </div>  
  98.               </td>  
  99.               <td align="center">  
  100.                 <button (click)="deleteRow(i)" class="btn btn-danger">Delete Row</button>  
  101.               </td>  
  102.             </tr>  
  103.           </tbody>  
  104.         </table>  
  105.       </div>  
  106.     </div>  
  107.   </div>  
  108. </div>  
Step 7 
 
Now, open home.component.css file and add the following code in this file. 
  1. .tooltip {  
  2.     position: absolute;  
  3.     z-index: 3000;  
  4.     border: 1px solid #b7b086;  
  5.     background-color: white;  
  6.     color: #000!important;  
  7.     padding: 5px 15px 5px 10px;  
  8.     opacity: 1;  
  9.     width: 350px;  
  10. }  
Step 8 
 
Now, open app.module.ts file and add the following code in this file.
  1. import { BrowserModule } from '@angular/platform-browser';  
  2. import { NgModule } from '@angular/core';  
  3. import { FormsModule } from '@angular/forms';  
  4. import { AppComponent } from './app.component';  
  5. import { RouterModule } from '@angular/router';  
  6. import { AppRoutingModule } from './app-routing.module';  
  7. import { HomeComponent } from './home/home.component';  
  8. @NgModule({  
  9.   declarations: [  
  10.     AppComponent,  
  11.     HomeComponent,  
  12.   ],  
  13.   imports: [  
  14.     BrowserModule,  
  15.     RouterModule,  
  16.     FormsModule,  
  17.     AppRoutingModule  
  18.   ],  
  19.   providers: [  
  20.   ],  
  21.   bootstrap: [AppComponent]  
  22. })  
  23. export class AppModule { }  
Step 9
 
Now, run the project, by using 'npm start' or 'ng serve' command.
 
Create Dynamic Row With Custom MultiSelect Dropdowns In Angular 8 
Click on Add blank row button and it creates a new row.
 
Create Dynamic Row With Custom MultiSelect Dropdowns In Angular 8
Step 10 
 
Now, click on the subject textbox.
 
Create Dynamic Row With Custom MultiSelect Dropdowns In Angular 8
Step 11
 
Create Dynamic Row With Custom MultiSelect Dropdowns In Angular 8
  

Summary

 
In this article, I discussed how we can create dynamic rows and custom multiselect dropdowns in Angular 8 applications.
 
Please give your valuable feedback/comments/questions about this article.  Please let me know if you liked and understood this article and how I could improve upon it.