I’m working with Angular 16. I have a custom UploadComponent inside a ModalComponent, that has a issue after I choose a file from my PC. When I have to insert a new element, the component works fine. But, when I’m in edit mode, the file name of the file selected is not shown in html.
This is my UploadComponent.
export class UploadFileComponent implements OnInit, OnChanges {
/** the selected file */
selectedFile: File | null = null;
/** the file confirmed */
fileConfirmed: boolean = false;
/** The show view default flag */
public showDefaultView: boolean = true;
/** allegato */
@Input() allegato?: Allegato;
/** Emit the file to the parent component */
@Output() fileSelected = new EventEmitter<File>();
constructor(private changeDetector: ChangeDetectorRef,
private allegatiService: AllegatiService
) {}
/**
* ngOnInit
*/
public ngOnInit(): void {
this.loadViews();
}
/**
* ngOnChanges
* @param changes
*/
public ngOnChanges(changes: SimpleChanges): void {}
/**
* Handle the file selection
* @param event the file
*/
public onFileSelected(event: any) {
const file: File = event.target.files[0];
const allowedMimeTypes = ['image/png', 'image/jpeg', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
if (file) {
if (!allowedMimeTypes.includes(file.type)) {
alert('Tipo file non valido. Sono permessi solo PNG, JPEG, PDF, and DOC/DOCX.');
this.selectedFile = null;
this.changeDetector.detectChanges();
return;
}
this.selectedFile = file;
this.fileConfirmed = false;
this.fileSelected.emit(this.selectedFile);
this.changeDetector.detectChanges();
}
}
/**
* Handle remove file
*/
public removeFile() {
this.selectedFile = null;
this.fileConfirmed = false;
this.fileSelected.emit(undefined);
this.changeDetector.detectChanges();
}
/**
* "Carica" button confirms the file and emits it to the parent
* @returns
*/
public onUpload() {
if (!this.selectedFile) {
return;
}
this.fileConfirmed = true;
this.fileSelected.emit(this.selectedFile);
this.changeDetector.detectChanges();
}
/**
* Handle the reset of the component
*/
public reset() {
this.selectedFile = null;
this.fileConfirmed = false;
this.fileSelected.emit(undefined);
this.changeDetector.detectChanges();
}
}
UploadComponent Html
<div class="upload-container">
<div class="row align-items-center g-1">
<ng-container *ngIf="showDefaultView else downloadView">
<ng-container *ngIf="!fileConfirmed">
<div class="col-auto">
<label for="fileInput" class="btn btn-xs btn-primary btn-file">
<i class="bi bi-upload"></i> {{ "upload.button.sceglifile" | translate }}
<input type="file" id="fileInput" (change)="onFileSelected($event)" hidden />
</label>
</div>
<div class="col">
<input type="text" [value]="selectedFile ? selectedFile.name : 'Nessun file selezionato'" readonly
class="form-control file-name-input" />
</div>
<div class="col-auto">
<button type="button" (click)="onUpload()" class="btn btn-xs btn-primary" [disabled]="!selectedFile">
{{ "upload.button.carica" | translate }}
</button>
</div>
</ng-container>
<ng-container *ngIf="fileConfirmed">
<div class="col-9">
<input type="text" [value]="selectedFile?.name || allegato?.nomeFile" readonly
class="form-control file-name-input" style="flex: 1;" />
</div>
<div class="col-3">
<button type="button" class="btn btn-danger btn-xs" (click)="removeFile()">
<i class="bi bi-trash"></i>
</button>
</div>
</ng-container>
</ng-container>
</div>
</div>
<ng-template #downloadView>
<div *ngIf="allegato" style="flex: 1;">
<!-- File download link -->
<a href="#" (click)="downloadAttachment(allegato.id)" download class="d-flex link-opacity-75-hover">
<i class="bi bi-file-earmark me-2"></i>
<span>{{ allegato!.nomeFile }}</span>
</a>
</div>
</ng-template>
This UploadComponent is a child component of the ModalComponent:
ModalComponent TS:
ngOnInit() {
this.initComponent();
}
/**
* The after view init method.
*/
ngAfterViewInit() {
this.modalDiscussione.nativeElement.addEventListener("show.bs.modal", this.initComponent);
this.modalDiscussione.nativeElement.addEventListener("shown.bs.modal", this.onModalShown);
this.modalDiscussione.nativeElement.addEventListener("hide.bs.modal", this.dismissModal);
// Prevent Bootstrap dialog from blocking focusin
document.addEventListener('focusin', (e) => {
if (e.target instanceof HTMLElement &&
e.target.closest(".tox-tinymce-aux, .moxman-window, .tam-assetmanager-root") !== null
) {
e.stopImmediatePropagation();
}
});
}
// Handle file selection from the child component
onFileSelected(file: File | null) {
console.log('File selected in parent:', file);
this.selectedFile = file;
}
/**
* Metodo di inizializzazione del componente.
*/
private initComponent = () => {
this.saved = false;
this.serverError = undefined;
this.onClose = undefined;
this.onConfirm = undefined;
this.temiDiscussione = this.discussione.temiDiscussione;
this.aree = this.discussione.aree;
this.categorie = this.discussione.categorie;
this.form = this.fb.group({
tema: [this.discussione.infoTema?.id, Validators.required],
area: [{value: this.discussione.categoria?.area?.id, disabled: !this.aree.length}, Validators.required],
categoria: [{value: this.discussione.categoria?.id, disabled: !this.aree.length}, Validators.required],
evidenza: this.discussione.flagEvidenza,
titolo: [this.discussione.titolo, Validators.required],
descrizione: [this.discussione.descrizione, Validators.required]
});
}
/**
* The on modal shown method.
* @private
*/
private onModalShown = () => {
if (this.isNew && this.discussione.infoTema) {
this.uploadFileComponent.reset();
this.onChangeTema();
} else {
if (this.discussione.allegato) {
this.uploadFileComponent.allegato = this.discussione.allegato;
this.uploadFileComponent.fileConfirmed = true;
this.cd.detectChanges();
}
}
}
When I choose the file I call onFileSelected($event), either for the new insertion or the editing.
I try to log the selectedFile and it seems to be valued in the function and in the parent component, but the html doesn’t change.
I try to use change detector to force the update but it still doesn’t work.
It should behave in the same way as when I open modal for insertion.
UPDATE:
I try to bypass onUpload() function, now the fileName shows up at the second time I choose the file, so the second time that i call onFileSelected();
user27365092 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
i suggest that you replace detectChanges() with markForCheck() in the UploadFileComponent and ensure the change detection triggers in onModalShown
i updated your code here:
ngOnChanges(changes: SimpleChanges): void {
if (changes['allegato'] && this.allegato) {
// uupdate on edit
this.fileConfirmed = true;
this.selectedFile = null; // reset file selection
this.changeDetector.markForCheck(); // Ensure change detection here !!!
}
}
also call this.changeDetector.markForCheck(); in othor method related to file upload
you need to ensure that you correctly trigger change detection in the onModalShown method
private onModalShown = () => {
if (this.isNew && this.discussione.infoTema) {
this.uploadFileComponent.reset();
this.onChangeTema();
} else {
if (this.discussione.allegato) {
this.uploadFileComponent.allegato = this.discussione.allegato;
this.uploadFileComponent.fileConfirmed = true;
this.cd.markForCheck(); //here you trigger detection in edit mode
}
}
}
1