Description
Import sub-step: Let user load a file and return parsed data.
Example
Methods
|
onFileLoad
|
onFileLoad(parsedData: ParsedData<any>)
|
|
|
Handle a freshly parsed file emitted by the parsed-file-input child.
Pre-selects the column-separator dropdown to the auto-detected
delimiter (which may be outside the defaults — the dropdown will
include it automatically via separatorOptions). Falls back to
comma only when nothing was detected.
|
|
onSeparatorChange
|
onSeparatorChange(value: string | undefined)
|
|
|
Handle a user-driven change of the column-separator dropdown:
remember the choice and ask the parsed-file-input to re-parse the cached
file content with the new delimiter (which will re-emit dataLoaded).
Parameters :
| Name |
Type |
Optional |
| value |
string | undefined
|
No
|
|
|
onTrimValuesChange
|
onTrimValuesChange(value: boolean)
|
|
|
Parameters :
| Name |
Type |
Optional |
| value |
boolean
|
No
|
|
|
createCustomSeparator
|
Type : unknown
|
Default value : () => {...}
|
|
|
|
Readonly
multiValueSeparatorOptions
|
Type : string[]
|
Default value : [",", ";"]
|
|
|
|
Readonly
selectedDelimiter
|
Type : unknown
|
Default value : signal<string | undefined>(undefined)
|
|
|
|
Readonly
separatorOptions
|
Type : unknown
|
Default value : computed<string[]>(() => {
const detected = this.selectedDelimiter();
if (detected && !this.defaultSeparatorOptions.includes(detected)) {
return [...this.defaultSeparatorOptions, detected];
}
return this.defaultSeparatorOptions;
})
|
|
|
Dropdown options: the project-supported defaults plus the
auto-detected delimiter if PapaParse picked something outside the
defaults (e.g. tab, ASCII control chars). This keeps the dropdown
in sync with the actual delimiter used to parse the file, so the
user always sees and can override the real value.
|
|
Readonly
trimValues
|
Type : unknown
|
Default value : computed(
() => this.additionalSettings()?.trimValues !== false,
)
|
|
|
Accessors
|
multiValueSeparator
|
getmultiValueSeparator()
|
|
|
setmultiValueSeparator(value: string)
|
|
|
Parameters :
| Name |
Type |
Optional |
| value |
string
|
No
|
|
import {
Component,
EventEmitter,
Output,
ViewChild,
ChangeDetectionStrategy,
signal,
computed,
input,
model,
} from "@angular/core";
import {
ParsedFileInputComponent,
ParsedData,
} from "../../common-components/parsed-file-input/parsed-file-input.component";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatExpansionModule } from "@angular/material/expansion";
import { MatCheckboxModule } from "@angular/material/checkbox";
import { FormsModule } from "@angular/forms";
import { HelpButtonComponent } from "../../common-components/help-button/help-button.component";
import { BasicAutocompleteComponent } from "../../common-components/basic-autocomplete/basic-autocomplete.component";
import { ImportAdditionalSettings } from "../import-additional-settings";
/**
* Import sub-step: Let user load a file and return parsed data.
*/
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "app-import-file",
templateUrl: "./import-file.component.html",
styleUrls: ["./import-file.component.scss"],
imports: [
ParsedFileInputComponent,
MatFormFieldModule,
MatExpansionModule,
MatCheckboxModule,
FormsModule,
HelpButtonComponent,
BasicAutocompleteComponent,
],
})
export class ImportFileComponent {
entityType = input<string>();
additionalSettings = model<ImportAdditionalSettings>({});
@Output() dataLoaded = new EventEmitter<ParsedData<any>>();
data: ParsedData<any>;
readonly selectedDelimiter = signal<string | undefined>(undefined);
private readonly defaultSeparatorOptions: string[] = [",", ";", "|"];
/**
* Dropdown options: the project-supported defaults plus the
* auto-detected delimiter if PapaParse picked something outside the
* defaults (e.g. tab, ASCII control chars). This keeps the dropdown
* in sync with the actual delimiter used to parse the file, so the
* user always sees and can override the real value.
*/
readonly separatorOptions = computed<string[]>(() => {
const detected = this.selectedDelimiter();
if (detected && !this.defaultSeparatorOptions.includes(detected)) {
return [...this.defaultSeparatorOptions, detected];
}
return this.defaultSeparatorOptions;
});
@ViewChild(ParsedFileInputComponent)
parsedFileInputField: ParsedFileInputComponent;
readonly multiValueSeparatorOptions: string[] = [",", ";"];
get multiValueSeparator(): string {
return this.additionalSettings()?.multiValueSeparator ?? ",";
}
set multiValueSeparator(value: string) {
this.additionalSettings.update((settings) => ({
...settings,
multiValueSeparator: value,
}));
}
readonly trimValues = computed(
() => this.additionalSettings()?.trimValues !== false,
);
onTrimValuesChange(value: boolean) {
this.additionalSettings.update((settings) => ({
...settings,
trimValues: value,
}));
}
createCustomSeparator = async (input: string) => input;
/**
* Handle a freshly parsed file emitted by the parsed-file-input child.
* Pre-selects the column-separator dropdown to the auto-detected
* delimiter (which may be outside the defaults — the dropdown will
* include it automatically via `separatorOptions`). Falls back to
* comma only when nothing was detected.
*/
onFileLoad(parsedData: ParsedData<any>) {
this.data = parsedData;
this.selectedDelimiter.set(parsedData.detectedDelimiter || ",");
this.dataLoaded.emit(parsedData);
}
/**
* Handle a user-driven change of the column-separator dropdown:
* remember the choice and ask the parsed-file-input to re-parse the cached
* file content with the new delimiter (which will re-emit `dataLoaded`).
*/
onSeparatorChange(value: string | undefined) {
if (!value || value === this.selectedDelimiter()) {
return;
}
this.selectedDelimiter.set(value);
this.parsedFileInputField?.reparseWithDelimiter(value);
}
public reset() {
delete this.data;
this.selectedDelimiter.set(undefined);
this.parsedFileInputField.formControl.reset();
}
}
<p i18n>Select a .xlsx or .csv file with data to import:</p>
<app-parsed-file-input
(fileLoad)="onFileLoad($event)"
[fileType]="['csv', 'xlsx']"
></app-parsed-file-input>
@if (data) {
<div i18n>{{ data.data?.length }} rows detected for import</div>
<mat-expansion-panel class="advanced-options-panel">
<mat-expansion-panel-header>
<mat-panel-title i18n="CSV advanced options panel title"
>Advanced Options</mat-panel-title
>
</mat-expansion-panel-header>
<div class="settings-row flex-row align-center gap-small">
<mat-form-field>
<mat-label i18n="CSV column separator label"
>Column separator</mat-label
>
<app-basic-autocomplete
[ngModel]="selectedDelimiter()"
(ngModelChange)="onSeparatorChange($event)"
[options]="separatorOptions()"
></app-basic-autocomplete>
</mat-form-field>
<app-help-button
text="The character that separates columns in your CSV file.
It is auto-detected from your file - only change this if the columns appear incorrect after import."
i18n-text="CSV column separator - help text"
></app-help-button>
</div>
<div class="settings-row flex-row align-center gap-small">
<mat-form-field>
<mat-label i18n>Multi-value separator</mat-label>
<app-basic-autocomplete
[(ngModel)]="multiValueSeparator"
[options]="multiValueSeparatorOptions"
[createOption]="createCustomSeparator"
></app-basic-autocomplete>
</mat-form-field>
<app-help-button
text="Which character is used to separate multiple values in a single column cell for array-type fields (e.g., multi-select options)."
i18n-text="import - multi-value separator - help text"
></app-help-button>
</div>
<div class="settings-row flex-row align-center gap-small">
<mat-checkbox
[ngModel]="trimValues()"
(ngModelChange)="onTrimValuesChange($event)"
i18n
>
Trim leading/trailing spaces from values
</mat-checkbox>
<app-help-button
text="Automatically remove leading and trailing spaces from all text values during import."
i18n-text="import - trim values - help text"
></app-help-button>
</div>
</mat-expansion-panel>
}
.advanced-options-panel {
margin-top: 1rem;
}
.settings-row {
margin-bottom: 0.5rem;
}
Legend
Html element with directive