An open API service indexing awesome lists of open source software.

https://github.com/bobbyg603/file-uploads-with-angular-and-rxjs

đŸ“‚đŸš€â˜ī¸ Powerful, elegant file uploads for Angular applications with RxJS
https://github.com/bobbyg603/file-uploads-with-angular-and-rxjs

angular article bindcallback bobbyg603 mergemap observable observables rxjs scan switchmap tutorial

Last synced: 12 months ago
JSON representation

đŸ“‚đŸš€â˜ī¸ Powerful, elegant file uploads for Angular applications with RxJS

Awesome Lists containing this project

README

          

## đŸ“‚đŸš€â˜ī¸ File Uploads with Angular and RxJS

Man Riding Rocket Ship In Space Holding Papers

[![medium profile link](https://img.shields.io/badge/Medium-12100E?style=for-the-badge&logo=medium&logoColor=white)](https://medium.com/better-programming/file-uploads-with-angular-and-rxjs-34262b3450ae)
[![twitter profile link](https://img.shields.io/badge/Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/bobbyg603/status/1524465334522195968)
[![StackBlitz](https://img.shields.io/badge/StackBlitz-Edit-blue?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAABECAYAAAD+1gcLAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH5AINBw4X0bTGRQAABSxJREFUaN7VmVtsFFUYx//fmQW79bbd2QKpaIIaDcGoifFBEgMGqTTRRA01SgxE5Rbi7QG6S3lgo9J2twpeotxEQlCigLdoQwJ4ARN9QB9MRCNRDBdRzE7LJbTSmTl/H4BYStmd2Z3tDOdt5lzml/9833fO9x0gYi2xgom6Tt5aapyKEnRDlrVGPzfGT+G3SwZ87HLGT8f5uYD7jmSl99IAX80RfTY3A5wMqDVepoQPnqVKHtMbAN4PyJeFtPwafXBSknG9UoDHAIDQq7xODRU8mdc5Aeaeffy7O2F8GnnwZM5dKsCic88CrMU8sSMNbubdZwTIDnjlOoZa52eNYQc3c84sEK+d/1a6ji2UA5EFN3POw4C8fcYy/m+a3p1y2MGTOXsqIJsAxAZ1Hei53tgeSfBkBycK1McALrswJGIVHhE3cuD1ed4uorsAXD5Ed7/hqvXlrFtV8LpO3qKpdwJIDLn/AB/+s0SORgp8VJ43KK23AzAvNsagWlXu+lKV6LGc14itvyEwrsiwX6wWNQEijITiY9pYD1vvKAENAG+VC40hQlNlNt3Bq22lt4EYX2Jor6PVe5V8KzDFG7KsFXE/A3GHB/vcdHyx9IQPnuXI/ji3CuRuT+N1+U4ZHPhmGqk43yXY5C0ccE9hsfwQLjgp5n69hmCz9ylYGcRPrgg8ldfLIXjSx5RjNX3GB6GCm3m3ncDz/v4QNnjJ4KsGbubdVhAZ35YFtTaoKOY7jps5dwGIZf73aH7dnZa9QYH72vLNDmcmRNaX86eEnGvT2BoIdA0o3pV2HgRkS9C7bXnRDGlPypmd9r2AvB8FaAFetDJGvqTiyU7eJWeOp1cgfOo3rRbj6ZJRJdHB20TrrkhAAxutXvVsSedMtfEmGno3gNHhM8snVp80IytO0The18HraOgdkYCm7KyLy6MDoYdUfNQyjnZjeheAm8NXmt/FlDH16CI5dUHaN/DhypeZUqK/AkomAsMQ8fCjq41GKy0nim75ydd51UjX3QZgQgQccV/MUfcVSzYM4Mw1hnPa7QJkYgSgD2qqe6xWOVL8kLWaI3ptbgFkUgSgjwpUY09GDpY8ZJnH9UsExhPYH8CuVgtgTJlzC5pqipXxdpUSaF3FzLkdANJleOIJETWlkJbvh78glOVIM64PARjlc2afiGoqtMiuUMoTqRp3ehnQtpDNfqEDBdeC+T6nuELOLGRiXVVPJC5u2xwP6L0+1qOQ8wqZWNmpXECK6wV+RBCipRLoQBRvyLL2dFwfBlDnTWos7W4xXgi3IATg31p3hldoEG8EAR0IuEC8OuUGK62eCyoYVARutvNOL9VZQD6yxqmnKqmHB6u46PkejHp7XVxmlHOzVhXnTKxgwujXhzH0bdo56m9jymgcKhEITXFl61lFoYV7BMa0akCjkjqJEHOKdP/U7xhNJ1vlZLXOv2Upnmq3JxfJlH4XRzWebBWrmgf38hRXav5F4vSfjqGmHl8if1W/NuSzjWljvW3oQxh0Ly9AQRtqUvdC+Xk4UiXfpmLH9JzB0CBOQKtpwwXtHzxLJcTsQW97FdQDQVxIVc3GUzVuEyEDb4z7NTndysju4c6qfSlOOc8pXQof78nEtoVRDvDsnMlXeK04+o+ztRgSnNOdjq1DSM2z4uLoeecKSCQWhgntXfEsY2ZcHwDQAMESq8VoC7ty5EnxZK37EIAGAV6NArT3c3def2Hm3HdASlSYSipe384bAR6x+tTsIBOBqoMTzlirVz2BrOgoWcF/mizikfkwKiQAAAAASUVORK5CYII=)]([https://stackblitz.com/edit/github-ktbxdp-ftgv1g](https://stackblitz.com/github/bobbyg603/file-uploads-with-angular-and-rxjs))

This is is a companion repo for [File Uploads with Angular and RxJS](https://betterprogramming.pub/file-uploads-with-angular-and-rxjs-34262b3450ae) that demonstrates how to build a drag and drop file upload control. Topics in this article include the uploading files with Angular HttpClient, using Bootstrap to display progress bars, and leveraging RxJS observables with subscriptions that complete automatically.

## â˜•ī¸ TL;DR

Clone this repo to your workspace:

```sh
git clone https://github.com/bobbyg603/file-uploads-with-angular-and-rxjs
```

Install the dependencies and start the application:

```sh
cd file-uploads-with-angular-and-rxjs && npm i && npm start
```

You will also need to clone the companion Express server:

```sh
git clone https://github.com/bobbyg603/upload-server
```

Install the dependencies and start the server:

```sh
cd upload-server && npm i && npm start
```

Use the drag and drop control or click "Browse Files" to select files to upload.

File Uploads With Angular and RxJS

## đŸ•ĩī¸ Inspecting the Code

This project requires a separate server for testing file uploads. Follow the instructions in the [bobbyg603/upload-server](https://github.com/bobbyg603/upload-server) repo to configure your system for testing file uploads.

> â„šī¸ The upload server should only be run on your local system while you're actively testing.

We use Angular's HttpClient to make a GET to our server so that we can display a list of files. The `getFilesSubject` will emit an event that triggers another GET to the server:

[app.component.ts](https://github.com/bobbyg603/file-uploads-with-angular-and-rxjs/blob/c327f1c833d0de4d8b09d5a2a5012b8670b2c2d3/src/app/app.component.ts#L21-L26)
```ts
files$?: Observable;

constructor(private httpClient: HttpClient) {
this.files$ = this.getFilesSubject.asObservable()
.pipe(
switchMap(() => this.httpClient.get('http://localhost:8080/files'))
);
}
```

The `files$` property is an observable that emits the list of files and is subscribed to in the template via the AsyncPipe:

[app.component.html](https://github.com/bobbyg603/file-uploads-with-angular-and-rxjs/blob/c327f1c833d0de4d8b09d5a2a5012b8670b2c2d3/src/app/app.component.html#L3)
```html

```

For file uploads, we start with a drag and drop control in the component template:

[app.component.html](https://github.com/bobbyg603/file-uploads-with-angular-and-rxjs/blob/c327f1c833d0de4d8b09d5a2a5012b8670b2c2d3/src/app/app.component.html#L1)
```html

```

We handle the `filesDropped` event in the component code. In the event handler we transform the `NgxFileDropEntry` array into an observable array of type `File`. For each file in the collection we call `uploadFile` and take all of the progress events until we see `HttpEventType.Response` which is the indication that the file has been uploaded successfully. We take all of the events and add them to a collection containing `FileUploadProgress` objects that describe the current upload progress for each of the files. Finally, the function passed to the `finalize` operator gets called and we instruct the `getFilesSubject` to emit so that the table of uploaded files is refreshed:

[app.component.ts](https://github.com/bobbyg603/file-uploads-with-angular-and-rxjs/blob/c327f1c833d0de4d8b09d5a2a5012b8670b2c2d3/src/app/app.component.ts#L28-L70)
```ts
uploads$?: Observable;

onFilesDropped(files: NgxFileDropEntry[]): void {
this.uploads$ = from(files)
.pipe(
mergeMap(selectedFile => {
const id = uuid();
const fileEntry = selectedFile.fileEntry as FileSystemFileEntry;
const observableFactory = bindCallback(fileEntry.file) as any;
const file$ = observableFactory.call(fileEntry) as Observable;
return file$
.pipe(
switchMap(file => this.uploadFile(file)
.pipe(
takeWhile(event => event.type !== HttpEventType.Response),
filter(isHttpProgressEvent),
map(event => {
const name = file.name;
const loaded = event.loaded ?? 0;
const total = event.total ?? 1;
const progress = Math.round(loaded / total * 100);
const failed = false;
const done = progress === 100;
return {
id,
name,
progress,
failed,
done
};
}),
)
)
);
}),
scan((acc, next) => {
acc[next.id] = next;
return {
...acc
};
}, {} as Record),
map(progress => Object.values(progress)),
finalize(() => this.getFilesSubject.next(null))
);
}
```

The `uploads$` property contains an observable collection of `FileUploadProgress` objects and is in the template to create a progress bar for each of the files being uploaded:

[app.component.html](https://github.com/bobbyg603/file-uploads-with-angular-and-rxjs/blob/c327f1c833d0de4d8b09d5a2a5012b8670b2c2d3/src/app/app.component.html#L2)
```html

```

## 🧑‍🎓 Further Exploration

Want to use this component in a production scenario? Take a look the [upload-client](https://github.com/bobbyg603/upload-client) repo.

Further Exploration Preview

The upload client repository takes this example and adds a Navbar, a modal, a loading wheel, error handling, and more!

## 🧑‍đŸ’ģ Next Steps

If you liked this example, please follow me on [Medium](https://bobbyg603.medium.com/) and [X](https://twitter.com/bobbyg603), where I post programming tutorials and discuss tips and tricks that have helped make me a better programmer.

**Thank you for your support â¤ī¸**