diff --git a/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-design/payloads-table/payloads-table.component.html b/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-design/payloads-table/payloads-table.component.html index 73af470757..a43b3f9611 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-design/payloads-table/payloads-table.component.html +++ b/frontend/projects/upgrade/src/app/features/dashboard/home/components/experiment-design/payloads-table/payloads-table.component.html @@ -62,6 +62,7 @@ required [matAutocomplete]="payloadRowAutoCompleteConditionCodes" (keyup)="handleFilterContextMetaDataConditions(rowData.payload, $event)" + appTrimInput /> diff --git a/frontend/projects/upgrade/src/app/features/dashboard/home/components/factorial-experiment-design/factorial-experiment-design.component.html b/frontend/projects/upgrade/src/app/features/dashboard/home/components/factorial-experiment-design/factorial-experiment-design.component.html index 8d08a6cca6..792cdb7a56 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/home/components/factorial-experiment-design/factorial-experiment-design.component.html +++ b/frontend/projects/upgrade/src/app/features/dashboard/home/components/factorial-experiment-design/factorial-experiment-design.component.html @@ -539,6 +539,7 @@ formControlName="value" [value]="payload?.value" autocomplete="off" + appTrimInput /> diff --git a/frontend/projects/upgrade/src/app/shared/directives/trim-input.directive.ts b/frontend/projects/upgrade/src/app/shared/directives/trim-input.directive.ts new file mode 100644 index 0000000000..c0ee3b8d99 --- /dev/null +++ b/frontend/projects/upgrade/src/app/shared/directives/trim-input.directive.ts @@ -0,0 +1,37 @@ +import { Directive, ElementRef, HostListener } from '@angular/core'; +import { NgControl } from '@angular/forms'; + +/** + * TrimInputDirective automatically trims leading and trailing whitespace + * from form control values when the user finishes editing (on blur). + * + * Usage: + * + * + * This directive will: + * - Trim whitespace on blur (when user finishes editing) + * - Update both the DOM element and the form control + * - Work with any input that has a form control + */ +@Directive({ + selector: '[appTrimInput]', + standalone: false, +}) +export class TrimInputDirective { + constructor(private el: ElementRef, private control: NgControl) {} + + @HostListener('blur') onBlur() { + const value = this.el.nativeElement.value; + if (typeof value === 'string') { + const trimmedValue = value.trim(); + + // Only update if the value actually changed after trimming + if (trimmedValue !== value) { + this.el.nativeElement.value = trimmedValue; + if (this.control?.control) { + this.control.control.setValue(trimmedValue, { emitEvent: false }); + } + } + } + } +} diff --git a/frontend/projects/upgrade/src/app/shared/shared.module.ts b/frontend/projects/upgrade/src/app/shared/shared.module.ts index ae72779a8f..4fc23947d9 100755 --- a/frontend/projects/upgrade/src/app/shared/shared.module.ts +++ b/frontend/projects/upgrade/src/app/shared/shared.module.ts @@ -34,6 +34,7 @@ import { TruncatePipe } from './pipes/truncate.pipe'; import { ExperimentStatePipe } from './pipes/experiment-state.pipe'; import { FormatDatePipe } from './pipes/format-date.pipe'; import { ScrollDirective } from './directives/scroll.directive'; +import { TrimInputDirective } from './directives/trim-input.directive'; import { OperationPipe } from './pipes/operation.pipe'; import { SegmentStatusPipe } from './pipes/segment-status.pipe'; import { QueryResultComponent } from './components/query-result/query-result.component'; @@ -76,6 +77,7 @@ import { MatConfirmDialogComponent } from './components/mat-confirm-dialog/mat-c TruncatePipe, ExperimentStatePipe, ScrollDirective, + TrimInputDirective, FormatDatePipe, OperationPipe, QueryResultComponent, @@ -118,6 +120,7 @@ import { MatConfirmDialogComponent } from './components/mat-confirm-dialog/mat-c ExperimentStatePipe, FormatDatePipe, ScrollDirective, + TrimInputDirective, OperationPipe, QueryResultComponent, DeleteComponent,