primefaces / primereact

The Most Complete React UI Component Library
https://primereact.org
MIT License
6.86k stars 1.04k forks source link

FileUpload: Set Badges to error in customUpload if file is not valid due to custom validation #7054

Open ismailmemis opened 2 months ago

ismailmemis commented 2 months ago

Describe the bug

During the custom upload, I first upload two files and check their names according to certain conventions. These files do not pass the test and their badge remains on “Pending”.

If I now upload a correct file, the two invalid files are removed from the upload field and only the valid file remains, whose badge is set to “Completed”.

However, the desired behavior is as follows:

Is there a way to implement this behavior?

Reproducer

https://stackblitz.com/edit/stackblitz-starters-3u6avq?file=src%2FApp.tsx

System Information

System: OS: Windows 11 10.0.22621 CPU: (12) x64 13th Gen Intel(R) Core(TM) i7-1355U Memory: 16.85 GB / 31.69 GB Binaries: Node: 21.6.1 - C:\Program Files\nodejs\node.EXE Yarn: 1.22.22 - ~\AppData\Roaming\npm\yarn.CMD npm: 10.5.1 - C:\Program Files\nodejs\npm.CMD Browsers: Edge: Chromium (127.0.2651.74) Internet Explorer: 11.0.22621.3527 npmPackages: primereact: ^10.7.0 => 10.7.0 react: ^18.2.0 => 18.3.1

Steps to reproduce the behavior

  1. choose one .png and one .jpg file
  2. click on upload

Expected behavior

the .jpg files badge needs to get to error.

sja-cslab commented 2 months ago

tl:dr Use setUploadedFiles and setFiles methods of FileUpload with custom template rendering. (itemTemplate: ReactNode | (file: object, options: ItemTemplateOptions) => React.ReactNode)

You could use ref.current.setUploadedFiles([]); and fileUpload.current.setFiles([]); fot that. It depends on what, where and when you try to check your files.

One way of doing it would e.g. upload the files (backend checks those files) and if successfully, set a "setCheckedFiles: string[]" to know what files have been checked - if all is fine just put them back to fileUpload.current.setFiles(checkedFiles) and render the required tag based on the checkedFiles state

ismailmemis commented 2 months ago

Thanks for your answer, it worked. I now use two arrays: one for successful files and one for unsuccessful ones. I set them like this:

fileuploadref.current.setUploadedFiles(correctFiles); fileuploadref.current.setFiles(errorFiles); The errorFiles and correctFiles lists do not overlap. I go through the errorFiles and set the badges in the DOM to “Error” and color them red.

Now I have a problem:

onRemove={(event) => handleRemoveClick(event)}

I do the following in handleRemoveClick:

const handleRemoveClick = (event: FileUploadRemoveEvent) => { console.log(event.file); } event.file is undefined if the file was added with fileUploadRef.current.setUploadedFiles(file). But it is defined if it was added with fileUploadRef.current.setFiles(file).

Therefore, I cannot delete a file that is contained in uploadedFiles. Is there a solution or an extension option for this?

sja-cslab commented 1 month ago

@melloware guess this can get Workaround tag.

@ismailmemis I use custom Button for that and just call fileUploadRef.current.setUploadedFiles([])

melloware commented 1 month ago

Done!

ismailmemis commented 1 month ago

@melloware @sja-cslab

I've reviewed the FileUpload component code on GitHub and noticed the following:

`const removeUploadedFiles = (event, index) => { clearInput(); let currentUploadedFiles = [...uploadedFilesState]; let removedFile = filesState[index];

currentUploadedFiles.splice(index, 1);
setUploadedFilesState(currentUploadedFiles);

if (props.onRemove) {
    props.onRemove({
        originalEvent: event,
        file: removedFile
    });
}

};`

It seems like there's an issue with how you're retrieving the file to be removed. You're using filesState[index], which represents files that have not yet been uploaded, to get the file that the user wants to remove.

Since the index might not correspond to an item in filesState after the file has been uploaded, this could be why removedFile is returning undefined. Instead, you should retrieve the file from uploadedFilesState, which is the array containing the files that have already been uploaded.