Building Realtime Blood Donor App using Angular 8, Google Maps, and Firebase

Building Realtime Blood Donor App using Angular 8, Google Maps, and Firebase
In this post, you'll see step by step tutorial on building Realtime blood donor app using Angular 8, Google Maps, Location, and Firebase Realtime Database
Originally published at https://www.djamware.com

In this Angular 8 tutorial, we will be building a realtime blood donor app based on location tracking. Set the donor location to Firebase realtime database that automatically updated and seen by other users as real-time Google maps markers. The other users that see the blood donor markers on Google maps based on near to their device or computer location. So, they can choose and contact the desire blood donor then contact it.

Simply as that the flow of the Angular 8 Google Map Location Firebase realtime donor app.

Table of Contents:

  • Prerequisites
  • Setup Google Maps API Key
  • Set up Firebase Realtime Database
  • Create a New Angular 8 Web App
  • Install Google Firebase SDK
  • Create Angular Component and Routing
  • Display Google Maps
  • Get Donor List from Firebase Realtime Database
  • Display Donor Position to Google Maps
  • Add a New Donor Data using Angular Material
  • Run and Test Angular 8 Google Maps Firebase Realtime Blood Donor App

Prerequisites

As we mention in the first paragraph of this tutorial, this Angular 8 web app involves Google Map, Browser Location, and Firebase Realtime Database. So, the following tools, frameworks, libraries, and modules are required for this tutorial achievement:

  1. Node.js
  2. Angular 8
  3. Google Maps Javascript API
  4. Google Maps API Key
  5. Firebase Realtime Database
  6. Firebase Javascript Module
  7. Terminal or Node Command Line
  8. Text Editor or IDE

As usual, we have to make sure the Node.js installed correctly before going to the main steps. Type this command in the terminal or command line to check the installed Node.js and NPM.

node -v
v10.15.1
npm -v
6.11.2

If there's no Node.js and NPM installed, go to the Node.js official site then download and install it.

Setup Google Maps API Key

To use Google Maps Javascript API we need a Google Maps API key. The Google Maps JavaScript API lets you customize maps with your own content and imagery for display on web pages and mobile devices. The Maps JavaScript API features four basic map types (roadmap, satellite, hybrid, and terrain) which you can modify using layers and styles, controls and events, and various services and libraries.

Next, open your browser the go to the Google Developer Console. You will be taken to this Google Developer Console page.

Just scroll the default opened projects then it will take to this dialog.

Click the "New Project" button then it will take to this New Google Project page.

Fill the project name and leave other fields as default then click the "Create" button and it will take to the Google Developer Console home page with default opened project. Select again the project then choose the newly created Angular Maps project and click the "OK" button. It will take to the Angular Maps project dashboard without any APIs enabled.

Click the "Enable API" button then it will take to this Google APIs library page.

Find and choose Maps Javascript API then it will take to this Maps Javascript API page.

Just click on the "Enable" button then it will take back to the Maps Javascript API dashboard.

Click on Credentials link then it will take to the Credentials page.

Click on "+ Create Credentials" link then choose "API KEY" and it will take to the API KEY dialog. Copy and paste the newly created API KEY to your Notepad or Text Editor for using in the Angular app.

Set up Firebase Realtime Database

Next, we will set up or create a new Google Firebase project that can use the realtime database. Just open your browser then go to Google Firebase Console and it will take to this page.

From that page, click "+" add project button to create a Google Firebase project then it will be redirected to this page.

Type the previously created Google APIs project then choose the existing Google APIs project and click the "Continue" button.

This time, choose to not add Firebase analytics for now then click the "Add Firebase" button. And now, the Firebase will be added to the Angular Maps project.

Click the "Continue" button then it will take to the Firebase Angular Maps project dashboard.

Click the "Database" menu then it will take to the Firebase Database dashboard.

Scroll down and find "Or Choose Realtime Database" then click on the "Create Database" button. Next, it will take to the "Security rules for Realtime Database" dialog.

Choose "Start in test mode" radio button then click on the "Enable" button and it will take to the "Realtime Database" dashboard. Now, the Google Firebase realtime database is ready to use with your Angular Maps web app.

Create a New Angular 8 Web App

In the prerequisites step, we have checked the Node.js and NPM version. Now, we have to install or check the Angular CLI version. The Angular CLI is a tool to initialize, develop, scaffold and maintain Angular applications. From the Terminal or Node Command Line, type this command to install or update the Angular CLI.

sudo npm install -g @angular/cli

Now, we have the latest version of Angular when this example was written.

  _           _        ____ _  ___
  / \ _ __ __ _ _ _| | __ _ _ __  / ___| | |_ _|
 / △ \ | '_ \ / _` | | | | |/ _` | '__| | | | |  | |
 / ___ \| | | | (_| | |_| | | (_| | |   | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_|   \____|_____|___|
        |___/


Angular CLI: 8.3.2
Node: 10.15.1
OS: darwin x64
Angular:
...

Package           Version
------------------------------------------------------
@angular-devkit/architect  0.803.2
@angular-devkit/core    8.3.2
@angular-devkit/schematics 8.3.2
@schematics/angular     8.3.2
@schematics/update     0.803.2
rxjs            6.4.0

Next, create an Angular 8 application for this Google Maps Firebase Realtime Blood Donor App by typing this command.

ng new angular-maps

Answer all questions like below which we will skip Angular Routing and use SCSS as a stylesheet.

? Would you like to add Angular routing? No
?
Which stylesheet format would you like to use? SCSS   [
https://sass-lang.com/documentation/syntax#scss        
        ]

Next, to sanitize the newly created Angular 8 project go to that project folder then run the Angular application.

cd ./angular-maps
ng serve

You will this page or view when you open "http://localhost:4200/" in your browser which means the Angular 8 is ready to go.


Install Google Firebase SDK

We will use Google Firebase Javascript SDK for accessing Firebase Realtime Database. For that, type this command to install the module.

npm install --save firebase

Next, register the Firebase SDK module in the Angular Maps app by open and edit this file `src/app/app.component.ts` then add these imports of Firebase.

import * as firebase from 'firebase';

Declare a constant variable for holds Firebase setting before @Component that contain the configuration variable for accessing Firebase using apiKey, authDomain, databaseURL, projectId, storageBucket.

 const config = {
 apiKey: 'YOUR_APIKEY',
 authDomain: 'YOUR_AUTH_DOMAIN',
 databaseURL: 'YOUR_DATABASE_URL',
 projectId: 'YOUR_PROJECT_ID',
 storageBucket: 'YOUR_STORAGE_BUCKET',
};

You can find or get those configuration parameters by click on the settings (gear button) -> Project Settings to get web API key and Project ID. Click Develop -> Authentication then scrolls to Authorized domain to get authDomain value. In order to get the value of storageBucket, you have to enable or start a Storage by going to Develop -> Storage. Next, initialize Firebase configuration settings inside Angular constructor.

constructor() {
 firebase.initializeApp(config);
}

Now, the Firebase realtime database is ready to use.

Create Angular Component and Routing

We will display the Google maps and add a new donor in the new Angular components. For that, generate component using Angular schematics.

ng g component donor-list
ng g component add-donor

Because in the first Angular creation not including the Routing, we have to add it manually. Open and edit `src/app/app.module.ts` then add this import of Angular RouterModule and Router.

import { RouterModule, Routes } from '@angular/router';

Add a constant variable after the imports for the routes to the new Angular component.

const appRoutes: Routes = [
 { path: 'donor-list', component: DonorListComponent },
 { path: 'add-donor/:lat/:lng', component: AddDonorComponent },
 { path: '',
  redirectTo: '/donor-list',
  pathMatch: 'full'
 }
];

Add the Angular RouterModule to the @NgModule imports.

imports: [
 ...
 RouterModule.forRoot(
  appRoutes
 )
],

As you see, the newly created components already registered in the Angular AppModule.

Display Google Maps

Now, we will display a Google Maps in the Angular component (donor-list) template using Google Maps Javascript SDK. Before that, we need to load the Google Maps Javascript SDK first by open and edit `src/index.html` then add this Script loader before the closing of </body> tag.

<body>
 <app-root></app-root>
  <script src="http://maps.googleapis.com/maps/api/js?key=AIzaSyCeUZ4BzsoVCSMnnGdNUQxDlIMSxEQhmLU"></script>
</body>

Next, open and edit `src/app/donor-list/donor-list.component.html` then replace all HTML tags with this tag that represent the Google Maps.

<div #map id="map"></div>

Open and edit `src/app/donor-list/donor-list.component.ts` then modify the @angular/core import to add ViewChild and ElementRef.

import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';

Declare the basic required Google maps variables (map, marker, options) before the Angular @Component.

declare var google: any;
let map: any;
let marker: any;
const options = {
 enableHighAccuracy: true,
 timeout: 5000,
 maximumAge: 0
};
let infowindow: any;
const iconBase = 'http://maps.google.com/mapfiles/ms/icons/';

Load map element, after the title variable.

@ViewChild('map', {static: false}) mapElement: ElementRef;

Create a function to load Google Maps and set a default marker of the current browser location.

initMap() {
 navigator.geolocation.getCurrentPosition((location) => {
  map = new google.maps.Map(this.mapElement.nativeElement, {
   center: { lat: location.coords.latitude, lng: location.coords.longitude },
   zoom: 15
  });

  infowindow = new google.maps.InfoWindow();


  marker = new google.maps.Marker({
   position: { lat: location.coords.latitude, lng: location.coords.longitude },
   map,
   title: 'Click to zoom',
   icon: iconBase + 'blue-dot.png'
  });

  map.addListener('center_changed', () => {
   window.setTimeout(() => {
    map.panTo(marker.getPosition());
   }, 3000);
  });

  marker.addListener('click', (event: any) => {
   infowindow.setPosition(event.latLng);
   infowindow.setContent('<h2>Yes, I wanna be a donor!</h2>' +
   '<h3><a href="/add-donor/' + marker.getPosition().lat() + '/' + marker.getPosition().lng() + '">Register Here</a></h3>');
   infowindow.open(map, marker);
  });
 }, (error) => {
  console.log(error);
 }, options);
}

Call that function inside Angular constructor.

constructor() {
 this.initMap();
}

Now, the Google maps are displayed in the Angular page and ready to populate with a lot of markers that load from the Firebase realtime database. The current user location will be marked as a blue-dot icon.

Get Donor List from Firebase Realtime Database

Let's get back to the Firebase Realtime Database. We will get the list of Donor data from the Firebase Realtime Database. Still on `src/app/donor-list/donor-list.component.ts` then add this import of the Firebase.

import * as firebase from 'firebase';

Next, add this export constant function before the Angular @Component to extract the Firebase Realtime Database response to the Angular array.

export const snapshotToArray = (snapshot: any) => {
 const returnArr = [];

 snapshot.forEach((childSnapshot: any) => {
   const item = childSnapshot.val();
   item.key = childSnapshot.key;
   returnArr.push(item);
 });

 return returnArr;
};

Add the variables after @ViewChild variable to holds response data from Firebase realtime database.

donors = [];

Create a constructor after the variables to implement the Firebase realtime database. So, the data from Firebase automatically fetched on every value changes in Firebase realtime database side.

constructor() {
 firebase.database().ref('donors/').on('value', resp => {
  this.donors = [];
  this.donors = snapshotToArray(resp);
 });
 this.initMap();
}

The received data should contain the name, phone, email, and the coords.

Display Donor Position to Google Maps

After we have got donors data from the Firebase realtime database, we will display that data to Google Maps as the markers. Still, on `src/app/donor-list/donor-list.component.ts` iterate the donors' array to set the marker of the donors to the Google Maps.

constructor() {
 firebase.database().ref('donors/').on('value', resp => {
  this.donors = [];
  this.donors = snapshotToArray(resp);
  for (const donor of this.donors) {
   this.createMarkers(donor);
  }
 });
 this.initMap();
}

Add a new function to create markers that iterated from the donors' array.

createMarkers(place: any) {
 const latitude = parseFloat(place.coords.latitude);
 const longitude = parseFloat(place.coords.longitude);
 const donorMarker = new google.maps.Marker({
  map,
  position: { lat: latitude, lng: longitude },
  icon: iconBase + 'green-dot.png'
 });

 google.maps.event.addListener(donorMarker, 'click', function() {
  infowindow.setContent('<h3>' + place.name + '</h3><p>Phone number: ' + place.phone + '<br>Email: ' + place.email + '</p>');
  infowindow.open(map, this);
 });
}

Now, we have displayed the donors as green-dot markers.

Add a New Donor Data using Angular Material

Next, we will use another newly created Angular component for add new donor data. For add data form, we will use Angular Material and Reactive Form. For that, add Angular Material to this project using schematics.

ng add @angular/material

Open and edit `src/app/app.module.ts` then add these imports of BrowserAnimationModule, the required Angular Material components, and Angular ReactiveForm.

import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {
 MatInputModule,
 MatPaginatorModule,
 MatProgressSpinnerModule,
 MatSortModule,
 MatTableModule,
 MatIconModule,
 MatButtonModule,
 MatCardModule,
 MatFormFieldModule } from '@angular/material';

Add them into @NgModule imports.

imports: [
 ...
 FormsModule,
 ReactiveFormsModule,
 BrowserAnimationsModule,
 MatInputModule,
 MatTableModule,
 MatPaginatorModule,
 MatSortModule,
 MatProgressSpinnerModule,
 MatIconModule,
 MatButtonModule,
 MatCardModule,
 MatFormFieldModule,
 ...
],

Next, open and edit `src/app/add-donor/add-donor.component.ts` then add these imports of Angular ActivatedRoute, Router, FormControl, FormGroupDirective, FormBuilder, FormGroup, NgForm, Validators, ErrorStateMatcher, and Firebase.

import { ActivatedRoute, Router } from '@angular/router';
import { FormControl, FormGroupDirective, FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms';
import { ErrorStateMatcher } from '@angular/material/core';
import * as firebase from 'firebase';

Add a new export class for handling the error of each FormControl after the imports.

export class MyErrorStateMatcher implements ErrorStateMatcher {
 isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
  const isSubmitted = form && form.submitted;
  return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
 }
}

Add the required variables of donor FormGroup, name, phone, email, lat, lng, and Firebase database reference.

donorForm: FormGroup;
name: string='';
phone: string='';
email: string='';
lat = '';
lng = '';
ref = firebase.database().ref('donors/');

Inject the previously imported modules to the constructor and fill the constructor body with data from the previous page and set to LAT and LNG variables.

constructor(private route: ActivatedRoute, private router: Router, private formBuilder: FormBuilder) {
 this.lat = this.route.snapshot.paramMap.get('lat');
 this.lng = this.route.snapshot.paramMap.get('lng');
}

Initialize each of the FormControl in the FormGroup including the validations inside NgOnInit function.

ngOnInit() {
 this.donorForm = this.formBuilder.group({
  'name' : [null, Validators.required],
  'phone' : [null, Validators.required],
  'email' : [null, Validators.required]
 });
}

Add a function for handling the submitted form than send the form controls values to the Firebase Realtime Database.

onFormSubmit(form: any) {
 const donor = form;
 donor.coords = { latitude: this.lat, longitude: this.lng };
 const newDonor = firebase.database().ref('donors/').push();
 newDonor.set(donor);
 this.router.navigate(['/']);
}

After form submitted and data sent to Firebase realtime database, it will return to the previous Google Maps page.

Run and Test Angular 8 Google Maps Firebase Realtime Blood Donor App

To run this Angular 8 Google Maps Firebase Realtime Blood Donor App, simply type this Angular command.

ng serve

Now, you can go to localhost:4200 using your browser then you see the maps. For demo purpose, you use a single browser then change the geolocation of the browser.

That it's, the Angular 8 Google Maps Firebase Realtime Blood Donor App. You can get the full source code from our GitHub.

Thanks for reading

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading

Best 50 Angular Interview Questions for Frontend Developers in 2019

How to build a CRUD Web App with Angular 8.0

React vs Angular: An In-depth Comparison

React vs Angular vs Vue.js by Example

Microfrontends — Connecting JavaScript frameworks together (React, Angular, Vue etc)




Suggest:

Single Page Application using Asp.Net Core 2.2 and Angular

How To Level Up Your Angular Unit Testing Game (2/3)

Create a cryptocurrency dashboard with Angular

The world beyond React, Vue & Angular

The A to Z Guide to Angular Lifecycle | Hooks & Components | Hooks & Components

Top 10 Podcasts for Web Developers