Implementing DevExtreme FileUploader Component With Custom RxJs Observables and Callbacks
By: Dominik Januvka
Tags: Devextreme, Angular, Front End Development, Ui Framework, Rxjs

Photo by Wesley Tingey on Unsplash

Let’s say you are developing an application where as part of your app you want to upload some files and you want to use existing component from UI framework. In this example I am using Angular and DevExtreme as UI framework.

FileUploader component in action

TL;DR: This guide serves as how-to since the official documentation is lacking details in this manner. This article was written retrospectively, so some info may be missing or incomplete.

Prerequisites

To use FileUploader module from devextreme ui framework you have to setup project first. Here is how: https://js.devexpress.com/Documentation/Guide/Angular_Components/Getting_Started/Create_a_DevExtreme_Application/

Configuration Options of FileUploader

Config properties for file uploader

#templateSelector is needed so you can select Devextreme’s file uploader component using Angular’s @ViewChild

name self describing :)

accept is set up if you want to filter file types in Explorer window

uploadMode decides the behavior of component itself, so let’s set up instant (no need to press any button to upload)

uploadUrl in bigger applications you want to use secure connection to API, right? So the default uploadUrl property wouldn’t be sufficient because it routes you to current domain, instead of some preferred API URL. Best way to do this, is to have custom service which will handle connection to API back-end and also handle security.

[uploadFile] is a function that uploads a file. This is where our magic starts to happen. Here is how

uploadFile(file, uploadInfoCallback) {

let formData = new FormData();

formData.append("file", file, file.name);

return this.dataService

.upload(this.URL_UPLOAD, formData, uploadInfoCallback)

.toPromise()

}

See? we just create new form and append the file to it. Then call our service upload observable and convert it toPromise(). We do this because frameworks core uses promises. Do not forget callback function, it is important to track you file upload progress.

Service

In service there is no need to setup special header parameters about form, I learned it the hard way. If you are using interceptor and want to use cookies, you have to setup withCredentials to true, here is the right place to do it.

/**

* Method for file uploader component

* @param url uri string

* @param data form data File - The file that is uploaded.

* @param uploadInfo progress callback - Function that you should call to notify the widget about the file upload progress.

*/

public upload(url: string, data: any, uploadInfoCallback: Function): Observable<any> {

return this.http

.post<any[]>(url, data, { withCredentials: true, reportProgress: true, observe: 'events' } // no need to setup any headers

)

.pipe(

map((event) => {

switch (event.type) {

case HttpEventType.UploadProgress:

uploadInfoCallback && uploadInfoCallback(Math.round(event.loaded));

return event;

default:

return event;

}

})

)

};

Here we are using POST method from common HttpClient to upload file, where we setup url, options. In options we can specify usage of credentials, additional headers, and most importantly progress reporting.

Since we are using observable, we can observe events emitted from there. This setup will pipe us events of progress type, so we can catch them and pass info into callback to show current progress.

Clear the widget

Remember that #templateSelector we set up? So basically you want to reset the widget after uploading and closing window. When/where to do it? At beginning of course, which means on showing the widget. In this example widget is placed inside of popup with onShowing method.

onShowing(e) {

if (this.fileUploader) {

// clear file uploader

this.fileUploader.instance.reset();

// optionally use this.fileUploader.instance.option("value", []);

}

}

Sandbox

You can play around with this code example in sandbox here https://codesandbox.io/s/e71zj