Build a file upload dropzone 📨 from scratch with Angular & Firebase that can handle multiple concurrent files and save the download URL to Firestore https://fireship.io/lessons/angular-firebase-storage-uploads-multi/ 

File Drop Web Component https://github.com/GoogleChromeLabs/file-drop
Firebase Storage https://firebase.google.com/docs/storage/
Drag and Drop https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop

#angular #firebase #storage
2024-02-04T06:57:22.196Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
ec0e2a72-41b7-48f6-8cbc-f815885b5a92
e9a830a3a0099e2cdc278ea38b8d91f63ddb292f76bc1789a790b9269dcdbfc6
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
When I first got started in web development, cloud storage buckets were a relatively new technology, and getting user generated files uploaded to the cloud was a major pain point.
But luckily today we have Firebase which makes this process much easier but just as flexible for the developer.
In today's video, you'll learn how to build a drop zone dial file uploader in Angular, they can handle multiple concurrent files to Firebase Storage.
If you're new here, like and subscribe and grab the full source code from Fireship IO.
I created a similar video about a year ago, but the number one request has been a system that handles multiple files concurrently.
So, in this demo, you can drop as many files as you want onto the drop zone, and then you can pause or cancel each individual upload.
The cool thing is that Firebase will handle all of the concurrency under the hood, so you can have your users drop as many files as you want here, and Firebase will choose the best strategy to get those files uploaded to the Cloud, which is based mostly on the user's network connection.
And another thing we'll do is save the download URL to this file in Firestore.
This makes it really easy to access the raw file if you're already using Firestore and other parts of your application.
Now, I'm going to show you how to build the drop zone from scratch in Angular, But, one thing you should check out is this custom file drop element from Google Chrome Labs.
It has nothing to do with Angular, but because web components are awesome, you can just drop it in Angular app and start using it.
So this might be a good alternative for building your own custom drop zone.
Let's go ahead and get started.
First, I'm assuming that you have an Angular app along with AngularFire and Firebase installed.
If we take a look at the app module, you can see I have AngularFire storage and Firestore.
And if we take a look at the CSS for this application, we have a drop zone class, which is just a flex box with a border.
Then we have a hovering class that will change the border from dash saw it when the user hovers over the box.
And all the other styles come from a framework called Volma, which if you're not familiar with, is a cool alternative to Bootstrap or Material.
The first thing we'll do is generate a directive that will be able to turn any div into a drop zone.
And by drop zone, I just mean an area that the user can drag and drop files do and then we can receive those files as an event in our web application.
So we'll go ahead and call that directive drop zone and its responsibility is to receive the files and then emit them up as a custom event that we can listen to in other components.
In Angular, we create custom events by using a combination of output and event emitter.
This allows a parent component to listen to events that happen in this child directive.
In this case here, we're creating a custom event called dropped that emits a file list.
And a file list is built into the browser and it contains the actual files that the user dragged on to this element.
Then we'll also emit a custom event called hovered that will tell us whether or not the user is hovering over the elements so we can toggle that border.
From here, we're going to use host listener to intercept the drop event in the DOM.
Drop will happen after the user drags a set of files over to the drop zone and then let's go on the mouse.
Normally, this would cause a new browser tab to open, so we call event prevent default choose stop that from happening, from there, we want the directive to emit the files out as a custom event.
And we can access the files by calling event data transfer files.
And we'll also go ahead and emit false through our hovered event.
So that takes care of the file drop event.
We also wanna listen to drag over and drag leave, then emit true or false depending on whether or not the user is dragging over the element.
And that takes care of the entire directive.
You now have a way to compose this logic into any component or element in your Angular app.
Now we can move on to the actual file uploading logic.
Because we want to handle multiple concurrent file uploads, we'll have a parent that manages all of the files that the user dropped and then each child component will manage the actual upload of that file.
You can see here I've generated 2 new components.
1 is the uploader, that's the parent, and then one is the upload task, that's the child.
Let's start with the logic for the parent component.
It's going to have a property is hovering which which we can just use to toggle the border on the drop zone, and it also has an array of files.
1st, we'll define this toggle hover event handler, which will just flip that property from true to false.
Then the on drop event handler takes the file list as its argument.
The file list contains all of the files, but it's not something that we can just loop over directly with a for each loop.
So so instead we have to set up a traditional for loop here and then we'll add it to the array of files on this component.
The reason we do this is so we can pass each individual file to a child component in the Angular template.
Now we can go into the template and we'll set up a div here with our drop zone class and then we'll add that drop zone directive that we created earlier.
This gives us access to the custom events that we created like hovered and on drop.
In Angular has a built in class directive that we can use to toggle the hovering class whenever the is hovering property is true.
We could stop there and the drag and drop feature would work perfectly fine, but put it, it's also a good idea to add a file input field so users on mobile devices can just click a button to upload, or for those on desktop that just don't want to drag and drop.
We can use the same on drop event handler, but for the argument, we'll wanna pass the event target files.
And the event itself is the change event on that form input.
The last thing we need to do here is loop over the array of files.
Each file will be passed as an input property to the child upload task component.
Now it's time to move on to the upload task and that's where we'll write the code that actually uploads the file to cloud storage.
We'll start by importing our AngularFire dependencies and a few things from RxJS.
And in this demo, we're going to have the upload start as soon as the component is initialized, but you could easily modify this to make it more lazy if you want the user to push a button first before it actually uploads the file.
1st, we decorate the file property with input so it can be passed down from the parent component.
Then we have the AngularFire upload task which does most of the magic for the file upload itself.
Then while the file is uploading, it provides a couple of different observables that we can listen to do monitor the progress, percentage and snapshot will help us do that, then we'll also display the download URL for the file when the upload is complete.
From there, we'll add our dependencies to the constructor, which are Angular Fire Storage and DB for Firestore.
Then we'll define the upload logic in its own method and then run that method as soon as the components initialized.
And again you could extract that out to a button if you want to make it a lazy upload.
The first step is to define the path in the storage bucket where this file will be saved.
I'm also adding a timestamp to the file name just to ensure that it's unique.
You don't have to do this, but keep in mind that file names need to be unique.
Saw if you upload a file to the same location with the same name, the latest one will override the old one.
From there, I'll use storage to make a reference to that actual location in the bucket, been calling upload, we'll start the actual file upload to Firebase Storage.
It's not an observable.
There's no need to subscribe to it, but it does provide bowls that we can use to monitor the progress of the upload.
Percentage changes is just a number ranging from 0 to 100 that makes it easy to create a progress bar.
Then snapshot changes is an observable that emits an object every few 100 milliseconds with a bunch of data about the file upload.
It contains the bytes transferred as well as a bunch of other information, so I recommend you console log it so you can take a closer look.
Then RxJS has a finalized operator that runs after this observable is lead it.
I've experimented with a few different approaches here, but I think what makes the most sense is just to add an async function that gets the download URL and converts it to a Promise.
The reason I like this approach is because we first need this download URL before we can run our update to the Firestore database.
And with async await, we can just do this in two lines of code.
We first get the download URL and then we make a reference to the files collection and add that document to the database.
As a final touch, I'm adding this is active method which will tell us whether or not an upload is currently running.
This just makes it easier to disable the cancel and pause buttons based on the state of the upload.
Now at this point, we just need to unwrap our Observables in the template.
I like to unwrap the Observables inside of n g f and then set the value as a template variable.
This allows us to use this percent variable just like a synchronous value in the template.
We can set this as the value to our progress bar and then also display the raw value as well.
We can unwrap the snapshot in the same way.
That'll give us access to the bytes transferred, which we can then compare to the total bytes of the file.
And then we can also display our download URL in here as well.
But the coolest part is that the AngularFire upload task allows us to control the upload itself.
For example, if we want the user to be able to control the upload, we can add a pause button here and then just call task pause to pause it.
Then we can do the same thing for cancel and resume.
And lastly, we'll use that is active method that we defined earlier to just disable these buttons depending on the current state of the upload.
If we go back to the demo and start load in some files, we should get results that look like this.
Each individual file will have its own progress indicator, and if we click pause or resume, it should react accordingly.
And if we pull up the Firestore database, you should also see the download URL being saved there as well.
Hopefully, that gives you a good starting point for your own file uploading system.
If this video helped you, please like and subscribe and make sure to grab the full source code from FireShip.
Io.
Thanks for watching and I will talk to you soon.

Speaker 0: When I first got started in web development, cloud storage buckets were a relatively new technology, and getting user generated files uploaded to the cloud was a major pain point. But luckily today we have Firebase which makes this process much easier but just as flexible for the developer. In today's video, you'll learn how to build a drop zone dial file uploader in Angular, they can handle multiple concurrent files to Firebase Storage. If you're new here, like and subscribe and grab the full source code from Fireship IO. I created a similar video about a year ago, but the number one request has been a system that handles multiple files concurrently.

So, in this demo, you can drop as many files as you want onto the drop zone, and then you can pause or cancel each individual upload. The cool thing is that Firebase will handle all of the concurrency under the hood, so you can have your users drop as many files as you want here, and Firebase will choose the best strategy to get those files uploaded to the Cloud, which is based mostly on the user's network connection. And another thing we'll do is save the download URL to this file in Firestore. This makes it really easy to access the raw file if you're already using Firestore and other parts of your application. Now, I'm going to show you how to build the drop zone from scratch in Angular, But, one thing you should check out is this custom file drop element from Google Chrome Labs.

It has nothing to do with Angular, but because web components are awesome, you can just drop it in Angular app and start using it. So this might be a good alternative for building your own custom drop zone. Let's go ahead and get started. First, I'm assuming that you have an Angular app along with AngularFire and Firebase installed. If we take a look at the app module, you can see I have AngularFire storage and Firestore.

And if we take a look at the CSS for this application, we have a drop zone class, which is just a flex box with a border. Then we have a hovering class that will change the border from dash saw it when the user hovers over the box. And all the other styles come from a framework called Volma, which if you're not familiar with, is a cool alternative to Bootstrap or Material. The first thing we'll do is generate a directive that will be able to turn any div into a drop zone. And by drop zone, I just mean an area that the user can drag and drop files do and then we can receive those files as an event in our web application.

So we'll go ahead and call that directive drop zone and its responsibility is to receive the files and then emit them up as a custom event that we can listen to in other components. In Angular, we create custom events by using a combination of output and event emitter. This allows a parent component to listen to events that happen in this child directive. In this case here, we're creating a custom event called dropped that emits a file list. And a file list is built into the browser and it contains the actual files that the user dragged on to this element.

Then we'll also emit a custom event called hovered that will tell us whether or not the user is hovering over the elements so we can toggle that border. From here, we're going to use host listener to intercept the drop event in the DOM. Drop will happen after the user drags a set of files over to the drop zone and then let's go on the mouse. Normally, this would cause a new browser tab to open, so we call event prevent default choose stop that from happening, from there, we want the directive to emit the files out as a custom event. And we can access the files by calling event data transfer files.

And we'll also go ahead and emit false through our hovered event. So that takes care of the file drop event. We also wanna listen to drag over and drag leave, then emit true or false depending on whether or not the user is dragging over the element. And that takes care of the entire directive. You now have a way to compose this logic into any component or element in your Angular app.

Now we can move on to the actual file uploading logic. Because we want to handle multiple concurrent file uploads, we'll have a parent that manages all of the files that the user dropped and then each child component will manage the actual upload of that file. You can see here I've generated 2 new components. 1 is the uploader, that's the parent, and then one is the upload task, that's the child. Let's start with the logic for the parent component.

It's going to have a property is hovering which which we can just use to toggle the border on the drop zone, and it also has an array of files. 1st, we'll define this toggle hover event handler, which will just flip that property from true to false. Then the on drop event handler takes the file list as its argument. The file list contains all of the files, but it's not something that we can just loop over directly with a for each loop. So so instead we have to set up a traditional for loop here and then we'll add it to the array of files on this component.

The reason we do this is so we can pass each individual file to a child component in the Angular template. Now we can go into the template and we'll set up a div here with our drop zone class and then we'll add that drop zone directive that we created earlier. This gives us access to the custom events that we created like hovered and on drop. In Angular has a built in class directive that we can use to toggle the hovering class whenever the is hovering property is true. We could stop there and the drag and drop feature would work perfectly fine, but put it, it's also a good idea to add a file input field so users on mobile devices can just click a button to upload, or for those on desktop that just don't want to drag and drop.

We can use the same on drop event handler, but for the argument, we'll wanna pass the event target files. And the event itself is the change event on that form input. The last thing we need to do here is loop over the array of files. Each file will be passed as an input property to the child upload task component. Now it's time to move on to the upload task and that's where we'll write the code that actually uploads the file to cloud storage.

We'll start by importing our AngularFire dependencies and a few things from RxJS. And in this demo, we're going to have the upload start as soon as the component is initialized, but you could easily modify this to make it more lazy if you want the user to push a button first before it actually uploads the file. 1st, we decorate the file property with input so it can be passed down from the parent component. Then we have the AngularFire upload task which does most of the magic for the file upload itself. Then while the file is uploading, it provides a couple of different observables that we can listen to do monitor the progress, percentage and snapshot will help us do that, then we'll also display the download URL for the file when the upload is complete.

From there, we'll add our dependencies to the constructor, which are Angular Fire Storage and DB for Firestore. Then we'll define the upload logic in its own method and then run that method as soon as the components initialized. And again you could extract that out to a button if you want to make it a lazy upload. The first step is to define the path in the storage bucket where this file will be saved. I'm also adding a timestamp to the file name just to ensure that it's unique.

You don't have to do this, but keep in mind that file names need to be unique. Saw if you upload a file to the same location with the same name, the latest one will override the old one. From there, I'll use storage to make a reference to that actual location in the bucket, been calling upload, we'll start the actual file upload to Firebase Storage. It's not an observable. There's no need to subscribe to it, but it does provide bowls that we can use to monitor the progress of the upload.

Percentage changes is just a number ranging from 0 to 100 that makes it easy to create a progress bar. Then snapshot changes is an observable that emits an object every few 100 milliseconds with a bunch of data about the file upload. It contains the bytes transferred as well as a bunch of other information, so I recommend you console log it so you can take a closer look. Then RxJS has a finalized operator that runs after this observable is lead it. I've experimented with a few different approaches here, but I think what makes the most sense is just to add an async function that gets the download URL and converts it to a Promise.

The reason I like this approach is because we first need this download URL before we can run our update to the Firestore database. And with async await, we can just do this in two lines of code. We first get the download URL and then we make a reference to the files collection and add that document to the database. As a final touch, I'm adding this is active method which will tell us whether or not an upload is currently running. This just makes it easier to disable the cancel and pause buttons based on the state of the upload.

Now at this point, we just need to unwrap our Observables in the template. I like to unwrap the Observables inside of n g f and then set the value as a template variable. This allows us to use this percent variable just like a synchronous value in the template. We can set this as the value to our progress bar and then also display the raw value as well. We can unwrap the snapshot in the same way.

That'll give us access to the bytes transferred, which we can then compare to the total bytes of the file. And then we can also display our download URL in here as well. But the coolest part is that the AngularFire upload task allows us to control the upload itself. For example, if we want the user to be able to control the upload, we can add a pause button here and then just call task pause to pause it. Then we can do the same thing for cancel and resume.

And lastly, we'll use that is active method that we defined earlier to just disable these buttons depending on the current state of the upload. If we go back to the demo and start load in some files, we should get results that look like this. Each individual file will have its own progress indicator, and if we click pause or resume, it should react accordingly. And if we pull up the Firestore database, you should also see the download URL being saved there as well. Hopefully, that gives you a good starting point for your own file uploading system.

If this video helped you, please like and subscribe and make sure to grab the full source code from FireShip. Io. Thanks for watching and I will talk to you soon.
When I first got started in web development, cloud storage buckets were a relatively new technology, and getting user generated files uploaded to the cloud was a major pain point. But luckily today we have Firebase which makes this process much easier but just as flexible for the developer. In today's video, you'll learn how to build a drop zone dial file uploader in Angular, they can handle multiple concurrent files to Firebase Storage.
If you're new here, like and subscribe and grab the full source code from Fireship IO. I created a similar video about a year ago, but the number one request has been a system that handles multiple files concurrently. So, in this demo, you can drop as many files as you want onto the drop zone, and then you can pause or cancel each individual upload.
streaming
video gaming
The cool thing is that Firebase will handle all of the concurrency under the hood, so you can have your users drop as many files as you want here, and Firebase will choose the best strategy to get those files uploaded to the Cloud, which is based mostly on the user's network connection. And another thing we'll do is save the download URL to this file in Firestore. This makes it really easy to access the raw file if you're already using Firestore and other parts of your application. Now, I'm going to show you how to build the drop zone from scratch in Angular, But, one thing you should check out is this custom file drop element from Google Chrome Labs. It has nothing to do with Angular, but because web components are awesome, you can just drop it in Angular app and start using it. So this might be a good alternative for building your own custom drop zone. Let's go ahead and get started. First, I'm assuming that you have an Angular app along with AngularFire and Firebase installed. If we take a look at the app module, you can see I have AngularFire storage and Firestore. And if we take a look at the CSS for this application, we have a drop zone class, which is just a flex box with a border. Then we have a hovering class that will change the border from dash saw it when the user hovers over the box. And all the other styles come from a framework called Volma, which if you're not familiar with, is a cool alternative to Bootstrap or Material. The first thing we'll do is generate a directive that will be able to turn any div into a drop zone. And by drop zone, I just mean an area that the user can drag and drop files do and then we can receive those files as an event in our web application. So we'll go ahead and call that directive drop zone and its responsibility is to receive the files and then emit them up as a custom event that we can listen to in other components. In Angular, we create custom events by using a combination of output and event emitter. This allows a parent component to listen to events that happen in this child directive. In this case here, we're creating a custom event called dropped that emits a file list. And a file list is built into the browser and it contains the actual files that the user dragged on to this element. Then we'll also emit a custom event called hovered that will tell us whether or not the user is hovering over the elements so we can toggle that border. From here, we're going to use host listener to intercept the drop event in the DOM. Drop will happen after the user drags a set of files over to the drop zone and then let's go on the mouse. Normally, this would cause a new browser tab to open, so we call event prevent default choose stop that from happening, from there, we want the directive to emit the files out as a custom event.
And we can access the files by calling event data transfer files. And we'll also go ahead and emit false through our hovered event. So that takes care of the file drop event. We also wanna listen to drag over and drag leave, then emit true or false depending on whether or not the user is dragging over the element.
streaming
And that takes care of the entire directive. You now have a way to compose this logic into any component or element in your Angular app. Now we can move on to the actual file uploading logic. Because we want to handle multiple concurrent file uploads, we'll have a parent that manages all of the files that the user dropped and then each child component will manage the actual upload of that file.
You can see here I've generated 2 new components. 1 is the uploader, that's the parent, and then one is the upload task, that's the child. Let's start with the logic for the parent component. It's going to have a property is hovering which which we can just use to toggle the border on the drop zone, and it also has an array of files.
parenting
1st, we'll define this toggle hover event handler, which will just flip that property from true to false. Then the on drop event handler takes the file list as its argument. The file list contains all of the files, but it's not something that we can just loop over directly with a for each loop. So so instead we have to set up a traditional for loop here and then we'll add it to the array of files on this component. The reason we do this is so we can pass each individual file to a child component in the Angular template. Now we can go into the template and we'll set up a div here with our drop zone class and then we'll add that drop zone directive that we created earlier. This gives us access to the custom events that we created like hovered and on drop. In Angular has a built in class directive that we can use to toggle the hovering class whenever the is hovering property is true. We could stop there and the drag and drop feature would work perfectly fine, but put it, it's also a good idea to add a file input field so users on mobile devices can just click a button to upload, or for those on desktop that just don't want to drag and drop. We can use the same on drop event handler, but for the argument, we'll wanna pass the event target files. And the event itself is the change event on that form input. The last thing we need to do here is loop over the array of files. Each file will be passed as an input property to the child upload task component. Now it's time to move on to the upload task and that's where we'll write the code that actually uploads the file to cloud storage. We'll start by importing our AngularFire dependencies and a few things from RxJS. And in this demo, we're going to have the upload start as soon as the component is initialized, but you could easily modify this to make it more lazy if you want the user to push a button first before it actually uploads the file. 1st, we decorate the file property with input so it can be passed down from the parent component. Then we have the AngularFire upload task which does most of the magic for the file upload itself.
Then while the file is uploading, it provides a couple of different observables that we can listen to do monitor the progress, percentage and snapshot will help us do that, then we'll also display the download URL for the file when the upload is complete. From there, we'll add our dependencies to the constructor, which are Angular Fire Storage and DB for Firestore.
streaming
Then we'll define the upload logic in its own method and then run that method as soon as the components initialized. And again you could extract that out to a button if you want to make it a lazy upload. The first step is to define the path in the storage bucket where this file will be saved. I'm also adding a timestamp to the file name just to ensure that it's unique. You don't have to do this, but keep in mind that file names need to be unique. Saw if you upload a file to the same location with the same name, the latest one will override the old one. From there, I'll use storage to make a reference to that actual location in the bucket, been calling upload, we'll start the actual file upload to Firebase Storage. It's not an observable. There's no need to subscribe to it, but it does provide bowls that we can use to monitor the progress of the upload.
Percentage changes is just a number ranging from 0 to 100 that makes it easy to create a progress bar. Then snapshot changes is an observable that emits an object every few 100 milliseconds with a bunch of data about the file upload. It contains the bytes transferred as well as a bunch of other information, so I recommend you console log it so you can take a closer look.
statistics
Then RxJS has a finalized operator that runs after this observable is lead it. I've experimented with a few different approaches here, but I think what makes the most sense is just to add an async function that gets the download URL and converts it to a Promise. The reason I like this approach is because we first need this download URL before we can run our update to the Firestore database. And with async await, we can just do this in two lines of code. We first get the download URL and then we make a reference to the files collection and add that document to the database. As a final touch, I'm adding this is active method which will tell us whether or not an upload is currently running. This just makes it easier to disable the cancel and pause buttons based on the state of the upload. Now at this point, we just need to unwrap our Observables in the template. I like to unwrap the Observables inside of n g f and then set the value as a template variable. This allows us to use this percent variable just like a synchronous value in the template. We can set this as the value to our progress bar and then also display the raw value as well. We can unwrap the snapshot in the same way.
That'll give us access to the bytes transferred, which we can then compare to the total bytes of the file. And then we can also display our download URL in here as well. But the coolest part is that the AngularFire upload task allows us to control the upload itself.
streaming
For example, if we want the user to be able to control the upload, we can add a pause button here and then just call task pause to pause it. Then we can do the same thing for cancel and resume. And lastly, we'll use that is active method that we defined earlier to just disable these buttons depending on the current state of the upload.
If we go back to the demo and start load in some files, we should get results that look like this. Each individual file will have its own progress indicator, and if we click pause or resume, it should react accordingly. And if we pull up the Firestore database, you should also see the download URL being saved there as well. Hopefully, that gives you a good starting point for your own file uploading system. If this video helped you, please like and subscribe and make sure to grab the full source code from FireShip. Io. Thanks for watching and I will talk to you soon.
streaming
youtube
video gaming
documentary
When I first got started in web development, cloud storage buckets were a relatively new technology, and getting user generated files uploaded to the cloud was a major pain point. But luckily today we have Firebase which makes this process much easier but just as flexible for the developer. In today's video, you'll learn how to build a drop zone dial file uploader in Angular, they can handle multiple concurrent files to Firebase Storage. If you're new here, like and subscribe and grab the full source code from Fireship IO. I created a similar video about a year ago, but the number one request has been a system that handles multiple files concurrently. So, in this demo, you can drop as many files as you want onto the drop zone, and then you can pause or cancel each individual upload. The cool thing is that Firebase will handle all of the concurrency under the hood, so you can have your users drop as many files as you want here, and Firebase will choose the best strategy to get those files uploaded to the Cloud, which is based mostly on the user's network connection. And another thing we'll do is save the download URL to this file in Firestore. This makes it really easy to access the raw file if you're already using Firestore and other parts of your application. Now, I'm going to show you how to build the drop zone from scratch in Angular, But, one thing you should check out is this custom file drop element from Google Chrome Labs. It has nothing to do with Angular, but because web components are awesome, you can just drop it in Angular app and start using it. So this might be a good alternative for building your own custom drop zone. Let's go ahead and get started. First, I'm assuming that you have an Angular app along with AngularFire and Firebase installed. If we take a look at the app module, you can see I have AngularFire storage and Firestore. And if we take a look at the CSS for this application, we have a drop zone class, which is just a flex box with a border. Then we have a hovering class that will change the border from dash saw it when the user hovers over the box. And all the other styles come from a framework called Volma, which if you're not familiar with, is a cool alternative to Bootstrap or Material. The first thing we'll do is generate a directive that will be able to turn any div into a drop zone. And by drop zone, I just mean an area that the user can drag and drop files do and then we can receive those files as an event in our web application. So we'll go ahead and call that directive drop zone and its responsibility is to receive the files and then emit them up as a custom event that we can listen to in other components. In Angular, we create custom events by using a combination of output and event emitter. This allows a parent component to listen to events that happen in this child directive. In this case here, we're creating a custom event called dropped that emits a file list. And a file list is built into the browser and it contains the actual files that the user dragged on to this element. Then we'll also emit a custom event called hovered that will tell us whether or not the user is hovering over the elements so we can toggle that border. From here, we're going to use host listener to intercept the drop event in the DOM. Drop will happen after the user drags a set of files over to the drop zone and then let's go on the mouse. Normally, this would cause a new browser tab to open, so we call event prevent default choose stop that from happening, from there, we want the directive to emit the files out as a custom event. And we can access the files by calling event data transfer files. And we'll also go ahead and emit false through our hovered event. So that takes care of the file drop event. We also wanna listen to drag over and drag leave, then emit true or false depending on whether or not the user is dragging over the element. And that takes care of the entire directive. You now have a way to compose this logic into any component or element in your Angular app. Now we can move on to the actual file uploading logic. Because we want to handle multiple concurrent file uploads, we'll have a parent that manages all of the files that the user dropped and then each child component will manage the actual upload of that file. You can see here I've generated 2 new components. 1 is the uploader, that's the parent, and then one is the upload task, that's the child. Let's start with the logic for the parent component. It's going to have a property is hovering which which we can just use to toggle the border on the drop zone, and it also has an array of files. 1st, we'll define this toggle hover event handler, which will just flip that property from true to false. Then the on drop event handler takes the file list as its argument. The file list contains all of the files, but it's not something that we can just loop over directly with a for each loop. So so instead we have to set up a traditional for loop here and then we'll add it to the array of files on this component. The reason we do this is so we can pass each individual file to a child component in the Angular template. Now we can go into the template and we'll set up a div here with our drop zone class and then we'll add that drop zone directive that we created earlier. This gives us access to the custom events that we created like hovered and on drop. In Angular has a built in class directive that we can use to toggle the hovering class whenever the is hovering property is true. We could stop there and the drag and drop feature would work perfectly fine, but put it, it's also a good idea to add a file input field so users on mobile devices can just click a button to upload, or for those on desktop that just don't want to drag and drop. We can use the same on drop event handler, but for the argument, we'll wanna pass the event target files. And the event itself is the change event on that form input. The last thing we need to do here is loop over the array of files. Each file will be passed as an input property to the child upload task component. Now it's time to move on to the upload task and that's where we'll write the code that actually uploads the file to cloud storage. We'll start by importing our AngularFire dependencies and a few things from RxJS. And in this demo, we're going to have the upload start as soon as the component is initialized, but you could easily modify this to make it more lazy if you want the user to push a button first before it actually uploads the file. 1st, we decorate the file property with input so it can be passed down from the parent component. Then we have the AngularFire upload task which does most of the magic for the file upload itself. Then while the file is uploading, it provides a couple of different observables that we can listen to do monitor the progress, percentage and snapshot will help us do that, then we'll also display the download URL for the file when the upload is complete. From there, we'll add our dependencies to the constructor, which are Angular Fire Storage and DB for Firestore. Then we'll define the upload logic in its own method and then run that method as soon as the components initialized. And again you could extract that out to a button if you want to make it a lazy upload. The first step is to define the path in the storage bucket where this file will be saved. I'm also adding a timestamp to the file name just to ensure that it's unique. You don't have to do this, but keep in mind that file names need to be unique. Saw if you upload a file to the same location with the same name, the latest one will override the old one. From there, I'll use storage to make a reference to that actual location in the bucket, been calling upload, we'll start the actual file upload to Firebase Storage. It's not an observable. There's no need to subscribe to it, but it does provide bowls that we can use to monitor the progress of the upload. Percentage changes is just a number ranging from 0 to 100 that makes it easy to create a progress bar. Then snapshot changes is an observable that emits an object every few 100 milliseconds with a bunch of data about the file upload. It contains the bytes transferred as well as a bunch of other information, so I recommend you console log it so you can take a closer look. Then RxJS has a finalized operator that runs after this observable is lead it. I've experimented with a few different approaches here, but I think what makes the most sense is just to add an async function that gets the download URL and converts it to a Promise. The reason I like this approach is because we first need this download URL before we can run our update to the Firestore database. And with async await, we can just do this in two lines of code. We first get the download URL and then we make a reference to the files collection and add that document to the database. As a final touch, I'm adding this is active method which will tell us whether or not an upload is currently running. This just makes it easier to disable the cancel and pause buttons based on the state of the upload. Now at this point, we just need to unwrap our Observables in the template. I like to unwrap the Observables inside of n g f and then set the value as a template variable. This allows us to use this percent variable just like a synchronous value in the template. We can set this as the value to our progress bar and then also display the raw value as well. We can unwrap the snapshot in the same way. That'll give us access to the bytes transferred, which we can then compare to the total bytes of the file. And then we can also display our download URL in here as well. But the coolest part is that the AngularFire upload task allows us to control the upload itself. For example, if we want the user to be able to control the upload, we can add a pause button here and then just call task pause to pause it. Then we can do the same thing for cancel and resume. And lastly, we'll use that is active method that we defined earlier to just disable these buttons depending on the current state of the upload. If we go back to the demo and start load in some files, we should get results that look like this. Each individual file will have its own progress indicator, and if we click pause or resume, it should react accordingly. And if we pull up the Firestore database, you should also see the download URL being saved there as well. Hopefully, that gives you a good starting point for your own file uploading system. If this video helped you, please like and subscribe and make sure to grab the full source code from FireShip. Io. Thanks for watching and I will talk to you soon.
When
when
I
i
first
first
got
got
started
started
in
in
web
web
development,
development
cloud
cloud
storage
storage
buckets
buckets
were
were
a
a
relatively
relatively
new
new
technology,
technology
and
and
getting
getting
user
user
generated
generated
files
files
uploaded
uploaded
to
to
the
the
cloud
cloud
was
was
a
a
major
major
pain
pain
point.
point
But
but
luckily
luckily
today
today
we
we
have
have
Firebase
firebase
which
which
makes
makes
this
this
process
process
much
much
easier
easier
but
but
just
just
as
as
flexible
flexible
for
for
the
the
developer.
developer
In
in
today's
today's
video,
video
you'll
you'll
learn
learn
how
how
to
to
build
build
a
a
drop
drop
zone
zone
dial
dial
file
file
uploader
uploader
in
in
Angular,
angular
they
they
can
can
handle
handle
multiple
multiple
concurrent
concurrent
files
files
to
to
Firebase
firebase
Storage.
storage
If
if
you're
you're
new
new
here,
here
like
like
and
and
subscribe
subscribe
and
and
grab
grab
the
the
full
full
source
source
code
code
from
from
Fireship
fireship
IO.
io
I
i
created
created
a
a
similar
similar
video
video
about
about
a
a
year
year
ago,
ago
but
but
the
the
number
number
one
one
request
request
has
has
been
been
a
a
system
system
that
that
handles
handles
multiple
multiple
files
files
concurrently.
concurrently
So,
so
in
in
this
this
demo,
demo
you
you
can
can
drop
drop
as
as
many
many
files
files
as
as
you
you
want
want
onto
onto
the
the
drop
drop
zone,
zone
and
and
then
then
you
you
can
can
pause
pause
or
or
cancel
cancel
each
each
individual
individual
upload.
upload
The
the
cool
cool
thing
thing
is
is
that
that
Firebase
firebase
will
will
handle
handle
all
all
of
of
the
the
concurrency
concurrency
under
under
the
the
hood,
hood
so
so
you
you
can
can
have
have
your
your
users
users
drop
drop
as
as
many
many
files
files
as
as
you
you
want
want
here,
here
and
and
Firebase
firebase
will
will
choose
choose
the
the
best
best
strategy
strategy
to
to
get
get
those
those
files
files
uploaded
uploaded
to
to
the
the
Cloud,
cloud
which
which
is
is
based
based
mostly
mostly
on
on
the
the
user's
user's
network
network
connection.
connection
And
and
another
another
thing
thing
we'll
we'll
do
do
is
is
save
save
the
the
download
download
URL
url
to
to
this
this
file
file
in
in
Firestore.
firestore
This
this
makes
makes
it
it
really
really
easy
easy
to
to
access
access
the
the
raw
raw
file
file
if
if
you're
you're
already
already
using
using
Firestore
firestore
and
and
other
other
parts
parts
of
of
your
your
application.
application
Now,
now
I'm
i'm
going
going
to
to
show
show
you
you
how
how
to
to
build
build
the
the
drop
drop
zone
zone
from
from
scratch
scratch
in
in
Angular,
angular
But,
but
one
one
thing
thing
you
you
should
should
check
check
out
out
is
is
this
this
custom
custom
file
file
drop
drop
element
element
from
from
Google
google
Chrome
chrome
Labs.
labs
It
it
has
has
nothing
nothing
to
to
do
do
with
with
Angular,
angular
but
but
because
because
web
web
components
components
are
are
awesome,
awesome
you
you
can
can
just
just
drop
drop
it
it
in
in
Angular
angular
app
app
and
and
start
start
using
using
it.
it
So
so
this
this
might
might
be
be
a
a
good
good
alternative
alternative
for
for
building
building
your
your
own
own
custom
custom
drop
drop
zone.
zone
Let's
let's
go
go
ahead
ahead
and
and
get
get
started.
started
First,
first
I'm
i'm
assuming
assuming
that
that
you
you
have
have
an
an
Angular
angular
app
app
along
along
with
with
AngularFire
angularfire
and
and
Firebase
firebase
installed.
installed
If
if
we
we
take
take
a
a
look
look
at
at
the
the
app
app
module,
module
you
you
can
can
see
see
I
i
have
have
AngularFire
angularfire
storage
storage
and
and
Firestore.
firestore
And
and
if
if
we
we
take
take
a
a
look
look
at
at
the
the
CSS
css
for
for
this
this
application,
application
we
we
have
have
a
a
drop
drop
zone
zone
class,
class
which
which
is
is
just
just
a
a
flex
flex
box
box
with
with
a
a
border.
border
Then
then
we
we
have
have
a
a
hovering
hovering
class
class
that
that
will
will
change
change
the
the
border
border
from
from
dash
dash
saw
saw
it
it
when
when
the
the
user
user
hovers
hovers
over
over
the
the
box.
box
And
and
all
all
the
the
other
other
styles
styles
come
come
from
from
a
a
framework
framework
called
called
Volma,
volma
which
which
if
if
you're
you're
not
not
familiar
familiar
with,
with
is
is
a
a
cool
cool
alternative
alternative
to
to
Bootstrap
bootstrap
or
or
Material.
material
The
the
first
first
thing
thing
we'll
we'll
do
do
is
is
generate
generate
a
a
directive
directive
that
that
will
will
be
be
able
able
to
to
turn
turn
any
any
div
div
into
into
a
a
drop
drop
zone.
zone
And
and
by
by
drop
drop
zone,
zone
I
i
just
just
mean
mean
an
an
area
area
that
that
the
the
user
user
can
can
drag
drag
and
and
drop
drop
files
files
do
do
and
and
then
then
we
we
can
can
receive
receive
those
those
files
files
as
as
an
an
event
event
in
in
our
our
web
web
application.
application
So
so
we'll
we'll
go
go
ahead
ahead
and
and
call
call
that
that
directive
directive
drop
drop
zone
zone
and
and
its
its
responsibility
responsibility
is
is
to
to
receive
receive
the
the
files
files
and
and
then
then
emit
emit
them
them
up
up
as
as
a
a
custom
custom
event
event
that
that
we
we
can
can
listen
listen
to
to
in
in
other
other
components.
components
In
in
Angular,
angular
we
we
create
create
custom
custom
events
events
by
by
using
using
a
a
combination
combination
of
of
output
output
and
and
event
event
emitter.
emitter
This
this
allows
allows
a
a
parent
parent
component
component
to
to
listen
listen
to
to
events
events
that
that
happen
happen
in
in
this
this
child
child
directive.
directive
In
in
this
this
case
case
here,
here
we're
we're
creating
creating
a
a
custom
custom
event
event
called
called
dropped
dropped
that
that
emits
emits
a
a
file
file
list.
list
And
and
a
a
file
file
list
list
is
is
built
built
into
into
the
the
browser
browser
and
and
it
it
contains
contains
the
the
actual
actual
files
files
that
that
the
the
user
user
dragged
dragged
on
on
to
to
this
this
element.
element
Then
then
we'll
we'll
also
also
emit
emit
a
a
custom
custom
event
event
called
called
hovered
hovered
that
that
will
will
tell
tell
us
us
whether
whether
or
or
not
not
the
the
user
user
is
is
hovering
hovering
over
over
the
the
elements
elements
so
so
we
we
can
can
toggle
toggle
that
that
border.
border
From
from
here,
here
we're
we're
going
going
to
to
use
use
host
host
listener
listener
to
to
intercept
intercept
the
the
drop
drop
event
event
in
in
the
the
DOM.
dom
Drop
drop
will
will
happen
happen
after
after
the
the
user
user
drags
drags
a
a
set
set
of
of
files
files
over
over
to
to
the
the
drop
drop
zone
zone
and
and
then
then
let's
let's
go
go
on
on
the
the
mouse.
mouse
Normally,
normally
this
this
would
would
cause
cause
a
a
new
new
browser
browser
tab
tab
to
to
open,
open
so
so
we
we
call
call
event
event
prevent
prevent
default
default
choose
choose
stop
stop
that
that
from
from
happening,
happening
from
from
there,
there
we
we
want
want
the
the
directive
directive
to
to
emit
emit
the
the
files
files
out
out
as
as
a
a
custom
custom
event.
event
And
and
we
we
can
can
access
access
the
the
files
files
by
by
calling
calling
event
event
data
data
transfer
transfer
files.
files
And
and
we'll
we'll
also
also
go
go
ahead
ahead
and
and
emit
emit
false
false
through
through
our
our
hovered
hovered
event.
event
So
so
that
that
takes
takes
care
care
of
of
the
the
file
file
drop
drop
event.
event
We
we
also
also
wanna
wanna
listen
listen
to
to
drag
drag
over
over
and
and
drag
drag
leave,
leave
then
then
emit
emit
true
true
or
or
false
false
depending
depending
on
on
whether
whether
or
or
not
not
the
the
user
user
is
is
dragging
dragging
over
over
the
the
element.
element
And
and
that
that
takes
takes
care
care
of
of
the
the
entire
entire
directive.
directive
You
you
now
now
have
have
a
a
way
way
to
to
compose
compose
this
this
logic
logic
into
into
any
any
component
component
or
or
element
element
in
in
your
your
Angular
angular
app.
app
Now
now
we
we
can
can
move
move
on
on
to
to
the
the
actual
actual
file
file
uploading
uploading
logic.
logic
Because
because
we
we
want
want
to
to
handle
handle
multiple
multiple
concurrent
concurrent
file
file
uploads,
uploads
we'll
we'll
have
have
a
a
parent
parent
that
that
manages
manages
all
all
of
of
the
the
files
files
that
that
the
the
user
user
dropped
dropped
and
and
then
then
each
each
child
child
component
component
will
will
manage
manage
the
the
actual
actual
upload
upload
of
of
that
that
file.
file
You
you
can
can
see
see
here
here
I've
i've
generated
generated
2
2
new
new
components.
components
1
1
is
is
the
the
uploader,
uploader
that's
that's
the
the
parent,
parent
and
and
then
then
one
one
is
is
the
the
upload
upload
task,
task
that's
that's
the
the
child.
child
Let's
let's
start
start
with
with
the
the
logic
logic
for
for
the
the
parent
parent
component.
component
It's
it's
going
going
to
to
have
have
a
a
property
property
is
is
hovering
hovering
which
which
which
which
we
we
can
can
just
just
use
use
to
to
toggle
toggle
the
the
border
border
on
on
the
the
drop
drop
zone,
zone
and
and
it
it
also
also
has
has
an
an
array
array
of
of
files.
files
1st,
1st
we'll
we'll
define
define
this
this
toggle
toggle
hover
hover
event
event
handler,
handler
which
which
will
will
just
just
flip
flip
that
that
property
property
from
from
true
true
to
to
false.
false
Then
then
the
the
on
on
drop
drop
event
event
handler
handler
takes
takes
the
the
file
file
list
list
as
as
its
its
argument.
argument
The
the
file
file
list
list
contains
contains
all
all
of
of
the
the
files,
files
but
but
it's
it's
not
not
something
something
that
that
we
we
can
can
just
just
loop
loop
over
over
directly
directly
with
with
a
a
for
for
each
each
loop.
loop
So
so
so
so
instead
instead
we
we
have
have
to
to
set
set
up
up
a
a
traditional
traditional
for
for
loop
loop
here
here
and
and
then
then
we'll
we'll
add
add
it
it
to
to
the
the
array
array
of
of
files
files
on
on
this
this
component.
component
The
the
reason
reason
we
we
do
do
this
this
is
is
so
so
we
we
can
can
pass
pass
each
each
individual
individual
file
file
to
to
a
a
child
child
component
component
in
in
the
the
Angular
angular
template.
template
Now
now
we
we
can
can
go
go
into
into
the
the
template
template
and
and
we'll
we'll
set
set
up
up
a
a
div
div
here
here
with
with
our
our
drop
drop
zone
zone
class
class
and
and
then
then
we'll
we'll
add
add
that
that
drop
drop
zone
zone
directive
directive
that
that
we
we
created
created
earlier.
earlier
This
this
gives
gives
us
us
access
access
to
to
the
the
custom
custom
events
events
that
that
we
we
created
created
like
like
hovered
hovered
and
and
on
on
drop.
drop
In
in
Angular
angular
has
has
a
a
built
built
in
in
class
class
directive
directive
that
that
we
we
can
can
use
use
to
to
toggle
toggle
the
the
hovering
hovering
class
class
whenever
whenever
the
the
is
is
hovering
hovering
property
property
is
is
true.
true
We
we
could
could
stop
stop
there
there
and
and
the
the
drag
drag
and
and
drop
drop
feature
feature
would
would
work
work
perfectly
perfectly
fine,
fine
but
but
put
put
it,
it
it's
it's
also
also
a
a
good
good
idea
idea
to
to
add
add
a
a
file
file
input
input
field
field
so
so
users
users
on
on
mobile
mobile
devices
devices
can
can
just
just
click
click
a
a
button
button
to
to
upload,
upload
or
or
for
for
those
those
on
on
desktop
desktop
that
that
just
just
don't
don't
want
want
to
to
drag
drag
and
and
drop.
drop
We
we
can
can
use
use
the
the
same
same
on
on
drop
drop
event
event
handler,
handler
but
but
for
for
the
the
argument,
argument
we'll
we'll
wanna
wanna
pass
pass
the
the
event
event
target
target
files.
files
And
and
the
the
event
event
itself
itself
is
is
the
the
change
change
event
event
on
on
that
that
form
form
input.
input
The
the
last
last
thing
thing
we
we
need
need
to
to
do
do
here
here
is
is
loop
loop
over
over
the
the
array
array
of
of
files.
files
Each
each
file
file
will
will
be
be
passed
passed
as
as
an
an
input
input
property
property
to
to
the
the
child
child
upload
upload
task
task
component.
component
Now
now
it's
it's
time
time
to
to
move
move
on
on
to
to
the
the
upload
upload
task
task
and
and
that's
that's
where
where
we'll
we'll
write
write
the
the
code
code
that
that
actually
actually
uploads
uploads
the
the
file
file
to
to
cloud
cloud
storage.
storage
We'll
we'll
start
start
by
by
importing
importing
our
our
AngularFire
angularfire
dependencies
dependencies
and
and
a
a
few
few
things
things
from
from
RxJS.
rxjs
And
and
in
in
this
this
demo,
demo
we're
we're
going
going
to
to
have
have
the
the
upload
upload
start
start
as
as
soon
soon
as
as
the
the
component
component
is
is
initialized,
initialized
but
but
you
you
could
could
easily
easily
modify
modify
this
this
to
to
make
make
it
it
more
more
lazy
lazy
if
if
you
you
want
want
the
the
user
user
to
to
push
push
a
a
button
button
first
first
before
before
it
it
actually
actually
uploads
uploads
the
the
file.
file
1st,
1st
we
we
decorate
decorate
the
the
file
file
property
property
with
with
input
input
so
so
it
it
can
can
be
be
passed
passed
down
down
from
from
the
the
parent
parent
component.
component
Then
then
we
we
have
have
the
the
AngularFire
angularfire
upload
upload
task
task
which
which
does
does
most
most
of
of
the
the
magic
magic
for
for
the
the
file
file
upload
upload
itself.
itself
Then
then
while
while
the
the
file
file
is
is
uploading,
uploading
it
it
provides
provides
a
a
couple
couple
of
of
different
different
observables
observables
that
that
we
we
can
can
listen
listen
to
to
do
do
monitor
monitor
the
the
progress,
progress
percentage
percentage
and
and
snapshot
snapshot
will
will
help
help
us
us
do
do
that,
that
then
then
we'll
we'll
also
also
display
display
the
the
download
download
URL
url
for
for
the
the
file
file
when
when
the
the
upload
upload
is
is
complete.
complete
From
from
there,
there
we'll
we'll
add
add
our
our
dependencies
dependencies
to
to
the
the
constructor,
constructor
which
which
are
are
Angular
angular
Fire
fire
Storage
storage
and
and
DB
db
for
for
Firestore.
firestore
Then
then
we'll
we'll
define
define
the
the
upload
upload
logic
logic
in
in
its
its
own
own
method
method
and
and
then
then
run
run
that
that
method
method
as
as
soon
soon
as
as
the
the
components
components
initialized.
initialized
And
and
again
again
you
you
could
could
extract
extract
that
that
out
out
to
to
a
a
button
button
if
if
you
you
want
want
to
to
make
make
it
it
a
a
lazy
lazy
upload.
upload
The
the
first
first
step
step
is
is
to
to
define
define
the
the
path
path
in
in
the
the
storage
storage
bucket
bucket
where
where
this
this
file
file
will
will
be
be
saved.
saved
I'm
i'm
also
also
adding
adding
a
a
timestamp
timestamp
to
to
the
the
file
file
name
name
just
just
to
to
ensure
ensure
that
that
it's
it's
unique.
unique
You
you
don't
don't
have
have
to
to
do
do
this,
this
but
but
keep
keep
in
in
mind
mind
that
that
file
file
names
names
need
need
to
to
be
be
unique.
unique
Saw
saw
if
if
you
you
upload
upload
a
a
file
file
to
to
the
the
same
same
location
location
with
with
the
the
same
same
name,
name
the
the
latest
latest
one
one
will
will
override
override
the
the
old
old
one.
one
From
from
there,
there
I'll
i'll
use
use
storage
storage
to
to
make
make
a
a
reference
reference
to
to
that
that
actual
actual
location
location
in
in
the
the
bucket,
bucket
been
been
calling
calling
upload,
upload
we'll
we'll
start
start
the
the
actual
actual
file
file
upload
upload
to
to
Firebase
firebase
Storage.
storage
It's
it's
not
not
an
an
observable.
observable
There's
there's
no
no
need
need
to
to
subscribe
subscribe
to
to
it,
it
but
but
it
it
does
does
provide
provide
bowls
bowls
that
that
we
we
can
can
use
use
to
to
monitor
monitor
the
the
progress
progress
of
of
the
the
upload.
upload
Percentage
percentage
changes
changes
is
is
just
just
a
a
number
number
ranging
ranging
from
from
0
0
to
to
100
100
that
that
makes
makes
it
it
easy
easy
to
to
create
create
a
a
progress
progress
bar.
bar
Then
then
snapshot
snapshot
changes
changes
is
is
an
an
observable
observable
that
that
emits
emits
an
an
object
object
every
every
few
few
100
100
milliseconds
milliseconds
with
with
a
a
bunch
bunch
of
of
data
data
about
about
the
the
file
file
upload.
upload
It
it
contains
contains
the
the
bytes
bytes
transferred
transferred
as
as
well
well
as
as
a
a
bunch
bunch
of
of
other
other
information,
information
so
so
I
i
recommend
recommend
you
you
console
console
log
log
it
it
so
so
you
you
can
can
take
take
a
a
closer
closer
look.
look
Then
then
RxJS
rxjs
has
has
a
a
finalized
finalized
operator
operator
that
that
runs
runs
after
after
this
this
observable
observable
is
is
lead
lead
it.
it
I've
i've
experimented
experimented
with
with
a
a
few
few
different
different
approaches
approaches
here,
here
but
but
I
i
think
think
what
what
makes
makes
the
the
most
most
sense
sense
is
is
just
just
to
to
add
add
an
an
async
async
function
function
that
that
gets
gets
the
the
download
download
URL
url
and
and
converts
converts
it
it
to
to
a
a
Promise.
promise
The
the
reason
reason
I
i
like
like
this
this
approach
approach
is
is
because
because
we
we
first
first
need
need
this
this
download
download
URL
url
before
before
we
we
can
can
run
run
our
our
update
update
to
to
the
the
Firestore
firestore
database.
database
And
and
with
with
async
async
await,
await
we
we
can
can
just
just
do
do
this
this
in
in
two
two
lines
lines
of
of
code.
code
We
we
first
first
get
get
the
the
download
download
URL
url
and
and
then
then
we
we
make
make
a
a
reference
reference
to
to
the
the
files
files
collection
collection
and
and
add
add
that
that
document
document
to
to
the
the
database.
database
As
as
a
a
final
final
touch,
touch
I'm
i'm
adding
adding
this
this
is
is
active
active
method
method
which
which
will
will
tell
tell
us
us
whether
whether
or
or
not
not
an
an
upload
upload
is
is
currently
currently
running.
running
This
this
just
just
makes
makes
it
it
easier
easier
to
to
disable
disable
the
the
cancel
cancel
and
and
pause
pause
buttons
buttons
based
based
on
on
the
the
state
state
of
of
the
the
upload.
upload
Now
now
at
at
this
this
point,
point
we
we
just
just
need
need
to
to
unwrap
unwrap
our
our
Observables
observables
in
in
the
the
template.
template
I
i
like
like
to
to
unwrap
unwrap
the
the
Observables
observables
inside
inside
of
of
n
n
g
g
f
f
and
and
then
then
set
set
the
the
value
value
as
as
a
a
template
template
variable.
variable
This
this
allows
allows
us
us
to
to
use
use
this
this
percent
percent
variable
variable
just
just
like
like
a
a
synchronous
synchronous
value
value
in
in
the
the
template.
template
We
we
can
can
set
set
this
this
as
as
the
the
value
value
to
to
our
our
progress
progress
bar
bar
and
and
then
then
also
also
display
display
the
the
raw
raw
value
value
as
as
well.
well
We
we
can
can
unwrap
unwrap
the
the
snapshot
snapshot
in
in
the
the
same
same
way.
way
That'll
that'll
give
give
us
us
access
access
to
to
the
the
bytes
bytes
transferred,
transferred
which
which
we
we
can
can
then
then
compare
compare
to
to
the
the
total
total
bytes
bytes
of
of
the
the
file.
file
And
and
then
then
we
we
can
can
also
also
display
display
our
our
download
download
URL
url
in
in
here
here
as
as
well.
well
But
but
the
the
coolest
coolest
part
part
is
is
that
that
the
the
AngularFire
angularfire
upload
upload
task
task
allows
allows
us
us
to
to
control
control
the
the
upload
upload
itself.
itself
For
for
example,
example
if
if
we
we
want
want
the
the
user
user
to
to
be
be
able
able
to
to
control
control
the
the
upload,
upload
we
we
can
can
add
add
a
a
pause
pause
button
button
here
here
and
and
then
then
just
just
call
call
task
task
pause
pause
to
to
pause
pause
it.
it
Then
then
we
we
can
can
do
do
the
the
same
same
thing
thing
for
for
cancel
cancel
and
and
resume.
resume
And
and
lastly,
lastly
we'll
we'll
use
use
that
that
is
is
active
active
method
method
that
that
we
we
defined
defined
earlier
earlier
to
to
just
just
disable
disable
these
these
buttons
buttons
depending
depending
on
on
the
the
current
current
state
state
of
of
the
the
upload.
upload
If
if
we
we
go
go
back
back
to
to
the
the
demo
demo
and
and
start
start
load
load
in
in
some
some
files,
files
we
we
should
should
get
get
results
results
that
that
look
look
like
like
this.
this
Each
each
individual
individual
file
file
will
will
have
have
its
its
own
own
progress
progress
indicator,
indicator
and
and
if
if
we
we
click
click
pause
pause
or
or
resume,
resume
it
it
should
should
react
react
accordingly.
accordingly
And
and
if
if
we
we
pull
pull
up
up
the
the
Firestore
firestore
database,
database
you
you
should
should
also
also
see
see
the
the
download
download
URL
url
being
being
saved
saved
there
there
as
as
well.
well
Hopefully,
hopefully
that
that
gives
gives
you
you
a
a
good
good
starting
starting
point
point
for
for
your
your
own
own
file
file
uploading
uploading
system.
system
If
if
this
this
video
video
helped
helped
you,
you
please
please
like
like
and
and
subscribe
subscribe
and
and
make
make
sure
sure
to
to
grab
grab
the
the
full
full
source
source
code
code
from
from
FireShip.
fireship
Io.
io
Thanks
thanks
for
for
watching
watching
and
and
I
i
will
will
talk
talk
to
to
you
you
soon.
soon
success
The speakers discuss building drop zone dial files in Angular, including the use of ante and the use of a framework called Volma. They also explain how to create a parent component for each file and access and manipulate the file upload process. The process involves decorating input and output property, importing dependencies, and setting up the upload process. The importance of disabling buttons based on the current state of the upload is also discussed. Finally, they discuss the use of async await and the importance of disabling buttons based on the current state of the upload process.
Multiple Concurrent File Uploads with Firebase Storage + Angular
When I first got started in web development, cloud storage buckets were a relatively new technology, and getting user generated files uploaded to the cloud was a major pain point. But luckily today we have Firebase which makes this process much easier but just as flexible for the developer. In today's video, you'll learn how to build a drop zone dial file uploader in Angular, they can handle multiple concurrent files to Firebase Storage. If you're new here, like and subscribe and grab the full source code from Fireship IO. I created a similar video about a year ago, but the number one request has been a system that handles multiple files concurrently. So, in this demo, you can drop as many files as you want onto the drop zone, and then you can pause or cancel each individual upload. The cool thing is that Firebase will handle all of the concurrency under the hood, so you can have your users drop as many files as you want here, and Firebase will choose the best strategy to get those files uploaded to the Cloud, which is based mostly on the user's network connection. And another thing we'll do is save the download URL to this file in Firestore. This makes it really easy to access the raw file if you're already using Firestore and other parts of your application. Now, I'm going to show you how to build the drop zone from scratch in Angular, But, one thing you should check out is this custom file drop element from Google Chrome Labs. It has nothing to do with Angular, but because web components are awesome, you can just drop it in Angular app and start using it. So this might be a good alternative for building your own custom drop zone. Let's go ahead and get started. First, I'm assuming that you have an Angular app along with AngularFire and Firebase installed. If we take a look at the app module, you can see I have AngularFire storage and Firestore. And if we take a look at the CSS for this application, we have a drop zone class, which is just a flex box with a border. Then we have a hovering class that will change the border from dash saw it when the user hovers over the box. And all the other styles come from a framework called Volma, which if you're not familiar with, is a cool alternative to Bootstrap or Material. The first thing we'll do is generate a directive that will be able to turn any div into a drop zone. And by drop zone, I just mean an area that the user can drag and drop files do and then we can receive those files as an event in our web application. So we'll go ahead and call that directive drop zone and its responsibility is to receive the files and then emit them up as a custom event that we can listen to in other components. In Angular, we create custom events by using a combination of output and event emitter. This allows a parent component to listen to events that happen in this child directive. In this case here, we're creating a custom event called dropped that emits a file list. And a file list is built into the browser and it contains the actual files that the user dragged on to this element. Then we'll also emit a custom event called hovered that will tell us whether or not the user is hovering over the elements so we can toggle that border. From here, we're going to use host listener to intercept the drop event in the DOM. Drop will happen after the user drags a set of files over to the drop zone and then let's go on the mouse. Normally, this would cause a new browser tab to open, so we call event prevent default choose stop that from happening, from there, we want the directive to emit the files out as a custom event. And we can access the files by calling event data transfer files. And we'll also go ahead and emit false through our hovered event. So that takes care of the file drop event. We also wanna listen to drag over and drag leave, then emit true or false depending on whether or not the user is dragging over the element. And that takes care of the entire directive. You now have a way to compose this logic into any component or element in your Angular app. Now we can move on to the actual file uploading logic. Because we want to handle multiple concurrent file uploads, we'll have a parent that manages all of the files that the user dropped and then each child component will manage the actual upload of that file. You can see here I've generated 2 new components. 1 is the uploader, that's the parent, and then one is the upload task, that's the child. Let's start with the logic for the parent component. It's going to have a property is hovering which which we can just use to toggle the border on the drop zone, and it also has an array of files. 1st, we'll define this toggle hover event handler, which will just flip that property from true to false. Then the on drop event handler takes the file list as its argument. The file list contains all of the files, but it's not something that we can just loop over directly with a for each loop. So so instead we have to set up a traditional for loop here and then we'll add it to the array of files on this component. The reason we do this is so we can pass each individual file to a child component in the Angular template. Now we can go into the template and we'll set up a div here with our drop zone class and then we'll add that drop zone directive that we created earlier. This gives us access to the custom events that we created like hovered and on drop. In Angular has a built in class directive that we can use to toggle the hovering class whenever the is hovering property is true. We could stop there and the drag and drop feature would work perfectly fine, but put it, it's also a good idea to add a file input field so users on mobile devices can just click a button to upload, or for those on desktop that just don't want to drag and drop. We can use the same on drop event handler, but for the argument, we'll wanna pass the event target files. And the event itself is the change event on that form input. The last thing we need to do here is loop over the array of files. Each file will be passed as an input property to the child upload task component. Now it's time to move on to the upload task and that's where we'll write the code that actually uploads the file to cloud storage. We'll start by importing our AngularFire dependencies and a few things from RxJS. And in this demo, we're going to have the upload start as soon as the component is initialized, but you could easily modify this to make it more lazy if you want the user to push a button first before it actually uploads the file. 1st, we decorate the file property with input so it can be passed down from the parent component. Then we have the AngularFire upload task which does most of the magic for the file upload itself. Then while the file is uploading, it provides a couple of different observables that we can listen to do monitor the progress, percentage and snapshot will help us do that, then we'll also display the download URL for the file when the upload is complete. From there, we'll add our dependencies to the constructor, which are Angular Fire Storage and DB for Firestore. Then we'll define the upload logic in its own method and then run that method as soon as the components initialized. And again you could extract that out to a button if you want to make it a lazy upload. The first step is to define the path in the storage bucket where this file will be saved. I'm also adding a timestamp to the file name just to ensure that it's unique. You don't have to do this, but keep in mind that file names need to be unique. Saw if you upload a file to the same location with the same name, the latest one will override the old one. From there, I'll use storage to make a reference to that actual location in the bucket, been calling upload, we'll start the actual file upload to Firebase Storage. It's not an observable. There's no need to subscribe to it, but it does provide bowls that we can use to monitor the progress of the upload. Percentage changes is just a number ranging from 0 to 100 that makes it easy to create a progress bar. Then snapshot changes is an observable that emits an object every few 100 milliseconds with a bunch of data about the file upload. It contains the bytes transferred as well as a bunch of other information, so I recommend you console log it so you can take a closer look. Then RxJS has a finalized operator that runs after this observable is lead it. I've experimented with a few different approaches here, but I think what makes the most sense is just to add an async function that gets the download URL and converts it to a Promise. The reason I like this approach is because we first need this download URL before we can run our update to the Firestore database. And with async await, we can just do this in two lines of code. We first get the download URL and then we make a reference to the files collection and add that document to the database. As a final touch, I'm adding this is active method which will tell us whether or not an upload is currently running. This just makes it easier to disable the cancel and pause buttons based on the state of the upload. Now at this point, we just need to unwrap our Observables in the template. I like to unwrap the Observables inside of n g f and then set the value as a template variable. This allows us to use this percent variable just like a synchronous value in the template. We can set this as the value to our progress bar and then also display the raw value as well. We can unwrap the snapshot in the same way. That'll give us access to the bytes transferred, which we can then compare to the total bytes of the file. And then we can also display our download URL in here as well. But the coolest part is that the AngularFire upload task allows us to control the upload itself. For example, if we want the user to be able to control the upload, we can add a pause button here and then just call task pause to pause it. Then we can do the same thing for cancel and resume. And lastly, we'll use that is active method that we defined earlier to just disable these buttons depending on the current state of the upload. If we go back to the demo and start load in some files, we should get results that look like this. Each individual file will have its own progress indicator, and if we click pause or resume, it should react accordingly. And if we pull up the Firestore database, you should also see the download URL being saved there as well. Hopefully, that gives you a good starting point for your own file uploading system. If this video helped you, please like and subscribe and make sure to grab the full source code from FireShip. Io. Thanks for watching and I will talk to you soon.
The speakers discuss building drop zone dial files in Angular, including the use of ante and the use of a framework called Volma. They also explain how to create a parent component for each file and access and manipulate the file upload process. The process involves decorating input and output property, importing dependencies, and setting up the upload process. The importance of disabling buttons based on the current state of the upload is also discussed. Finally, they discuss the use of async await and the importance of disabling buttons based on the current state of the upload process.