SlideShare a Scribd company logo
Serverless Angular + Material +
Firebase applications
Loiane Groner
@loiane
Build a full stack app with Google technologies
Serverless Angular, Material, Firebase and Google Cloud applications
Agenda
Build a UI
Make it responsive
Build an API (Serverless)
Realtime database x Firestore
Authentication
Cloud Functions
Hosting
Deployment
Loiane Groner
@loiane
github.com/loiane
loiane.com
loiane.training
Developer / Business Analyst by day
Blog / Youtube by night
Angular
Modularized components
Angular CLI
Large Dev community
Setup Angular
Angular CLI
Angular Schematics: create new project
Angular Schematics
Angular Schematics for Visual Studio Code
Angular Material: cross platform
Angular Material: modern UI components
Angular Flex Layout: Angular directives and API
Angular Material + Flex Layout - Desktop
Angular Material + Flex Layout
<mat-expansion-panel-header>
<mat-panel-title>
{{ module.name }}
"</mat-panel-title>
<mat-panel-description fxHide [fxHide.gt-md]=“false" >
{{ module.lessons.length}} Lessons"</mat-panel-description>
<span class="panel-title-time" fxShow [fxShow.xs]="false">{{ module.duration }}"</span>
"</mat-expansion-panel-header>
<mat-list dense *ngIf="module.lessons">
<ng-template ngFor let-lesson [ngForOf]="module.lessons">
<mat-list-item>
<mat-icon mat-list-avatar …>"</mat-icon>
<span mat-line>{{ lesson.name }}"</span>
<p mat-line fxHide [fxHide.xs]="false">{{ lesson.duration }} min"</p>
<div fxShow [fxShow.xs]="false" fxLayout="row">
<mat-icon fontSet="mdi" fontIcon=“mdi-clock" >"</mat-icon>{{ lesson.duration }}
"</div>
"</mat-list-item>
"</ng-template>
"</mat-list>
Angular Material + Flex Layout: Tablet
<mat-expansion-panel-header>
<mat-panel-title>
{{ module.name }}
"</mat-panel-title>
<mat-panel-description
fxHide [fxHide.gt-md]=“false" >
{{ module.lessons.length}} Lessons
"</mat-panel-description>
<span class="panel-title-time"
fxShow [fxShow.xs]=“false">
{{ module.duration }}
"</span>
"</mat-expansion-panel-header>
Angular Material + Flex Layout: Phone
<mat-expansion-panel-header>
<mat-panel-title>
{{ module.name }}
"</mat-panel-title>
<mat-panel-description
fxHide [fxHide.gt-md]=“false" >
{{ module.lessons.length}} Lessons
"</mat-panel-description>
<span class="panel-title-time"
fxShow [fxShow.xs]=“false">
{{ module.duration }}
"</span>
"</mat-expansion-panel-header>
Serverless
Pros x Cons
No need to think about servers
No upfront provisioning; scales as needed
Pay per use
Stateless
Vendor Lock-in
Architecture
Client
(Browser)
Authentication
Database
Student count
Generate Certificate
Serverless Angular, Material, Firebase and Google Cloud applications
Serverless Angular, Material, Firebase and Google Cloud applications
Serverless Angular, Material, Firebase and Google Cloud applications
Setup Firebase
Firebase Console
Firebase Console
Serverless Angular, Material, Firebase and Google Cloud applications
Creating a DB
Firebase Rules
Creating a collection of documents
Entering Sample Data
Entering Sample Data
Differences with Realtime DB
Firebase config
Firebase libraries
@angular/fire (angularfire2)
Observable based: use the power of RxJS, Angular, and Firebase.
Authentication: log users in with a variety of providers and monitor
authentication state in realtime.
Add Firebase config: dev and prod
export const environment = {
production: false,
firebase: {
apiKey: "AIzaSyDt4IqlLy7UYoPgCwwd_I6C7T5ZHjuFbrU",
authDomain: "devfest-bcc98.firebaseapp.com",
databaseURL: "https:"//devfest-bcc98.firebaseio.com",
projectId: "devfest-bcc98",
storageBucket: "devfest-bcc98.appspot.com",
messagingSenderId: "228593776604"
}
};
src/environment/environment.ts
Angular: AppModule
…
import { AngularFireModule } from '@angular/fire';
import { environment } from '"../environments/environment';
@NgModule({
imports: [
…,
AngularFireModule.initializeApp(environment.firebase)
],
bootstrap: [AppComponent]
})
export class AppModule { }
src/app/app.module.ts
Firebase modules
import { NgModule } from '@angular/core';
import { AngularFireModule } from '@angular/fire';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFirestoreModule } from '@angular/fire/firestore';
import { AngularFireStorageModule } from '@angular/fire/storage';
@NgModule({
exports: [
AngularFireModule, "// needed for everything
AngularFirestoreModule, "// only needed for database features
AngularFireAuthModule, "// only needed for auth features
AngularFireStorageModule "// only needed for storage features
]
})
export class AppFirebaseModule { }
Building the API
Firestore: retrieving collections / documents
export class FireApiService {
constructor(public db: AngularFirestore) {}
getCollection<T>(collectionName: string): Observable<T[]> {
return this.db.collection<T>(collectionName).valueChanges();
}
getCollectionItem<T>(collection: string, property: string, searchItem: string) {
return this.db
.collection<T>(collection, ref "=> ref.where(property, '"==', searchItem))
.valueChanges();
}
getDocument(path: string) {
"// path: /courses/XF40vxTSoSMNFXUndKaw
return this.db.doc(path).valueChanges();
}
}
Angular async pipe
@Component({
selector: 'app-courses-list',
template: `
<ul>
<li *ngFor="let course of courses$ | async">
{{ course.name }}
"</li>
"</ul>
`
})
export class CoursesListComponent {
courses$: Observable<any[]>;
constructor(db: AngularFirestore) {
this.courses$ = db.collection('courses').valueChanges();
}
}
Firestore: creating/updating data
export class FireApiService {
constructor(public db: AngularFirestore) {}
createDoc(path: string, obj: any): Observable<firebase.firestore.DocumentReference> {
return from(this.db.collection(path).add(obj));
}
updateDoc(path: string, obj: any) {
return this.db.doc(path).update(obj);
"// this.db.doc(path).set(obj); "// overwrite
}
deleteDoc(path: string) {
return this.db.doc(path).delete();
}
}
Authentication
Auth: providers
Advanced config
@angular/fire
export class AuthService {
constructor(private afAuth: AngularFireAuth) {}
get currentUser(): firebase.User {
return this.afAuth.auth.currentUser;
}
signInWithGoogleAuthProvider() {
return from(this.afAuth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider()));
}
signInWithEmailAndPassword(
email: string, password: string
): Observable<firebase.auth.UserCredential> {
return from(this.afAuth.auth.signInWithEmailAndPassword(email, password));
}
signOut() {
return from(this.afAuth.auth.signOut());
}
}
Angular route guards
export class AuthGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | boolean {
if (!this.auth.currentUser) {
this.router.navigate(['/login']);
return false;
}
return true;
}
}
Sign in
Firebase UI Web
Firebase UI Web
Cloud Functions
Firebase CLI
firebase init
firebase init
Functions: JS or TS
Http
import * as functions from 'firebase-functions';
"// "// Start writing Firebase Functions
"// "// https:"//firebase.google.com/docs/functions/typescript
"//
export const helloWorld = functions.https.onRequest((request, response) "=> {
response.send("Hello from Firebase!");
});
Firestore + auth trigger
export const createUser = functions.firestore
.document('users/{userId}')
.onCreate((snap, context) "=> {
"// Get an object representing the document
"// e.g. {'name': 'Loiane', 'course': Angular}
const newValue = snap.data();
const name = newValue.name;
"// perform desired operations ""...
});
export const sendWelcomeEmail = functions.auth.user().onCreate(user "=> {
"// ""...
});
Logs
Firebase Rules
Syntax Highlighting
Syntax Highlighting
Visual Studio Code Extension
Looks better now!
Some Tips
Avoiding templates changes: pipes for the rescue
export class UserEnrolledPipe implements PipeTransform {
constructor(priva: UserService) {}
transform(user: any, course: Course): Observable<boolean> {
if (user "&& course) {
return this.userService.isUserEnrolled(course);
}
return of(false);
}
} <button
*ngIf="(user | userEnrolled:course | async); else: enroll"
[routerLink]="['/continue-course/', course.slug]"
>
Continue Course
"</button>
Data modeling
Hosting and DevOps
Travis CI
firebase login:ci
Environment variables
.travis.yml
language: node_js
node_js:
- node
before_script:
- npm install -g "--silent firebase-tools
script:
- npm run build
after_success:
- test $TRAVIS_BRANCH = "master" "&& test $TRAVIS_PULL_REQUEST = "false"
"&& firebase deploy "--only hosting
—token $FIREBASE_TOKEN "--non-interactive
notifications:
email:
on_failure: change
on_success: change
Hosting: custom domain
Serverless Angular, Material, Firebase and Google Cloud applications
Full stack with Google technologies!
Thank you!
@loiane
github.com/loiane
loiane.com
loiane.training
Resources
https://angular.io/resources
https://material.angular.io/
https://github.com/angular/flex-layout/wiki
https://angularfirebase.com/
https://www.fullstackfirebase.com/
http://bit.ly/organizing-firebase-cf

More Related Content

Serverless Angular, Material, Firebase and Google Cloud applications