In this tutorial, we are going to learn how to upload an image to Firebase Cloud Storage from an Angular Project. We’ll be using AngularFire library for setting up Firebase in the Angular web application.
Firebase is Google's mobile platform that helps you quickly develop high-quality apps and grow your business.
Table of Contents
- Prerequisites
- Setup Angular Project using Angular CLI
- Setup Firebase (AngularFire library) in Angular
- Create a firebase project
- Project
- Conclusion
Prerequisite
To work with this demo, you must have Node.js and Angular CLI installed on your system. If you are a beginner then you should check out this link to Download node.js
Enter the command below in your terminal to install the latest version of Angular CLI:
npm install @angular/cli -g
Create an angular project
To create a new Angular project, run the following:
ng new cloudstorage
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? CSS
cd cloudstorage
This command does the initial setup for our Angular projects and installs the dependencies specified in package.json. Then we switch to the new project directory.
Setup AngularFire library in your Angular Project
The next step is to install AngularFire library. On your terminal, run this:
npm install firebase @angular/fire --save
Once you are done with setting up the angular project next step is to create a connection between firebase and your angular project.
Create a firebase project
Go to Firebase console and create a new project.
Afterward, enter your project name, accept the terms and condition and click on create a project button.
Once your project is set up, click on your project and you’ll see your admin dashboard. Click project overview > project settings > add app. click on add app button, and fill in the necessary details and your firebase credentials will appear.
Copy your firebase credentials and open your Angular app. Go to src/environments/enviorment.ts and enviorment.prod.ts files in your project folder. Then add your firebase configuration details in both the environment files as shown below.
Now, import AngularFireModule and environment.ts in app.module.ts file, then declare AngularFireModule into the import array.
You can optionally use your FirebaseApp name with the itializeApp method
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { HttpClientModule } from "@angular/common/http";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { AngularFireModule } from "@angular/fire";
import { environment } from "../environments/environment";
import {
AngularFireStorageModule,
AngularFireStorageReference,
AngularFireUploadTask,
StorageBucket
} from "@angular/fire/storage";
import { ApiService } from "./services/api.service";
@NgModule({
declarations: [AppComponent],
imports: [
HttpClientModule,
BrowserModule,
AppRoutingModule,
AngularFireStorageModule,
AngularFireModule.initializeApp(environment.firebaseConfig, "cloud")
],
providers: [
ApiService,
{ provide: StorageBucket, useValue: "your" }
],
bootstrap: [AppComponent]
})
export class AppModule {}
Now you are all set to use Firebase storage in your Angular App. Let’s move over to our app.component.html. You can delete all the default code init except this code below.
<router-outlet> </router-outlet>
then we can now add our input tag which we will use to select our file from our computer and bind it to a function whenever the file selected changes.
<div class="form-group col-12">
<input type="file"
id="file"
#userPhoto
(change)="onFileSelected($event)"
name="image"
autocomplete="off"
/>
</div>
<router-outlet> </router-outlet>
We now write the javascript code that will run the upload method in our app.component.ts
app.component.ts
import { Component } from "@angular/core";
import { ApiService } from "./services/api.service";
import { AngularFireStorage } from "@angular/fire/storage";
import { map, finalize } from "rxjs/operators";
import { Observable } from "rxjs";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.scss"]
})
export class AppComponent {
title = "cloudsSorage";
selectedFile: File = null;
fb;
downloadURL: Observable<string>;
constructor(private Api: ApiService, private storage: AngularFireStorage) {}
ngOnInit() {}
onFileSelected(event) {
var n = Date.now();
const file = event.target.files[0];
const filePath = `RoomsImages/${n}`;
const fileRef = this.storage.ref(filePath);
const task = this.storage.upload(`RoomsImages/${n}`, file);
task
.snapshotChanges()
.pipe(
finalize(() => {
this.downloadURL = fileRef.getDownloadURL();
this.downloadURL.subscribe(url => {
if (url) {
this.fb = url;
}
console.log(this.fb);
});
})
)
.subscribe(url => {
if (url) {
console.log(url);
}
});
}
}
To upload a file to cloud storage you first create a reference to the full path of the file, including the file name.
In the above code, we start by declaring a variable to hold the filePath where the images will be stored in the cloud and we declared another variable fileRef which points to the path where the image is stored and the task variable holds different properties of the upload state like the total bytes of the file to upload, how many bytes have been uploaded and more. We can use these to upload a progress bar to notify the user of how much of the file has been uploaded. After that, we get the image URL by calling .getDownloadURL() and we can now pass it to our API endpoint.
If everything was done correctly, our app will be ready to make our first upload. We can test it to know if our code is working by running:
ng serve -o
If our app is done serving you can now open the app in your browser using this URL: Localhost:4200 after that open your dev tool to see how the upload run and after running.
If you don't see that in your console, you might have missed a step. Look through the steps again to see what you are missing out. But if you see that it means your code is working and if you go to your firebase storage, you will see the image you uploaded.
Project Files
Click on the below button to get the code files from Git repo.
github
Conclusion
In this tutorial, we talked about Google Firebase Cloud Storage and its powerful features. We have learned how to create a firebase project. How to setup firebase services in your Angular project, and how to upload an image to Firebase Cloud Storage. I hope you love this tutorial. If you find this article useful share it to reach others.
Top comments (6)
You saved my life literally!
thank you :)
I have some trouble during upload pls help, I attached screenshot
zone.js:3243 POST firebasestorage.googleapis.com/v0/... 403
scheduleTask @ zone.js:3243
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:410
onScheduleTask @ zone.js:301
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:404
push../node_modules/zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:238
push../node_modules/zone.js/dist/zone.js.Zone.scheduleMacroTask @ zone.js:261
scheduleMacroTaskWithCurrentZone @ zone.js:1245
(anonymous) @ zone.js:3276
proto. @ zone.js:1569
push../node_modules/@firebase/storage/dist/index.esm.js.NetworkXhrIo.send @ index.esm.js:703
doTheRequest @ index.esm.js:3169
(anonymous) @ index.esm.js:3026
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:423
onInvokeTask @ core.js:17290
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:422
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:195
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:498
ZoneTask.invoke @ zone.js:487
timer @ zone.js:2281
setTimeout (async)
scheduleTask @ zone.js:2302
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:410
onScheduleTask @ zone.js:301
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:404
push../node_modules/zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:238
push../node_modules/zone.js/dist/zone.js.Zone.scheduleMacroTask @ zone.js:261
scheduleMacroTaskWithCurrentZone @ zone.js:1245
(anonymous) @ zone.js:2317
proto. @ zone.js:1569
callWithDelay @ index.esm.js:3024
start @ index.esm.js:3082
push../node_modules/@firebase/storage/dist/index.esm.js.NetworkRequest.start_ @ index.esm.js:3238
(anonymous) @ index.esm.js:3143
ZoneAwarePromise @ zone.js:910
make @ index.esm.js:558
NetworkRequest @ index.esm.js:3140
makeRequest @ index.esm.js:3303
push../node_modules/@firebase/storage/dist/index.esm.js.AuthWrapper.makeRequest @ index.esm.js:2952
(anonymous) @ index.esm.js:2254
(anonymous) @ index.esm.js:2149
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:391
onInvoke @ core.js:17299
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:390
push../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:150
(anonymous) @ zone.js:889
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:423
onInvokeTask @ core.js:17290
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:422
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:195
drainMicroTaskQueue @ zone.js:601
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:502
invokeTask @ zone.js:1744
globalZoneAwareCallback @ zone.js:1770
Show 22 more frames
core.js:15724 ERROR FirebaseStorageError {code_: "storage/unauthorized", message_: "Firebase Storage: User does not have permission to access 'RoomsImages/1596705165294'.", serverResponse_: "{↵ "error": {↵ "code": 403,↵ "message": "Pe…n denied. Could not perform this operation"↵ }↵}", name_: "FirebaseError"}
defaultErrorLogger @ core.js:15724
push../node_modules/@angular/core/fesm5/core.js.ErrorHandler.handleError @ core.js:15772
next @ core.js:17771
schedulerFn @ core.js:13515
push../node_modules/rxjs/esm5/internal/Subscriber.js.SafeSubscriber.tryOrUnsub @ Subscriber.js:194
push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next @ Subscriber.js:132
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next @ Subscriber.js:76
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next @ Subscriber.js:53
push../node_modules/rxjs/_esm5/internal/Subject.js.Subject.next @ Subject.js:47
push../node_modules/@angular/core/fesm5/core.js.EventEmitter.emit @ core.js:13499
(anonymous) @ core.js:17321
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:391
push../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:150
push../node_modules/@angular/core/fesm5/core.js.NgZone.runOutsideAngular @ core.js:17258
onHandleError @ core.js:17321
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.handleError @ zone.js:395
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:198
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:498
ZoneTask.invoke @ zone.js:487
timer @ zone.js:2281
setTimeout (async)
scheduleTask @ zone.js:2302
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:410
onScheduleTask @ zone.js:301
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:404
push../node_modules/zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:238
push../node_modules/zone.js/dist/zone.js.Zone.scheduleMacroTask @ zone.js:261
scheduleMacroTaskWithCurrentZone @ zone.js:1245
(anonymous) @ zone.js:2317
proto. @ zone.js:1569
hostReportError @ hostReportError.js:3
push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.error @ Subscriber.js:166
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._error @ Subscriber.js:79
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.error @ Subscriber.js:59
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._error @ Subscriber.js:79
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.error @ Subscriber.js:59
error @ fromTask.js:5
(anonymous) @ index.esm.js:2020
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:391
onInvoke @ core.js:17299
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:390
push../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:150
(anonymous) @ zone.js:889
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:423
onInvokeTask @ core.js:17290
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:422
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:195
drainMicroTaskQueue @ zone.js:601
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:502
invokeTask @ zone.js:1744
globalZoneAwareCallback @ zone.js:1781
load (async)
customScheduleGlobal @ zone.js:1883
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:410
onScheduleTask @ zone.js:301
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:404
push../node_modules/zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:238
push../node_modules/zone.js/dist/zone.js.Zone.scheduleEventTask @ zone.js:264
(anonymous) @ zone.js:2054
(anonymous) @ index.esm.js:681
ZoneAwarePromise @ zone.js:910
make @ index.esm.js:558
NetworkXhrIo @ index.esm.js:672
push../node_modules/@firebase/storage/dist/index.esm.js.XhrIoPool.createXhrIo @ index.esm.js:797
doTheRequest @ index.esm.js:3156
(anonymous) @ index.esm.js:3026
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:423
onInvokeTask @ core.js:17290
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:422
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:195
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:498
ZoneTask.invoke @ zone.js:487
timer @ zone.js:2281
setTimeout (async)
scheduleTask @ zone.js:2302
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:410
onScheduleTask @ zone.js:301
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:404
push../node_modules/zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:238
push../node_modules/zone.js/dist/zone.js.Zone.scheduleMacroTask @ zone.js:261
scheduleMacroTaskWithCurrentZone @ zone.js:1245
(anonymous) @ zone.js:2317
proto. @ zone.js:1569
callWithDelay @ index.esm.js:3024
start @ index.esm.js:3082
push../node_modules/@firebase/storage/dist/index.esm.js.NetworkRequest.start @ index.esm.js:3238
(anonymous) @ index.esm.js:3143
ZoneAwarePromise @ zone.js:910
make @ index.esm.js:558
NetworkRequest @ index.esm.js:3140
makeRequest @ index.esm.js:3303
push../node_modules/@firebase/storage/dist/index.esm.js.AuthWrapper.makeRequest @ index.esm.js:2952
(anonymous) @ index.esm.js:2254
(anonymous) @ index.esm.js:2149
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:391
onInvoke @ core.js:17299
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:390
push../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:150
(anonymous) @ zone.js:889
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:423
onInvokeTask @ core.js:17290
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:422
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:195
drainMicroTaskQueue @ zone.js:601
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:502
invokeTask @ zone.js:1744
globalZoneAwareCallback @ zone.js:1770
Show 33 more frames
zone.js:3243 GET firebasestorage.googleapis.com/v0/... 403
scheduleTask @ zone.js:3243
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:410
push../node_modules/zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:238
push../node_modules/zone.js/dist/zone.js.Zone.scheduleMacroTask @ zone.js:261
scheduleMacroTaskWithCurrentZone @ zone.js:1245
(anonymous) @ zone.js:3276
proto. @ zone.js:1569
push../node_modules/@firebase/storage/dist/index.esm.js.NetworkXhrIo.send @ index.esm.js:706
doTheRequest @ index.esm.js:3169
(anonymous) @ index.esm.js:3026
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:423
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:195
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:498
ZoneTask.invoke @ zone.js:487
timer @ zone.js:2281
setTimeout (async)
scheduleTask @ zone.js:2302
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:410
push../node_modules/zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:238
push../node_modules/zone.js/dist/zone.js.Zone.scheduleMacroTask @ zone.js:261
scheduleMacroTaskWithCurrentZone @ zone.js:1245
(anonymous) @ zone.js:2317
proto. @ zone.js:1569
callWithDelay @ index.esm.js:3024
start @ index.esm.js:3082
push../node_modules/@firebase/storage/dist/index.esm.js.NetworkRequest.start_ @ index.esm.js:3238
(anonymous) @ index.esm.js:3143
ZoneAwarePromise @ zone.js:910
make @ index.esm.js:558
NetworkRequest @ index.esm.js:3140
makeRequest @ index.esm.js:3303
push../node_modules/@firebase/storage/dist/index.esm.js.AuthWrapper.makeRequest @ index.esm.js:2952
(anonymous) @ index.esm.js:2780
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:391
push../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:150
(anonymous) @ zone.js:889
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:423
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:195
drainMicroTaskQueue @ zone.js:601
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:502
invokeTask @ zone.js:1744
globalZoneAwareCallback @ zone.js:1781
load (async)
customScheduleGlobal @ zone.js:1883
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:410
onScheduleTask @ zone.js:301
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:404
push../node_modules/zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:238
push../node_modules/zone.js/dist/zone.js.Zone.scheduleEventTask @ zone.js:264
(anonymous) @ zone.js:2054
(anonymous) @ index.esm.js:681
ZoneAwarePromise @ zone.js:910
make @ index.esm.js:558
NetworkXhrIo @ index.esm.js:672
push../node_modules/@firebase/storage/dist/index.esm.js.XhrIoPool.createXhrIo @ index.esm.js:797
doTheRequest @ index.esm.js:3156
(anonymous) @ index.esm.js:3026
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:423
onInvokeTask @ core.js:17290
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:422
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:195
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:498
ZoneTask.invoke @ zone.js:487
timer @ zone.js:2281
setTimeout (async)
scheduleTask @ zone.js:2302
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:410
onScheduleTask @ zone.js:301
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:404
push../node_modules/zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:238
push../node_modules/zone.js/dist/zone.js.Zone.scheduleMacroTask @ zone.js:261
scheduleMacroTaskWithCurrentZone @ zone.js:1245
(anonymous) @ zone.js:2317
proto. @ zone.js:1569
callWithDelay @ index.esm.js:3024
start @ index.esm.js:3082
push../node_modules/@firebase/storage/dist/index.esm.js.NetworkRequest.start_ @ index.esm.js:3238
(anonymous) @ index.esm.js:3143
ZoneAwarePromise @ zone.js:910
make @ index.esm.js:558
NetworkRequest @ index.esm.js:3140
makeRequest @ index.esm.js:3303
push../node_modules/@firebase/storage/dist/index.esm.js.AuthWrapper.makeRequest @ index.esm.js:2952
(anonymous) @ index.esm.js:2254
(anonymous) @ index.esm.js:2149
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:391
onInvoke @ core.js:17299
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:390
push../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:150
(anonymous) @ zone.js:889
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:423
onInvokeTask @ core.js:17290
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:422
push../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:195
drainMicroTaskQueue @ zone.js:601
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:502
invokeTask @ zone.js:1744
globalZoneAwareCallback @ zone.js:1770
Show 33 more frames
core.js:15724 ERROR FirebaseStorageError {code_: "storage/unauthorized", message_: "Firebase Storage: User does not have permission to access 'RoomsImages/1596705165294'.", serverResponse_: "{↵ "error": {↵ "code": 403,↵ "message": "Pe…n denied. Could not perform this operation"↵ }↵}", name_: "FirebaseError"}
Hi, Emma. Thanks for the article. I have a question: is executing another Observable with it's own subscription inside finalize operator is good practice?
Just asking, because putting an Observable inside subscribe is not a good idea, which can lead to memory leak, etc.
So, is it ok to do, like it's done in your article?
Thanks. It helped me
Sweet ...this is awesome ...nice read
thanks