I wrapped an ngx-datatable component in a form
tag so I can validate inputs
in the table cells. Due to the nature of how the table is populated I set the inputs name
properties dynamically
<form #tableForm="ngForm">
<ngx-datatable
[rows]="_rows">
<ng-container *ngFor="let column of rowDeffinition; let columnIndex=index">
<ngx-datatable-column [prop]="column.key" [name]="column.label">
<ng-template ngx-datatable-cell-template let-rowIndex="rowIndex" let-value="value" let-row="row">
<input
(blur)="updateCellValue($event, column.key, rowIndex)"
type="text"
[ngModel]="value"
[name]="rowIndex '-' column.key"
/>
...
</ng-template>
</ngx-datatable-column>
</ng-container>
</ngx-datatable>
</form>
Normally, the name
property would creates a local variable in the template and you can access the inputs control properties via the variable name.
<input type="text" name="name" [(ngModel)]="name" required minlength="4" />
<div *ngIf="name.invalid && name.touched">
I wonder how can I do this dynamically in the same manner I set the inputs name. So far I was able to access the input controls via the form reference but this becomes quite wordy
<span *ngIf="!tableForm.controls[rowIndex '-' column.key]?.valid &&
!tableForm.controls[rowIndex '-' column.key]?.pristine"
>
required
</span>
CodePudding user response:
You can wrap your input in new component and you can access these generated components via @ViewChildren(...)
in parent components .ts
file:
@ViewChildren(NgxDatatableInput) datatableInputs: QueryList<NgxDatatableInput>;
I recommend to create method in parent component, which retrieves concrete datatableInput from datatableInputs
by name
as parameter. After that you can use this method in generated, new ValidationSpanComponent
:
<ValidationSpan [control]="getDatatableInput(dynamicName)">
</ValidationSpan>
Template of ValidationSpanComponent
:
<span *ngIf="!control.valid &&
!control.pristine"
>
required
</span>
CodePudding user response:
Inspired by this answer I came up with following solution
<form #tableForm="ngForm">
<ngx-datatable
[rows]="_rows">
<ng-container *ngFor="let column of rowDeffinition; let columnIndex=index">
<ngx-datatable-column [prop]="column.key" [name]="column.label">
<ng-template ngx-datatable-cell-template let-rowIndex="rowIndex" let-value="value" let-row="row">
<!-- Helper template allowing to define few variables for more readable property binding-->
<ng-template #cellContent [ngTemplateOutlet]="cellContent"
let-cellName="cellName" let-isValidInput="isValidInput" let-isPristineInput="isPristineInput"
let-isRequiredInput="isRequiredInput"
[ngTemplateOutletContext]="{
cellName: rowIndex '-' column.key,
isValidInput: tableForm.controls[rowIndex '-' column.key]?.valid,
isPristineInput: tableForm.controls[rowIndex '-' column.key]?.pristine,
isRequiredInput: column.input?.required
}">
<input
(blur)="updateCellValue($event, column.key, rowIndex)"
type="text"
[ngModel]="value"
[name]="cellname"
/>
...
</ng-template>
</ng-template>
</ngx-datatable-column>
</ng-container>
</ngx-datatable>
</form>
This improves the general readability vastly, since my table has a very complex logic, and i track the state of the cell in a structure like:
interface EditTableRowStatus {
editing: { [coolumnId: string]: boolean},
changed: { [coolumnId: string]: boolean},
addedRow: boolean;
}
let rowsStates = EditTableRowStatus[]
which led to super complex property binding in the template
<input
*ngIf="column.input?.type === INPUT_TYPES.TEXT && (rowsStates[rowIndex]?.editing?.[column.key] || rowsStates[rowIndex]?.addedRow)"
[autofocus]="!rowsStates[rowIndex]?.addedRow || columnIndex === 0 "
(blur)="updateCellValue($event, column.key, rowIndex)"
type="text"
[ngModel]="value"
[ngClass]="{'has-changes': rowsStates[rowIndex]?.changed?.[column.key]}"
[name]="rowIndex '-' column.key"
[required]="column.input?.required"
/>
now becoming much more readable
<input
*ngIf="inputType === INPUT_TYPES.TEXT && (isEditing || isAddedRow)"
[autofocus]="!isAddedRow || columnIndex === 0 "
(blur)="updateCellValue($event, column.key, rowIndex)"
type="text"
[ngModel]="value"
[ngClass]="{'has-changes': isChanged}"
[name]="cellName"
[required]="isRequiredInput"
/>