File uploads come to AngularFire
Cloud Storage for Firebase is a serverless way to upload and download binary files straight from the browser. As of today, it’s officially supported by AngularFire. Adding AngularFire to your app allows you to easily and securely manage a Cloud Storage bucket. All without a line of server code.
Get ready, uploading files from your Angular app just got a lot easier.
AngularFire, meet Cloud Storage
If you’re not familiar with AngularFire, it’s the official Angular library for Firebase. AngularFire combines the power of Angular, Firebase, and RxJS to act as your serverless backend. It includes modules for the Realtime Database, Firebase Authentication, Cloud Firestore, and today it supports Cloud Storage.
Adding AngularFire to your project is easy. Install Firebase and AngularFire from npm:
npm i firebase angularfire2
Then add it to your NgModule:
Inject the AngularFireStorage
module into your component.
Now you’re ready to manage your files from Cloud Storage without a server of your own.
The foundation of a file upload
The primary way of uploading files on the web is through the <input type="file">
tag.
<label for="file">File:</label>
<input type="file" (change)="upload($event)" accept=".png,.jpg" />
This tag fires a (change)
event when the user selects a file. It even allows you to restrict the user from uploading undesired formats with the accept
attribute (beware that this is only a client restriction, we’ll cover server restrictions later). Event bindings in Angular make it easy to handle a (change)
event and send the file to Cloud Storage.
The sample above creates an AngularFireStorageReference
with a randomly generated Id. This reference controls a path in your Cloud Storage bucket. Creating a reference doesn’t initiate an upload, but it allows to start one as well as delete the file saved at that location. Calling .put()
on a reference with a Blob
beings the upload to Cloud Storage.
You may have noticed that creating a reference and calling.put()
is the longer way of callingafStorage.upload(path, blog)
shown above. Under the hood theafStorage.upload()
method creates a reference, calls.put()
, and returns theAngularFireUploadTask
for you.
The AngularFireUploadTask
is how you’ll monitor the upload progress.
Reactive upload methods
The web platform provides an easy and accessible way of displaying the progress of any given task. This is done through the aptly named <progress>
element.
<progress max="100" [value]="(uploadProgress | async)"></progress>
The progress element’s value
attribute is easy to control with Angular’s property binding. AngularFire provides an upload observable that you can pipe in the new value as it changes.
The .snapshotChanges()
method on an AngularFireUploadTask
returns an object with helpful metadata about the upload. Properties such as the totalBytesTransferred
, totalBytes
in the upload, any metadata
provided, the state
of the upload, and the downloadURL
of the file once uploaded. Using this metadata you can update the UI to show the progress.
Most of the time your UI will display the upload percentage and download url. Since this a common task, we made this a bit easier with two helpful methods: .percentageChanges()
and .downloadURL()
.
Instead of calculating the changes yourself, the .percentageChanges()
observable does the work for you. The .downloadURL()
observable emits the download URL string once the upload is completed. This simplifies binding this information to your UI.
The best part of these observable methods is that you don’t need to worry about complex mapping or multiple .subscribe()
calls in your component code. Just bind them to the async
pipe and your users are watching their file upload progress.
But what if your user changes their mind? What if they want to pause their upload because they’re no longer on a WiFi network? Will they be able to resume when they want? What if they want to cancel the upload all together?
Controlling uploads
A user should be able to pause, resume, or cancel an upload in progress. If or when their upload completes they should be able to delete it as well.
An AngularFireUploadTask
contains the following appropriately named methods: .pause()
, .resume()
, and .cancel()
. In the sample above, the component stores the task as an instance property. This allows you to call it from your template:
Ideally you’ll want to update your UI so the user knows the state of their upload. The .snapshotChanges()
observable emits this information through the state property.
When the user taps “Pause”, the 'paused'
state emits from the observable. When the user taps “Resume”, the 'running'
state emits. And of course, when the “Pause” button is tapped, the 'paused'
state emits.
The template above will disable each button depending on the state. A user can cancel a 'running'
upload, but they can’t click “Resume” unless the state is 'paused'
.
Binding the UI to the upload state simplifies your templates because you don’t have to manage stateful properties on your component like: isPaused
, isUploading
, and isFinished
. The state emits from the observable and you bind the expression in your template.
Simple downloads
Downloading files from Cloud Storage is real simple with AngularFireStorage
. The .getDownloadURL()
method on an AngularFireStorageReference
returns an observable of a download URL.
Combining the .getDownloadURL()
method with the *ngIf
directive and async
pipe allows you to display the image once it’s downloaded.
Just because uploading and downloading files is easy, it doesn’t mean we can’t secure them from unauthorized access.
Secure your files
Cloud Storage for Firebase comes with a server security rule set. These security rules ensures the proper file formats are uploaded and only the right users have access to the right files.
The <input type="file" access=".png,.jpg">
tag restricts file uploads to .png
and .jpg
. However, this a client only restriction. It has nothing to do with what Cloud Storage will accept. To secure your storage bucket you need to write rules that only allow images to be uploaded at the /images
path.
The rules above will let anyone read from the /images
path, but only upload a file if it has an 'image/.*'
content type (.png, .jpg, .jpeg, etc…) and is less than 5MB.
Get started and even contribute!
Get started by checking out our Github repo and the official documentation. AngularFire and the Cloud Storage SDK are each open source projects. If you want to get involved in the project make sure to check out our open issue or file one yourself!