This is a migrated thread and some comments may be shown as answers.

KendoReact Upload

7 Answers 1166 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
David
Top achievements
Rank 1
Iron
Iron
Veteran
David asked on 16 Dec 2020, 02:05 AM

Hi,

The KendoReact Upload component seems to only cater for sending files to dedicated server handlers. Is there any way to convert attached files to a byte array rather than posting to a server endpoint?

Kind regards,

David

7 Answers, 1 is accepted

Sort by
0
Stefan
Telerik team
answered on 16 Dec 2020, 06:04 AM

Hello, David,

The saveUrl can accept a function instead of a direct link.

This will allow the developer to get access to the files and use them as required, including transferring them to byte arrays:

https://www.telerik.com/kendo-react-ui/components/upload/api/UploadProps/#toc-saveurl

We have an example in this GitHub item as well:

https://github.com/telerik/kendo-react/issues/193

Please have in mind that the upload will provide only the file, any further conversion or modifications has to be done programmatically.

I hope this is helpful.

Regards,
Stefan
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
David
Top achievements
Rank 1
Iron
Iron
Veteran
answered on 18 Dec 2020, 06:55 AM

Thanks Stefan,

Are there any plans to add automatic transferral to byte arrays, or chunked upload of large files?

Kind regards,

David

0
Stefan
Telerik team
answered on 18 Dec 2020, 08:43 AM

Hello, David,

Any new features are based on the community requests in our portal.

If you wish a method that will do this conversion, please log a feature request for it and we will plan it accordingly:

https://feedback.telerik.com/kendo-react-ui

Regards,
Stefan
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
David
Top achievements
Rank 1
Iron
Iron
Veteran
answered on 29 Jan 2021, 10:38 AM

Hi Stefan,

As discussed I am attempting to use the Upload component to transfer a single file to a byte array. I was hoping that you could confirm that the implementation below is valid, specifically:

  • is it possible / necessary to call FileReader.abort() from the onCancel?
  • is it necessary to reject the uid on FileReader.abort() given that a cancel always seems to result in a subsequent Remove?
  • is there a list of the possible UploadFileInfo.validationErrors anywhere? It would be nice to present some sort of error in the Upload component on FileReader.abort or error (see attached for a simulated error part way through the upload process, the progress bar is red and the 'Done' text has a warning icon but there is no validation message to indicate why)
import React, { useEffect, useState } from "react";
import { Upload, UploadFileInfo, UploadFileStatus } from "@progress/kendo-react-upload";
 
interface IKendoFileUpload {
    files: UploadFileInfo[] | undefined;
    content: string | undefined;
}
 
export function KendoSingleFileUpload(props: {
    selectedFile: UploadFileInfo | undefined;
    content: string | undefined;
    allowedExtensions?: string[] | undefined;
    minFileSize?: number | undefined;
    maxFileSize?: number | undefined;
    onFileValidlySelected: (selectedFile: UploadFileInfo | undefined, content: string | undefined) => void;
}) {
    const [files, setFiles] = useState<UploadFileInfo[] | undefined>(new Array<UploadFileInfo>());
    const [content, setContent] = useState<string>("");
 
    useEffect(() => {
        setFiles(props.selectedFile ? [props.selectedFile] : new Array<UploadFileInfo>());
    }, [props.selectedFile]);
    useEffect(() => {
        setContent(props.content ?? "");
    }, [props.content]);
 
    function onAdd(event: any) {
        setFiles(event.newState);
    }
 
    function onCancel(event: any) {
        // abort reader?
    }
 
    function onProgress(event: any) {
        setFiles(event.newState);
    }
 
    function onRemove(event: any) {
        setFiles(event.newState);
    }
 
    function onStatusChange(event: any) {
        setFiles(event.newState);
    }
 
    function onSaveRequest(
        files: UploadFileInfo[],
        options: { formData: FormData; requestOptions: any },
        onProgress: (uid: string, event: ProgressEvent<EventTarget>) => void
    ): Promise<{ uid: string }> {
        const currentFile = files[0] as UploadFileInfo;
        const uid = currentFile.uid;
 
        const saveRequestPromise = new Promise<{ uid: string }>(async (resolve, reject) => {
            if (currentFile.validationErrors && currentFile.validationErrors.length > 0) {
                reject({ uid: uid });
            } else {
                const reader = new FileReader();
                reader.onload = () => {
                    if (reader.result && typeof reader.result === "string") {
                        // stripping the data-url declaration as per https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
                        const base64Result = reader.result.split(",")[1];
                        setContent(base64Result);
                        resolve({ uid: uid });
                    }
                    reject({ uid: uid });
                };
                reader.onabort = () => {
                    // reject({ uid: uid }); ?
                };
                reader.onerror = () => {
                    reject({ uid: uid });
                };
                reader.onprogress = (data) => {
                    onProgress(uid, data);
                };
 
                reader.readAsDataURL(currentFile.getRawFile!());
            }
        });
 
        return saveRequestPromise;
    }
 
    function onRemoveRequest(files: UploadFileInfo[], options: { formData: FormData; requestOptions: any }): Promise<{ uid: string }> {
        const currentFile = files[0] as UploadFileInfo;
        const uid = currentFile.uid;
 
        const removeRequestPromise = new Promise<{ uid: string }>((resolve) => {
            setContent("");
            resolve({ uid: uid });
        });
 
        return removeRequestPromise;
    }
 
    return (
        <Upload
            autoUpload={false}
            batch={false}
            files={files}
            multiple={false}
            onAdd={onAdd}
            onCancel={onCancel}
            onProgress={onProgress}
            onRemove={onRemove}
            onStatusChange={onStatusChange}
            withCredentials={false}
            removeUrl={onRemoveRequest}
            saveUrl={onSaveRequest}
            restrictions={{ allowedExtensions: props.allowedExtensions, minFileSize: props.minFileSize, maxFileSize: props.maxFileSize }}
        />
    );
}
0
Stefan
Telerik team
answered on 01 Feb 2021, 01:37 PM

Hello, David,

Thank you for the provided code.

Regarding the questions:

1)  is it possible / necessary to call FileReader.abort() from the onCancel?  - 

- Possible: it will be possible if the нew FileReader() is created on a top-level, so each function has access to it.

- Necessary: This will depend on the application and its requirements, if the read operation has to stop then the method can be called.

2) is it necessary to reject the uid on FileReader.abort() given that a cancel always seems to result in a subsequent Remove? - If we know that the process will stop it is better to reject it. Is there any issue caused by the reject that lead to this question?

3) is there a list of the possible UploadFileInfo.validationErrors anywhere? - This property expects one of the message keys listed here:

https://www.telerik.com/kendo-react-ui/components/upload/globalization/#toc-messages (The messages can be customized as well.)

I made an example showcasing this:

https://stackblitz.com/edit/react-pkuvmt-5nexde?file=app/main.jsx

Regards,
Stefan
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
David
Top achievements
Rank 1
Iron
Iron
Veteran
answered on 02 Feb 2021, 03:07 AM

Thanks Stefan,

You mentioned that the messages can be customised, could you please show me how to do that?

Kind regards,

David

0
Stefan
Telerik team
answered on 02 Feb 2021, 07:11 AM

Hello, David,

Yes, this can be done by combining both examples and changing the value of the message key in the message json file:

https://stackblitz.com/edit/react-vetqgz?file=app%2Fmain.jsx

If you load a file it will show the custom message associated with the invalidFiles key:

{
    "upload": {
        "cancel": "Отмени",
        "clearSelectedFiles": "Изчисти",
        "dropFilesHere": "Пусни фаиловете тук за качване",
        "headerStatusUploaded": "Готово",
        "headerStatusUploading": "Качване...",
        "invalidFileExtension": "Този тип фаил не е позволен.",
        "invalidFiles": "This is my custom message for invalid files",
The same can be done for other message keys.

Regards,
Stefan
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

David
Top achievements
Rank 1
Iron
Iron
Veteran
commented on 26 Aug 2021, 12:29 PM

Thanks Stefan,

In terms of implementing custom messages for an Upload component used repeatedly throughout a production app would best practice be to wrap the entire App in the LocalizationProvider and IntlProvider, and loadMessages there to avoid repeated loads?

Kind regards,

David

Stefan
Telerik team
commented on 26 Aug 2021, 12:32 PM

Hello, David,

Yes, this is the recommended approach. We advise using these provides on a lower level only if they have to be applied on specific components without affecting the others. In all other cases, we can recommend using both providers on a top-level in order to affect all components from a single place.

Tags
General Discussions
Asked by
David
Top achievements
Rank 1
Iron
Iron
Veteran
Answers by
Stefan
Telerik team
David
Top achievements
Rank 1
Iron
Iron
Veteran
Share this question
or