I have a div which contains one or more inputs files according to a list. This is generated with ngFor. I remove or add element of the list with two buttons and of course it updates the HTML.
Here is the html:
<form name="form" (ngSubmit)="f.form.valid" #f="ngForm" novalidate>
<div *ngFor="let dataset of datasetList; let index = index">
<div id="datasetFiles">
<h6>Browse the files:</h6>
<div class="container">
<div class="row justify-content-between">
<div class="col-6 d-flex align-items-center">
<input id="file" #file (change)="onChange(file.files, index, $event.currentTarget)" type="file">
</div>
<div class="col-2 d-flex align-items-center">
<button mat-icon-button color="warn (click)="removeDataset(index)">
<mat-icon>delete</mat-icon>
</button>
</div>
</div>
</div>
<div *ngIf="typeDataset.invalid && (typeDataset.dirty || typeDataset.touched)" class="alert alert-danger">
Dataset type is required
</div>
<div *ngIf="!fileValid" class="alert alert-danger">
Dataset file required
</div>
</div>
</div>
<div>
<button mat-icon-button color="primary" (click)="addDataset()">
<mat-icon>add_box</mat-icon>
</button>
</div>
<button mat-button color="primary" type="submit" [disabled]="!f.form.valid && !fileValid" (click)="createExperiment()">Submit</button>
</form>
Then in my component:
onChange(files: FileList, index: number, dom: any) {
this.fileValid = false;
// Option to parse the file with papaparse
let options = {
error: (err, file) => {
alert(
"Unable to parse CSV file, please verify the file can be accessed and try again. Error reason was: " +
err.code
);
return;
},
complete: (results, file) => {
console.log("Parsed:", results, file);
let filename = file.name;
// Add the dataset to the datasetList
this.datasetList[index].values = results.data;
this.fileValid = true;
this.cd.detectChanges();
}
};
this.fileSelected = files[0]; // Get the file
// Call the function to parse the file, option is the callback
this.papa.parse(this.fileSelected, options);
}
// Add a dataset form
addDataset() {
this.datasetList.push({});
}
// Remove a dataset form
removeDataset(index: number) {
this.datasetList.splice(index, 1);
}
This works properly. I use papaparse to read the file and add it to the datasetList. However, my problem was that I was not able to add "required" to the input file. But with what I have read, it seems that it does not exist.
Therefore, I add a variable "fileValid" to check if the file is properly selected or not. This variable is initialised to false and changed to true if the file is properly parsed. Then, if the user adds a file this variable changes to false. However, I don't know how to manage when a user deletes a div. For example:
How could I manage it ? Or Is there another way ?
Instead of trying to manage an entire list's validaty with only a single local boolean, you should consider increasing the dimension of your local boolean by turning it into an array of booleans. In this array, each index would represent the file validaty of the associated dataset at position index in datasetList.
Change:
fileValid: boolean = false;
to:
fileValid: Array<boolean> = [false]; // ideally the length of this would be equal to datasetList, but you should be able to get away by not bothering to initialize to that end.
Then in your onChange method:
this.fileValid[index] = false; // since you already conveniently have the index
or
this.fileValid[index] = true;
and in your template for the [disabled] part, you can have something like "! isFileValid()"
where in your component it would be:
isFileValid(): boolean {
return this.fileValid.indexOf(false) == -1
}
Hope it helps.