Friday, October 4, 2024

Kendo-Grid checkbox selected value update on database - step 1 How to do settings on Child component.

 Dear Reader,

This is a very important topic because developers are often confused about how to manage checkbox checked and unchecked values, and how to update multiple records with one click. First, I will explain how to set up the settings in the child component, which you can then use across multiple components. Here is my Child-Grid

<kendo-grid
  [data]="gridDataResult"
  (dataStateChange)="onDataStateChange($event)"
  (edit)="onEdit($event)"
  [selectable]="{ mode: 'multiple', checkboxOnly: true }"
  kendoGridSelectBy="id"
  [(selectedKeys)]="selectedKeys"
  (selectionChange)="onSelectionChange($event)"
  (selectedKeysChange)="onSelectedKeysChange()"
>
  <ng-template kendoGridToolbarTemplate>
    <button kendoGridAddCommand *ngIf="gridSetting.enableAdd">{{ gridSetting.addCommandTxt }}</button> 
    <button type="button" *ngIf="gridSetting.enableExport" kendoGridExcelCommand>Export to Excel</button> 
    <button kendoButton *ngIf="gridSetting.enableSave" (click)="onUpdateSelected()">Submit Selected Entry</button>
  </ng-template>

  <!-- Move the checkbox column to the first position -->
  <kendo-grid-checkbox-column *ngIf="showCheckbox" [showSelectAll]="true" [width]="50"></kendo-grid-checkbox-column>

  <kendo-grid-command-column
    [title]="gridSetting.commandColTxt"
    [width]="gridSetting.commandColWidth"
    *ngIf="gridSetting.enableEdit || gridSetting.enableRemove || gridSetting.enableDeny"
  >
    <ng-template kendoGridCellTemplate let-dataItem>
      <button kendoGridEditCommand [primary]="true" look="flat" *ngIf="gridSetting.enableEdit">
        <span class="k-icon k-i-edit" [title]="gridSetting.editCommandTxt">{{gridSetting.editCommandTxt}}</span>
      </button>
      <button kendoGridEditCommand [primary]="true" look="flat" *ngIf="gridSetting.enableDeny">
        <span class="k-icon k-i-edit" [title]="gridSetting.denyCommandTxt">{{gridSetting.denyCommandTxt}}</span>
      </button>
      <button
        kendoGridRemoveCommand
        *ngIf="gridSetting.enableRemove && (dataItem[gridSetting.activeFlagField] || gridSetting.activeFlagField === undefined)"
      >
        {{ gridSetting.removeCommandTxt }}
      </button>
    </ng-template>
  </kendo-grid-command-column>

  <kendo-grid-column
    *ngFor="let column of columns"
    [hidden]="column.type === ColumnTypeEnum.Hidden"
    [field]="column.displayField === undefined ? column.field : column.displayField"
    [title]="column.title"
    [format]="column.format"
    [filter]="column.filterType"
    [width]="column.width"
  >
    <ng-template kendoGridCellTemplate let-dataItem let-data *ngIf="column.type === ColumnTypeEnum.Checkbox">
      <input
       [state]="selectAllState"
       kendoGridSelectAllCheckbox
       (selectAllChanges)="onSelectAllChanges($event)"
        type="checkbox"
        kendoCheckBox
        disabled
        [attr.checked]="
          dataItem[column.displayField === undefined ? column.field.toString() : column.displayField.toString()] ? 'checked' : null
        "
      />
    </ng-template>
  </kendo-grid-column>

  <kendo-grid-excel [fileName]="gridSetting.exportFileName"></kendo-grid-excel>
</kendo-grid>


My Ts file 


@Component({
  selector: 'app-shared-common-grid',
  templateUrl: './common-grid.component.html',
  styleUrls: ['./common-grid.component.scss']
})
export class CommonGridComponent extends BaseGridComponent implements OnInit {
 
  @Input() showCheckbox: boolean = true;
  @Input() set gridDataSource$(input$: Observable<GridDataResult>) {
    if (input$) {
      this.gridData$ = input$;
      this.refreshGridData();
    }
  }
  @Input() private saveSuccess: EventEmitter<any>;

  @Output() selectionChange: EventEmitter<SelectionEvent> = new EventEmitter<SelectionEvent>();
  @Output() selectAllChanges: EventEmitter<SelectAllCheckboxState> = new EventEmitter<SelectAllCheckboxState>();
  @Output() selectedKeysChange: EventEmitter<void> = new EventEmitter<void>();
  @Output() loadingStateChange: EventEmitter<boolean> = new EventEmitter<boolean>();
  loading: false;
 
  selectedRecords: Array<any> = [];
  public selectAllState: SelectAllCheckboxState = "unchecked";
  public selectedKeys: Array<number> = [];
  constructor() {
    super();
  }

 
  onSelectionChange(e: SelectionEvent): void {
    this.selectionChange.emit(e);
  }

  onSelectAllChanges(checkedState: SelectAllCheckboxState): void {
    this.selectAllChanges.emit(checkedState);
  }

  onSelectedKeysChange(): void {
    this.selectedKeysChange.emit();
  }

 
}

Now My Parent code is as below :

<app-shared-common-grid
    [columns]="columns"
    [gridLoading]="loading"
    [gridSubmitting]="submitting"
    [gridDataSource$]="gridDataSource$"
    [gridSetting]="gridSetting"
    [saveSuccess]="saveSuccess"
    [showCheckbox]="true"
    (updateSelectedRecords)="onUpdateSelectedRecords($event)"
    (editClicked)="onEditClicked($event)"
    (selectionChange)="handleSelectionChange($event)"
    (selectAllChanges)="handleSelectAllChanges($event)"
    (selectedKeysChange)="handleSelectedKeysChange()"  
  ></app-shared-common-grid>

My Parent TS


@Component({
  selector: 'app-sample-submit-list',
  templateUrl: './submit-list.component.html'
})
export class SubmitListComponent implements OnInit {
  form: FormGroup;
  dropdownLoading = true;
  productControl: FormControl;
  loading = false;
  submitting: boolean;
  columns: ColumnSetting[];
  gridSetting: GridSetting;
  gridDataSource$: Observable<GridDataResult>;
  private gridDataSubject = new BehaviorSubject<GridDataResult>({ data: [], total: 0 });
  saveSuccess: EventEmitter<any> = new EventEmitter();
  hasData$: Observable<boolean>;
  ApproverDataSource$: Observable<Approver[]>;
  selectedKeys: any[] = [];
  selectedRecords: any[] = [];
  public mySelection: number[] = [];
  selectAllState: SelectAllCheckboxState = "unchecked";
  constructor(
  ) {
   
  }
  ngOnInit(): void
  }

  handleSelectionChange(event: SelectionEvent) {
    // Handle selection change event
    console.log('Parent component selection change:', event);
    if (event.selectedRows && event.selectedRows.length > 0) {
      event.selectedRows.forEach(row => {
        if (!this.selectedRecords.some(record => record.id === row.dataItem.id)) {
          this.selectedRecords.push(row.dataItem);
        }
      });
    }

    if (event.deselectedRows && event.deselectedRows.length > 0) {
      const deselectedIds = event.deselectedRows.map(row => row.dataItem.id);
      this.selectedRecords = this.selectedRecords.filter(record => !deselectedIds.includes(record.id));
    }

    this.selectedKeys = this.selectedRecords.map(record => record.id);
  }


  handleSelectAllChanges(checkedState: SelectAllCheckboxState) {
    // Handle select all changes event
    console.log('Parent component select all changes:', checkedState);
    if (checkedState === 'checked') {
      this.gridDataSource$.subscribe(data => {
        this.selectedRecords = data.data.filter(record => record.isChecked);
        this.selectedKeys = this.selectedRecords.map(record => record.id);
      });
    } else {
      this.selectedRecords = [];
      this.selectedKeys = [];
    }
  }

  handleSelectedKeysChange() {
    // Handle selected keys change event
    console.log('Parent component selected keys change');
    const len = this.selectedKeys.length;
    this.gridDataSource$.subscribe(data => {
      const gridDataLength = data.data.length;
      if (len === 0) {
        this.selectAllState = 'unchecked';
      } else if (len > 0 && len < gridDataLength) {
        this.selectAllState = 'indeterminate';
      } else {
        this.selectAllState = 'checked';
      }
    });
  }

  handleLoadingStateChange(isLoading: boolean) {
    // Handle loading state change
    this.loading = isLoading;
  }


  onUpdateSelectedRecords(selectedRecords: any[]): void {
    if (this.selectedKeys.length > 0) {
      this.submitting = true; // Activate the loader
      this.serviceforUpdate.updateRecords(this.selectedKeys).subscribe(
        res => {
          console.log('Selected records updated successfully.');
          this.notifyResult(res);
        },
        error => {
          console.error('Error updating records:', error);
          this.notifyResult({ viewStatus: ViewStatus.Failure, message: 'Error updating records' });
          this.submitting = false;
        }
      );
    } else {
      console.log('No records selected.');
    }
  }

 
}

Here is the full code. I hope it helps you. Thank you, Guru (Mr. Surendra), for explaining all the concepts.