ngx-storage-firebaseui - Open Source Library for Angular Web Apps to integrate a material user interface for firebase storage.
Angular UI component for firebase authentication. This library is an angular module (including angular components and services) that allows to upload/download or event delete files from firebase storage within a firebase project.
Do you have any
question or suggestion ? Please do not hesitate to contact us!
Alternatively, provide a PR | open an appropriate issue here
If you like this project, support ngx-storage-firebaseui by starring ⭐ and sharing it 📢
- Why to use ngx-storage-firebaseui ?
- Library's components
- Requirements
- Demo
- Screenshots
- Peer Dependencies
- Dependencies
- Firebase Cloud Functions and Firebase extensions
- Installation
- Usage
- API
- Run Demo App Locally
- Other Angular Libraries
- Support
- License
- 💝 it uses a responsive and accessible web design UX/UI from google material concepts and components (supporting desktop, tablet and mobile view) incl. smooth animations for a better UX.
- 💄 pick up your own theme! change the primary, accent and warn colors whenever you need (e.g to support light and dark themes)
- 🚢 super easy to use with an angular based project (project that is created with the angular-cli)
- 🔜 optional configuration
- ♻️ configure your components in runtime
- ♻️ reusable components for every project that needs some uploads workflows with a firebase project/app.
- 🛃 built in feedback mechanism in form of a snackbar when an error or
any
important event occurred. - 🆘 ability to delete files
- 👻 compatible with
ngx-auth-firebaseui
learn more - 🔥 Sync user's uploads with FIRESTORE AUTOMATICALLY
- 🎉 Supports SSR - Server Side Rendering
- 🔜 support of i18n
<ngx-storage-firebaseui-images>
used to upload imaged to firebase storage and sync them with firestore
- upload images
- image grid
- delete image (soon)
- pre-built firebase functions to auto-rotate images (soon)
- angular material theme
- angular material icons
- angular cdk - v9.x
- angular material - v9.x
- angular animations - v9.x
- angular router - v9.x
- angular flex-layout v9.0.0-beta.29
- @angular/fire - v5.4.x
- firebase - v7.13.x
the full tutorial guide can be found here
Peer Dependencies - please make sure that peerDependencies are installed if you are not using the schematics
"peerDependencies": {
"@angular/core": "^9.x",
"@angular/animations": "^9.x",
"@angular/cdk": "^9.x",
"@angular/flex-layout": "^9.0.0-beta.29",
"@angular/material": "^9.x",
"@angular/fire": "5.4.x",
"firebase": "7.13.x",
}
- Angular (requires Angular 2 or higher, developed with 9.x) - obviously
In the following section, I will show you how to improve the user's experience regarding images
Install firebase extension - Resize Images
- install the storage resize images extension in your firebase project
- set your firebase cloud function's location
- pick either the default bucket or choose another one
- set size images:
50x50,100x100,200x200,500x500,1000x1000,2000x2000
- choose whether to delete the original image (tip: don't do that so that you can regenerate the thumbnails)
- choose the cloud storage path for resized images
thumbs
(see below an example of an image directory in firebase storage)
after installation
Upload firebase cloud functions to sync the uploaded images to firebase storage with firestore (required
)
firebase init
- init firebase cloud function in your firebase project (
typescript
) - copy and paste the below functions
- upload
firbease deploy --only functions
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import { ObjectMetadata } from 'firebase-functions/lib/providers/storage';
// tslint:disable-next-line:no-implicit-dependencies
import { Bucket, Storage } from '@google-cloud/storage';
// @ts-ignore
// tslint:disable-next-line:no-implicit-dependencies
import { GetSignedUrlResponse } from '@google-cloud/storage/build/src/file';
const path = require('path');
const os = require('os');
const fs = require('fs');
// tslint:disable-next-line:no-implicit-dependencies
const spawn = require('child-process-promise').spawn;
// tslint:disable-next-line:no-implicit-dependencies
const mkdirp = require('mkdirp-promise');
const storage = new Storage();
const firestore = admin.firestore();
const defaultStorage = admin.storage();
// const defaultBucket = defaultStorage.bucket();
/**
* Firebase cloud function to sync uploaded images to firebase storage bucket with firestore
*
* @author Anthony Nahas
* @since 03.2020
* @version 1.0
*/
export const syncImgsWithFirestore =
functions
.storage
.object()
.onFinalize(async (object: ObjectMetadata) => {
console.log('syncImgsWithFirestore is now running', object);
if (object && object.contentType && !object.contentType.includes('image')) {
console.log('exiting function');
return false;
}
let downloadURLs: any = null;
let downloadURL = null;
try {
downloadURLs = await getDownloadURL(object);
downloadURL = downloadURLs[0];
console.log('Download URL --> ', downloadURL, typeof downloadURL);
// downloadURL = downloadURL[0];
} catch (e) {
console.error('Error while getting download url', e);
}
const filePath = object.name;
console.log('file path -->', filePath);
// @ts-ignore
const pathSegments = filePath.split('/');
console.log('path segments --> ', pathSegments);
const indexOfID = pathSegments.indexOf('imgs');
console.log('indexOfID', indexOfID, pathSegments[indexOfID + 1]);
const imgID = pathSegments[indexOfID + 1];
const lastSegment = pathSegments[pathSegments.length - 1];
console.log('lastSegment', lastSegment);
const nameSegments = lastSegment.split('_');
console.log('nameSegments', nameSegments);
const resize = nameSegments[nameSegments.length - 1];
console.log('resize', resize);
const size = resize.split('x')[0];
console.log('size', size, typeof size);
// const img: NahausImage = {
// id: imgID,
// downloadURL,
// path: filePath
// };
const indexOfThumbs = pathSegments.indexOf('thumbs');
console.log('indexOfThumbs', indexOfThumbs);
let firestorePath: string;
if (indexOfThumbs !== -1) {
// the image is a thumbnail
firestorePath = pathSegments.splice(0, indexOfThumbs).join('/');
console.log('firestorePath', firestorePath);
const thumbsMapKey: string = `thumbs.${size}`;
return await firestore.doc(firestorePath).update({
[thumbsMapKey]: {
id: imgID,
downloadURL,
path: filePath
}
});
} else {
pathSegments.pop();
firestorePath = pathSegments.join('/');
console.log('firestorePath', firestorePath);
return await firestore.doc(firestorePath).set({
id: imgID,
downloadURL,
path: filePath
}, { merge: true });
}
});
function getDownloadURL(object: ObjectMetadata): Promise<GetSignedUrlResponse> | void {
if (!object.name) {
return;
}
const bucket: Bucket = defaultStorage.bucket();
const file = bucket.file(object.name);
// Get a signed URL for the file
return file.getSignedUrl({
action: 'read',
expires: '03-17-2025'
});
}
export const adjustOrientation = functions
.storage
.object()
.onFinalize(async (object) => {
const filePath = object.name;
const bucketName = object.bucket;
const metadata = object.metadata;
const tempLocalFile = path.join(os.tmpdir(), filePath);
const tempLocalDir = path.dirname(tempLocalFile);
const bucket = storage.bucket(bucketName);
if (object && object.contentType && !object.contentType.startsWith('image/')) {
console.log('This is not an image.');
return null;
}
if (metadata && metadata.autoOrient) {
console.log('This is already rotated');
return null;
}
return mkdirp(tempLocalDir).then(() => {
// Download file from bucket.
// @ts-ignore
return bucket.file(filePath).download({ destination: tempLocalFile });
}).then(() => {
console.log('The file has been downloaded to', tempLocalFile);
// Convert the image using ImageMagick.
return spawn('convert', [tempLocalFile, '-auto-orient', tempLocalFile]);
}).then(() => {
console.log('rotated image created at', tempLocalFile);
// @ts-ignore
metadata.autoOrient = true;
return bucket.upload(tempLocalFile, {
destination: filePath,
metadata: { metadata: metadata }
});
}).then(() => {
console.log('image uploaded to Storage at', filePath);
// Once the image has been converted delete the local files to free up disk space.
fs.unlinkSync(tempLocalFile);
console.log('Deleted local file', filePath);
return;
});
});
(1) Installation
If Angular Material Design is not setup, just run ng add @angular/material
learn more
Now add the library via the angular schematics
ng add ngx-storage-firebaseui
- ✔️ peer dependencies will be automatically added the package.json and installed
- ✔️
ngx-storage-firebaseui
's module will be automatically imported to the root module (just replacePUT_YOUR_FIREBASE_API_KEY_HERE
with your firebase api key) - ✔️
ngx-storage-firebaseui
's assets will be automatically added theangular.json
file
Install above dependencies via npm.
Now install ngx-storage-firebaseui
via:
npm install --save ngx-storage-firebaseui
npm i -s @angular/material @angular/cdk @angular/flex-layout @angular/forms @angular/animations @angular/router
Firebase deps
npm i -s firebase @angular/fire
-> continue by following the instructions
here
Once installed you need to import the main module:
import { NgxStorageFirebaseuiModule } from 'ngx-storage-firebaseui';
The only remaining part is to list the imported module in your application module. The exact method will be slightly
different for the root (top-level) module for which you should end up with the code similar to (notice NgxStorageFirebaseuiModule .forRoot()
):
and then from your Angular AppModule
:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
// Import your library
import { NgxStorageFirebaseuiModule } from 'ngx-storage-firebaseui';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
// Specify the ngx-storage-firebaseui library as an import
NgxStorageFirebaseuiModule.forRoot({
apiKey: 'your-firebase-apiKey',
authDomain: 'your-firebase-authDomain',
databaseURL: 'your-firebase-databaseURL',
projectId: 'your-firebase-projectId',
storageBucket: 'your-firebase-storageBucket',
messagingSenderId: 'your-firebase-messagingSenderId'
}),
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Other modules in your application can simply import NgxStorageFirebaseuiModule
:
import { NgxStorageFirebaseuiModule } from 'ngx-storage-firebaseui';
@NgModule({
declarations: [OtherComponent, ...],
imports: [NgxStorageFirebaseuiModule, ...],
})
export class OtherModule {
}
Note:If you are using
SystemJS
, you should adjust your configuration to point to the UMD bundle. In your systemjs config file,map
needs to tell the System loader where to look forngx-storage-firebaseui
:
{
'ngx-storage-firebaseui';: 'node_modules/ngx-storage-firebaseui/bundles/ngx-storage-firebaseui.umd.js',
}
(3) Usage
Once the library is imported, you can use its components, directives and pipes in your Angular application:
<ngx-storage-firebaseui-images></ngx-storage-firebaseui-images>
see the usage
<ngx-storage-firebaseui-images></ngx-storage-firebaseui-images>
see the api
option | bind | type | default | description |
---|---|---|---|---|
path | Input() |
string |
- | path to store the image into firebase storage as well as in the firestore |
load | Input() |
boolean |
true |
whether to load the uploaded images from firebase |
addButtonTooltipText | Input() |
string |
add picture |
text of the add button tooltip |
onLoad | Output() |
number |
- | called when the images are loaded from firestore |
onImageUploaded | Output() |
number |
- | called when an image is uploaded to firebase storage |
onImageSelectedAtIndex | Output() |
number |
- | called when an image is selected / clicked |
- ngx-auth-firebaseui
- ngx-linkifyjs
- @angular-material-extensions/password-strength
- @angular-material-extensions/google-maps-autocomplete
- @angular-material-extensions/fab-menu
- @angular-material-extensions/select-country
- @angular-material-extensions/pages
- @angular-material-extensions/link-preview
- @angular-material-extensions/contacts
- @angular-material-extensions/faq
- angular-material-extensions/freelancer-theme
- @firebaseui/ng-bootstrap
- Drop an email to: Anthony Nahas
- or open an appropriate issue
- let us chat on Gitter
Built by and for developers ❤️ we will help you 👊
This project is supported by jetbrains with 1 ALL PRODUCTS PACK OS LICENSE incl. webstorm
Copyright (c) 2020 Anthony Nahas. Licensed under the MIT License (MIT)