'How to prevent pushing dynamic rows with duplicate values in Angular

I am pushing dynamic row on click of add new button.

I wanted to display validation to stop pushing row if previous row has same value.

For ex - i have 5 fields namely productType, process Technology,subfamilyId,Package Lines and batchSize.On click of add button i m pushing new empty rows,But i want to apply one validation on Add New button click.

Validation will check below condition

Suppose if i select below values in Row 1 productType - Red processTechnology - Red subfamilyId - Red PackageLines - Red batchSize - 2.5

And Again i select below values in Row 2,

productType - Red processTechnology - Red subfamilyId - Red PackageLines - Red batchSize - 2.5

But In above case, Row2 value is similar to Row 1, Then it will throw error on Add new button click.

On every Add New Button click, New object will be added in below array

this.items.value = [
    {productType: 'Laundry', processTechType: 'Continuous', subfamilyId: Array(1), lineId: Array(1), batchSize: 'NA'}
 {productType: 'Water Purification', processTechType: 'Batch', subfamilyId: Array(1), lineId: Array(1), batchSize: '34'}
];

Can anyone help me to do this logic, Below is my code

Component code

makeLineForm: FormGroup;  
  constructor(private fb: FormBuilder) {
    this.makeLineForm = this.fb.group({
      clusterId: ['', Validators.required],
      makeLineProcessList: this.fb.array([this.createItem(null)]),
    });
  }
  createItem(data) {
    const formgrp = this.fb.group({
      productType: ['', Validators.required],
      processTechType: ['', Validators.required],
      subfamilyId: ['', Validators.required],
      lineId: ['', Validators.required],
      batchSize: ['']
    });
    if (data) {
      formgrp.patchValue(data);
    }
    return formgrp;
  }
  addItem(item) {
    this.items.push(item);
  }
  get items() {
    return this.makeLineForm.get('makeLineProcessList') as FormArray;
  }
  addNewType() {    
    this.addItem(this.createItem(null));
  }


<div class="master-data-main-wrapper">
  
    <div class="content-wrapper">
        <form [formGroup]="makeLineForm">        
            <div class="row">                
                <div class="col-md-4">
                    <mat-label>Vendor</mat-label>
                    <input matInput class="mkline-input"
                        [class.inValidClass]="makeLineForm?.controls?.makeVendor?.invalid" placeholder="Vendor"
                        formControlName="makeVendor">
                </div>
            </div>

            <form [formGroup]="items" class="items">
                <div class="row dl-body" *ngFor="let subitem of items.controls; let i = index" [formGroupName]="i">
                    <div class="col-xs-12 col-sm-6 col-md-2 pl-4">
                        <mat-label>Product Type</mat-label>
                        <mat-select class="mkline-input" formControlName="productType"
                            [class.inValidClass]="subitem?.controls?.productType?.invalid">
                            <mat-option *ngFor="let prod of productTypes" [value]="prod.category">
                                {{prod.category}}
                            </mat-option>
                        </mat-select>
                    </div>
                    <div class="col-xs-12 col-sm-6 col-md-2">
                        <mat-label>Process Technology</mat-label>
                        <mat-select (selectionChange)="validateBatchSize($event,i)" class="mkline-input"
                            formControlName="processTechType"
                            [class.inValidClass]="subitem?.controls?.processTechType?.invalid">
                            <mat-option *ngFor="let type of types" [value]="type"> {{type}}
                            </mat-option>
                        </mat-select>
                    </div>
                    <div class="col-xs-12 col-sm-6 col-md-2">
                        <mat-label>Sub-Family Make</mat-label>
                        <mat-select class="mkline-input" formControlName="subfamilyId"
                            [class.inValidClass]="subitem?.controls?.subfamilyId?.invalid" multiple>
                            <mat-option *ngFor="let subfamily of subfamlies | async" [value]="subfamily"> {{subfamily}}
                            </mat-option>
                        </mat-select>
                    </div>
                    <div class="col-xs-12 col-sm-6 col-md-2">
                        <mat-label>Package Lines</mat-label>
                        <mat-select class="mkline-input" formControlName="lineId"
                            [class.inValidClass]="subitem?.controls?.lineId?.invalid" multiple>
                            <mat-option *ngFor="let line of lines | async" [value]="line.lineId"> {{line.name}}
                            </mat-option>
                        </mat-select>
                    </div>
                    <div class="col-xs-12 col-sm-6 col-md-2">
                        <mat-label>Batch Size (Ton)</mat-label>
                        <input matInput type="text" (keypress)="validateBatchSizeForDecimal($event)"
                            [readonly]="batchReadOnly" [class.inValidClass]="subitem?.controls?.batchSize?.invalid"
                            class="mkline-input" formControlName="batchSize">
                    </div>
                    <div class="col-xs-12 col-sm-6 col-md-2 aligctr">
                        <button mat-stroked-button (click)="addNewType()" class="add-button default-button"
                            *ngIf="(items.controls.length-1) === i">
                            <mat-icon class="material-icons-outlined">
                                add_circle_outline
                            </mat-icon> Add New
                        </button>
                    </div>
                </div>
            </form>
        </form>
    </div>
</div>


Solution 1:[1]

Use JSON.stringify to check if the objects are the same:

addNewType() {   
    // newRow -> new item (as object) to add
    // check if newRow values are already in items array:
    if (this.items.some(item =>
    JSON.stringify(item) === JSON.stringify(newRow) ) {
        console.log("error!"); // do your intended validation thing
    } 
    else {
         this.addItem(this.createItem(null));
    }       
}

However, I don't see how you get the values for the new item once you click the button? So newRow is just there as a placeholder.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1