This is the second part of the super series on Angular and Firebase. If you missed the first one then go take a look!

Welcome to part two of this series of articles that aim to help you bring your awesome ideas to life. In this installment of the series, I bring you lots more of Angular and Firebase goodness while we build the rest of baby-gotchi, a baby simulator to help you become a better dad.

Enjoy!

Quick Recap

Let’s start by making a quick recap of what we have achieved thus far so we all are on the same page before we continue.

In the last part of the series we:

Created a new Angular app using the Angular cli Devised a way to model babys in code with the Baby class Built the BabiesComponent as a way to show a list of babies and give birth to new ones Setup Firebase using the AngularFire2 library Used Firebase Realtime Database to store our babies Added Angular Material and Angular Flex Layout to our app and made it look nicer

And so we arrived to this point:

Just after adding those two buttons to Take Care and Control our babies with this corresponding template:

< h1 > Born Babies! </ h1 > < section fxLayout = " column " fxLayoutGap = " 12px " > < md-card *ngFor = " let baby of babies | async " > < md-card-title > {{baby.name}} </ md-card-title > < md-card-actions > < a md-button color = " primary " [routerLink] = " [baby.$key, 'care'] " > Take care </ a > < a md-button color = " accent " [routerLink] = " [baby.$key, 'control'] " > Control!!! </ a > </ md-card-actions > </ md-card > < button md-raised-button color = " accent " (click) = " giveBirth() " > Give Birth! </ button > </ section >

Excellent! The next feature in our MVP will be taking care of our baby.

Taking Care of Your Baby

I don’t have a lot of parenting experience yet, but I think that in order to be able to take care of a baby it can be helpful to see the actual baby.

So, we’ll start by creating a new BabyComponent where we can both see our baby and take actions to care for her or him like cuddling, feeding or rocking the baby to sleep.

Again, just like we did in the previous article, we’ll take advantage of the Angular cli to generate our components for us. And since you have become an expert with the cli by this point, we’ll start using short-hand notation:

PS > ng g c baby - component

The short-hand notation is surprisingly easy to guess. Just pick the first letter of a word (like g for generate ) and it’ll work 99% of the times. When in doubt, use the Angular cli help. You can reach it via ng help or ng <command> --help (or ng <command> -h ).

For instance, the following command :

PS > ng g - h

Will show you all the available generators and the different flags that you can use with them.

Back to the baby! My idea with the baby component is to have a UI sort of like this:

Since they are two separate concerns: showing the status of the baby and performing actions on him or her we should create two separate components, a BabyStatusComponent and a BabyCareComponent .

The Baby Status Component

Let’s start with the component for the baby status. Again, Angular cli for the win:

PS > ng g c baby - status

The baby status should have a template where we can see how the baby is feeling at a glance. We update the template of this component to reflect all of the babies stats:

< h1 > {{baby.name}} is {{status}} </ h1 > < div class = " baby " [class.baby-sad] = " baby.life < 50 " [class.baby-super-sad] = " baby.life < 25 " > </ div > < div fxLayout = " row " fxLayoutAlign = " start center " class = " status-indicator " > < span fxFlex = " 60% " > Sleepiness </ span > < md-progress-bar fxFlex = " 25% " mode = " determinate " [value] = " baby.sleepiness " color = " primary " > </ md-progress-bar > < span fxFlex = " 15% " class = " status-indicator-counter " > {{baby.sleepiness}} </ span > </ div > < div fxLayout = " row " fxLayoutAlign = " start center " class = " status-indicator " > < span fxFlex = " 60% " > Hunger </ span > < md-progress-bar fxFlex = " 25% " mode = " determinate " [value] = " baby.hunger " color = " primary " > </ md-progress-bar > < span fxFlex = " 15% " class = " status-indicator-counter " > {{baby.hunger}} </ span > </ div > < div class = " status-indicator " > < span fxFlex = " 60% " > Shittiness </ span > < md-progress-bar fxFlex = " 25% " mode = " determinate " [value] = " baby.shittiness " color = " accent " > </ md-progress-bar > < span fxFlex = " 15% " class = " status-indicator-counter " > {{baby.shittiness}} </ span > </ div > < div class = " life status-indicator " > < span fxFlex = " 60% " > Life </ span > < md-progress-bar fxFlex = " 25% " mode = " determinate " [value] = " baby.life " color = " warn " > </ md-progress-bar > < strong fxFlex = " 15% " class = " status-indicator-counter " > {{baby.life}} </ strong > </ div >

A couple of things happen in this template:

We use the [class] property binding to set a class on the .baby element in order to display different baby images depending on how the baby is feeling

property binding to set a class on the element in order to display different baby images depending on how the baby is feeling We use the [value] property binding to set the value of different progress bars for the baby’s different stats

What are Property Bindings? Property bindings let you bind properties from your component class into your template. They are one-directional bindings that sync changes inside your component class into the template. They are typically used to set your template element's DOM properties based on the properties in your components. They are also used to send data from parent to child components as you'll see in a bit.

The template binds to a baby property that is exposed in the BabyStatusComponent class. But how does that baby get there? How does this component get hold of a Baby instance? With an input! And what is an input you may be asking yourself?

Well, Angular allows you to define inputs in your own components so that you can pass data from parent to child components using HTML attributes (just like it is so natural when writing HTML).

For instance, a consumer of the BabyStatusComponent could type the following:

< app-baby-status [baby] = " myBaby " > </ app-baby-status >

And send the myBaby variable with a Baby to the BabyStatusComponent (also notice how this is again a property binding).

In order to allow this type of behavior we need to define an input in the BabyStatusComponent using the @Input() decorator:

import { Component , OnInit , Input } from '@angular/core' import { Baby } from 'app/baby' @ Component ( { selector : 'app-baby-status' , templateUrl : './baby-status.component.html' , styleUrls : [ './baby-status.component.scss' ] , } ) export class BabyStatusComponent implements OnInit { @ Input ( ) baby : Baby get status ( ) : string { if ( this . baby . life > 50 ) { return 'happy' } else if ( this . baby . life > 25 ) { return 'sad' } else { return 'very sad' } } }

We also need to update the look and feel of the component inside baby-status.component.scss with some basic styles and some images for the baby:

h1 { text-align : center; } .baby { width : 150px; height : 150px; background-image : url ( '~/assets/baby-happy.png' ) ; background-size : contain; background-repeat : no-repeat; margin : 0 auto; } .baby-sad { background-image : url ( '~/assets/baby-sad.png' ) ; } .baby-super-sad { background-image : url ( '~/assets/baby-super-sad.png' ) ; } .status-indicator { margin : 12px 0; .status-indicator-counter{ text-align : right; } } .life { color : red; }

Images! Images! For the best result put some images in your assets folder. One for when the baby is happy assets/baby-happy.png , one when the baby is sad assets/baby-sad.png and one when the baby is suuuuuper sad assets/baby-super-sad.png .

After writing this component you realize that there’s some opportunities for improvement. Particularly, you see that there’s a lot of code duplication and verbosity in what concerns the status indicators. This is a great signal that the indicator is a perfect candidate for becoming its own component.

Let’s create it and do some refactoring.

Refactoring!!! Extracting the Status Indicator Component

Once more we take advantage of the Angular cli and type:

PS > ng g c status - indicator

Which results in a new StatusIndicatorComponent . We update its template status-indicator.component.html by copying and pasting the original template and making it a little bit more configurable. Namely we should be able to set the label and the value for every status indicator:

< div fxLayout = " row " fxLayoutAlign = " start center " class = " status-indicator " > < span fxFlex = " 60% " > {{label}} </ span > < md-progress-bar fxFlex = " 25% " mode = " determinate " [value] = " value " [color] = " color " > </ md-progress-bar > < span fxFlex = " 15% " class = " counter " > {{value}} </ span > </ div >

We also update its styles status-indicator.component.scss :

.counter { text-align : right; }

And, of course, its underlying component class status-indicator.component.ts :

import { Component , OnInit , Input } from '@angular/core' @ Component ( { selector : 'app-status-indicator' , templateUrl : './status-indicator.component.html' , styleUrls : [ './status-indicator.component.scss' ] , } ) export class StatusIndicatorComponent { @ Input ( ) label : string @ Input ( ) value : number @ Input ( ) color : string = 'primary' }

Using this new component will make our original BabyStatusComponent less wordy and simpler:

< section *ngIf = " baby " > < h1 > {{baby.name}} is {{status}} </ h1 > < div class = " baby " [class.baby-sad] = " baby.life < 50 " [class.baby-super-sad] = " baby.life < 25 " > </ div > < section fxLayout = " column " fxLayoutGap = " 12px " > < app-status-indicator [label] = " ' Sleepiness' " [value] = " baby.sleepiness " > </ app-status-indicator > < app-status-indicator [label] = " ' Hunger' " [value] = " baby.hunger " [color] = " ' accent' " > </ app-status-indicator > < app-status-indicator [label] = " ' Shittiness' " [value] = " baby.shittiness " > </ app-status-indicator > < app-status-indicator class = " life " [label] = " ' Life' " [value] = " baby.life " [color] = " ' warn' " > </ app-status-indicator > </ section > </ section >

Ooooh… *sigh* like a breath of fresh air.

Ok, so now that we have a way to display the status of a baby we can use it within our baby component. If you remember from the beginning of the article, we had used some pseudocode to represent the template of the BabyComponent in baby.component.html which looked like this:

We can continue by substituting that with this:

< app-baby-status [baby] = " baby | async " > </ app-baby-status >

Now the BabyComponent needs to be loaded in our application somehow.

At this point, when a user uses baby-gotchi they are confronted with an initial view where they can see a list of babies, give birth and click on a link to either take care or control the baby. However, those links won’t work. That’s because we haven’t updated our routing configuration to tell Angular what to do with those URLs.

We are going to update the routing configuration to connect these URL paths with the BabyComponent which will be the component in charge of providing this service to the user.

Updating Our Routing Configuration To Care For The Baby

In our routing configuration in app-routing.component.ts we add the following route:

import { NgModule } from '@angular/core' import { Routes , RouterModule } from '@angular/router' import { BabiesComponent } from 'app/babies/babies.component' import { BabyComponent } from 'app/baby/baby.component' const routes : Routes = [ { path : 'babies' , children : [ { path : '' , component : BabiesComponent , } , { path : ':id' , component : BabyComponent , pathMatch : 'prefix' , } , ] , } , { path : '**' , redirectTo : 'babies' , } , ] @ NgModule ( { imports : [ RouterModule . forRoot ( routes ) ] , exports : [ RouterModule ] , } ) export class AppRoutingModule { }

The new route tells Angular that whenever he sees a path that matches the babies/ URL and then starts with :id it should load the BabyComponent . The special :id token represents a route parameter and will store the value it matches within the URL. For instance:

/babies/12 // => The 'id' route parameter is equal to 12 /babies/f324afasd324/care // => The 'id' route parameter is equal to f324afasd324

Later on, we will be able to refer to this route parameter via its name id when interacting with the router.

If you run the application now (remember ng serve --open ) you’ll be able to see how when you click on either Take Care or Control Baby you are able to navigate to the BabyComponent view where… nothing is displayed!

The reason for that is that we haven’t taught the BabyComponent how to get hold of a baby. In our current implementation, we click on the link, load the BabyComponent , attempt to bind a baby to the BabyStatus component and there’s no baby to be found.

We can get hold of that missing baby by using the id route parameter when loading the component. The Angular router offers a service called ActivatedRoute that let’s you get access to the current route parameters in an asynchronous fashion.

Let’s update the BabyComponent class to use ActivatedRoute . Within baby.component.ts we write the following:

import { Component , OnInit } from '@angular/core' ; import { ActivatedRoute } from '@angular/router' ; import { Baby } from 'app/baby' ; @ Component ( { selector : 'app-baby' , templateUrl : './baby.component.html' , styleUrls : [ './baby.component.css' ] } ) export class BabyComponent implements OnInit { constructor ( private activatedRoute : ActivatedRoute ) { } ngOnInit ( ) { this . activatedRoute . params . subscribe ( p => { const key = p [ 'id' ] ; } ) ; } }

So using the params observable property of the ActivatedRoute service we can get hold of the :id route parameter that is the baby’s key in Firebase Realtime database.

Now that we have that key in our hand we can use it to retrieve our baby and expose it through the public interface of our component class.

What is that subscribe? So far we've only consumed observables within our templates by taking advantage of the async pipe. So what's this subscribe that we're using here? The subscribe method is the most common way to consume observables. Using subscribe you can provide a callback to subscribe to new bits of data that are made available over time via the observable. In the example above, you subscribe to receiving the router parameters of the route when it is loaded. The async pipe also subscribes itself to the observable but it does so behind the scenes. If you want to learn more about observables and rx.js I suggest that you take a look at the Gentle Introduction to Rx.js.

The next step is to update our baby component class to take that key and retrieve our baby from Firebase. Again on baby.component.ts write:

import { Component , OnInit } from '@angular/core' ; import { ActivatedRoute } from '@angular/router' ; import { AngularFireDatabase , FirebaseObjectObservable } from 'angularfire2/database' ; import { Baby } from 'app/baby' ; @ Component ( { selector : 'app-baby' , templateUrl : './baby.component.html' , styleUrls : [ './baby.component.css' ] } ) export class BabyComponent implements OnInit { baby : FirebaseObjectObservable < Baby > ; constructor ( private activatedRoute : ActivatedRoute , private db : AngularFireDatabase ) { } ngOnInit ( ) { this . activatedRoute . params . subscribe ( p => { const key = p [ 'id' ] ; this . baby = this . db . object ( ` /babies/ ${ key } ` ) ; } ) ; } }

In this case we’ll use the FirebaseObjectObservable type and the db.object method because we have a single object that we want to retrieve: our Baby . Since we expose a baby property in our component class the template can now bind to that property and show the baby status in the screen.

If you take a look at your app using ng serve -o you should see this beautiful masterpiece:

Now We can Take Care of The Baby

So we’ve got ourselves the baby status where we can see how well our baby and parenting is faring. The next thing that we want to do is add some controls so as a dad I can take care of my baby. Since this feels like a complete separate concern from displaying the baby status we create a new component:

PS > ng g c baby - care

This creates a brand new and shiny BabyCareComponent . But before we dive into implementing the component there’s one detail that we still need to contend with: How are we going to load this component inside the BabyComponent template?

Since I had some foresight in my initial prototyping I know that I want to have very similar views for my baby caring and my baby controlling. When going to this route baby/key/care I want to get a view like this one:

And when going to this other route baby/key/control I want to get a view like this other one:

These two views are very similar and a perfect use case for nested routes. In this scenario we can take advantage of the Angular router and define a new <router-outlet> inside the BabyComponent where we can inject either the BabyCareComponent or the future BabyControlRoomComponent based on the url selected.

So if we update our BabyComponent template as follows:

< section fxLayout = " column " fxLayoutAlign = " start center " fxLayoutGap = " 12px " > < md-card *ngIf = " baby | async; let baby; else loading " > < md-card-title > Baby Status </ md-card-title > < md-card-content > < app-baby-status [baby] = " baby " > </ app-baby-status > </ md-card-content > </ md-card > < ng-template #loading > Loading Baby Data... </ ng-template > < router-outlet > </ router-outlet > </ section >

And our routing configuration in app-routing.module.ts :

import { NgModule } from '@angular/core' import { Routes , RouterModule } from '@angular/router' import { BabiesComponent } from 'app/babies/babies.component' import { BabyComponent } from 'app/baby/baby.component' import { BabyControlRoomComponent } from 'app/baby-control-room/baby-control-room.component' import { BabyCareComponent } from 'app/baby-care/baby-care.component' const routes : Routes = [ { path : 'babies' , children : [ { path : '' , component : BabiesComponent , } , { path : ':id' , component : BabyComponent , children : [ { path : 'care' , component : BabyCareComponent , } , ] , } , ] , } , { path : '' , pathMatch : 'full' , redirectTo : 'babies' , } , { path : '**' , redirectTo : 'babies' , } , ] @ NgModule ( { imports : [ RouterModule . forRoot ( routes ) ] , exports : [ RouterModule ] , } ) export class AppRoutingModule { }

Now when we click on the Take care button in the BabiesComponent view we will be magically transported to a view where we can see the status of our baby and below, the magical words: baby care works!.

Implementing the Baby Care Component

Let’s add some caring into our app. The dad will be able to use the following techniques to improve the stats of the baby:

Feed : To remove hunger. Effect: reduce Hunger indicator

: To remove hunger. Clean : To clean the baby’s outputs. Effect: reduce Shittiness indicator

: To clean the baby’s outputs. Sleep : To put the baby to sleep and give him the rest he or she needs. Effect: reduce sleepiness indicator

: To put the baby to sleep and give him the rest he or she needs. Cuddle: The secret weapon in every parent arsenal that will not only affect all stats but will also increase a baby’s life indicator. Effect: reduce all indicators and increase life.

These actions will be represented by buttons in the BabyCareComponent template within baby-care.component.html :

< md-card > < md-card-content > < button md-raised-button color = " primary " (click) = " feedBaby() " > Feed </ button > < button md-raised-button color = " primary " (click) = " cleanBaby() " > Clean </ button > < button md-raised-button color = " primary " (click) = " sleepBaby() " > Sleep </ button > < button md-raised-button color = " accent " (click) = " cuddleBaby() " > Cuddle </ button > </ md-card-content > </ md-card >

These buttons are bound to different methods in the underlying component class baby-care.component.ts . We now need to implement them to update the baby’s stats. Let’s focus on one single of these methods for the sake of simplicity:

import { Component , OnInit } from '@angular/core' ; import { FirebaseApp } from 'angularfire2' ; import { ActivatedRoute } from '@angular/router' ; @ Component ( { selector : 'app-baby-care' , templateUrl : './baby-care.component.html' , styleUrls : [ './baby-care.component.scss' ] } ) export class BabyCareComponent implements OnInit { babyId ; constructor ( private activatedRoute : ActivatedRoute , private firebaseApp : FirebaseApp ) { } ngOnInit ( ) { this . activatedRoute . parent . params . subscribe ( p => this . babyId = p [ 'id' ] ) ; } feedBaby ( ) { const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } /hunger ` ) ; statRef . transaction ( stat => stat - 10 < 0 ? 0 : stat - 10 ) ; } }

In the code above we do a couple of things:

On component initialization we get a hold of the baby’s id by using the ActivatedRoute service. Since this is a nested route we use the activantedRoute.parent property to access the parent route parameters. We take a direct reference to the babies hunger property within Firebase realtime database and we execute a transaction to update it so that the effect of a caring action decreases hunger in the baby by a factor of 10. We need to do a transaction because we plan to have several clients increasing and decreasing that hunger value at the same time.

We now can extend the same logic to all of our caring methods:

import { Component , OnInit } from '@angular/core' ; import { FirebaseApp } from 'angularfire2' ; import { ActivatedRoute } from '@angular/router' ; @ Component ( { selector : 'app-baby-care' , templateUrl : './baby-care.component.html' , styleUrls : [ './baby-care.component.scss' ] } ) export class BabyCareComponent implements OnInit { babyId ; constructor ( private activatedRoute : ActivatedRoute , private firebaseApp : FirebaseApp ) { } ngOnInit ( ) { this . activatedRoute . parent . params . subscribe ( p => this . babyId = p [ 'id' ] ) ; } feedBaby ( ) { const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } /hunger ` ) ; statRef . transaction ( stat => stat - 10 < 0 ? 0 : stat - 10 ) ; } cleanBaby ( ) { const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } /shittiness ` ) ; statRef . transaction ( stat => stat - 10 < 0 ? 0 : stat - 10 ) ; } sleepBaby ( ) { const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } /sleepiness ` ) ; statRef . transaction ( stat => stat - 10 < 0 ? 0 : stat - 10 ) ; } cuddleBaby ( ) { const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } ` ) ; statRef . transaction ( baby => { if ( baby ) { baby . hunger = this . getDecreasedStat ( { statGetter : ( ) => baby . hunger , modifier : 10 } ) ; baby . shittiness = this . getDecreasedStat ( { statGetter : ( ) => baby . shittiness , modifier : 10 } ) ; baby . sleepiness = this . getDecreasedStat ( { statGetter : ( ) => baby . sleepiness , modifier : 10 } ) ; baby . life = this . getIncreasedStat ( { statGetter : ( ) => baby . life , modifier : 1 } ) ; } return baby ; } ) ; } getDecreasedStat ( { statGetter , modifier } ) { return statGetter ( ) > modifier ? statGetter ( ) - modifier : 0 ; } getIncreasedStat ( { statGetter , modifier } ) { return statGetter ( ) + modifier > 100 ? 100 : statGetter ( ) + modifier ; } }

If you go back to the browser you’ll now be able to see the following:

In order to do some testing, you can go into your Firebase Realtime Database Dashboard, modify the stats of the baby and then interact with the baby caring buttons to verify that indeed they are working. Yay! Victory!

Controlling Your Baby

The other side of things, the baby control room, will let you affect the needs, wants and desires of the baby and make him or her be hungry or sleepy.

Implementing the baby control room will be very similar to what we have just done in the previous section. We start by creating a new component:

PS > ng g c baby - control - room

We update the BabyControlRoomComponent template within baby-control-room.component.html to display a bunch of buttons:

< md-card > < md-card-title > Baby Secret Control Room </ md-card-title > < md-card-content > < button md-raised-button (click) = " babyHungry() " > I'm Hungry!! </ button > < button md-raised-button (click) = " babyShitty() " > I'm Dirty!! </ button > < button md-raised-button (click) = " babySleepy() " > I'm Sleepy!! </ button > </ md-card-content > </ md-card >

And we implement these babyHungry , babyShitty and babySleepy methods in the component class baby-control-room.component.ts :

import { Component , OnInit } from '@angular/core' ; import { ActivatedRoute } from '@angular/router' ; import { FirebaseApp } from 'angularfire2' ; @ Component ( { selector : 'app-baby-control-room' , templateUrl : './baby-control-room.component.html' , styleUrls : [ './baby-control-room.component.scss' ] } ) export class BabyControlRoomComponent implements OnInit { babyId : string ; constructor ( private activatedRoute : ActivatedRoute , private firebaseApp : FirebaseApp ) { } ngOnInit ( ) { this . activatedRoute . parent . params . subscribe ( p => this . babyId = p [ 'id' ] ) ; } babyHungry ( ) { const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } /hunger ` ) ; statRef . transaction ( stat => stat + 10 ) ; } babyShitty ( ) { const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } /shittiness ` ) ; statRef . transaction ( stat => stat + 10 ) ; } babySleepy ( ) { const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } /sleepiness ` ) ; statRef . transaction ( stat => stat + 10 ) ; } }

And that’s it. Remember to uncomment the small section that referred to this component in your routing configuration in app-routing.module.ts and now you should be able to take care, and control your baby.

Now you can do some proper old school manual testing by opening a couple of browser windows, one with the caring, the other with the controlling and seeing how interacting with the buttons in either window affects the other. Awesome!

Adding More User Feedback With Snack Bars

Before we wrap up this part, we’re going do to a couple of things more.

First we’ll add some more feedback for our dads to give them some encouragement when they take care of the baby. Luckily for us, Angular Material provides a service that allows us to display messages to our users: the MdSnackBar.

The MdSnackBar is very simple to use. You just need to inject the MdSnackBar service into your component and then use the following method to display a message:

this . mdSnackBar . open ( 'Hi you!' )

Let’s update our BabyCareComponent class to show a message to the dad every time they do a caring action:

import { Component , OnInit } from '@angular/core' ; import { FirebaseApp } from 'angularfire2' ; import { ActivatedRoute } from '@angular/router' ; import { MdSnackBar } from '@angular/material' ; import { RandomPickerService } from "app/random-picker.service" ; const messages = [ 'Awesome Dad!' , 'You rock Buddy!' , 'Hell yeah!' , 'Good job!!' , 'Saaaavyyy' , 'Dad of the Year!' , 'Go get a beer, you deserve it!' , 'Sweeeet!' ] ; @ Component ( { selector : 'app-baby-care' , templateUrl : './baby-care.component.html' , styleUrls : [ './baby-care.component.scss' ] } ) export class BabyCareComponent implements OnInit { babyId ; constructor ( private activatedRoute : ActivatedRoute , private firebaseApp : FirebaseApp , private mdSnackBar : MdSnackBar , private randomPicker : RandomPickerService ) { } ngOnInit ( ) { this . activatedRoute . parent . params . subscribe ( p => this . babyId = p [ 'id' ] ) ; } feedBaby ( ) { this . showMessage ( ) ; const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } /hunger ` ) ; statRef . transaction ( stat => stat - 10 < 0 ? 0 : stat - 10 ) ; } cleanBaby ( ) { this . showMessage ( ) ; const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } /shittiness ` ) ; statRef . transaction ( stat => stat - 10 < 0 ? 0 : stat - 10 ) ; } sleepBaby ( ) { this . showMessage ( ) ; const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } /sleepiness ` ) ; statRef . transaction ( stat => stat - 10 < 0 ? 0 : stat - 10 ) ; } cuddleBaby ( ) { this . showMessage ( ) ; const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } ` ) ; statRef . transaction ( baby => { if ( baby ) { baby . hunger = this . getDecreasedStat ( { statGetter : ( ) => baby . hunger , modifier : 10 } ) ; baby . shittiness = this . getDecreasedStat ( { statGetter : ( ) => baby . shittiness , modifier : 10 } ) ; baby . sleepiness = this . getDecreasedStat ( { statGetter : ( ) => baby . sleepiness , modifier : 10 } ) ; baby . life = this . getIncreasedStat ( { statGetter : ( ) => baby . life , modifier : 1 } ) ; } return baby ; } ) ; } getDecreasedStat ( { statGetter , modifier } ) { return statGetter ( ) > modifier ? statGetter ( ) - modifier : 0 ; } getIncreasedStat ( { statGetter , modifier } ) { return statGetter ( ) + modifier > 100 ? 100 : statGetter ( ) + modifier ; } showMessage ( ) { this . mdSnackBar . open ( this . randomPicker . pickAtRandom ( messages ) , null , { duration : 3000 } ) ; } }

Good! Now everytime the dad clicks on a care button he’ll get some nice encouragement like “You rock Buddy!” or “Sweeeet!”.

We can extend the same functionality to our BabyControlRoomComponent :

import { Component , OnInit } from '@angular/core' ; import { ActivatedRoute } from '@angular/router' ; import { AngularFireDatabase } from 'angularfire2/database' ; import { FirebaseApp } from 'angularfire2' ; import { MdSnackBar } from "@angular/material" ; import { RandomPickerService } from "app/random-picker.service" ; const messages = [ 'You are evil!' , 'I bow before you Dr Evil!' , 'Satanaaaas!!' , "Keepin' it real!" , "Wow that was mean!" , "You have no shame!" , "OMG reaaaallllly?" ] ; @ Component ( { selector : 'app-baby-control-room' , templateUrl : './baby-control-room.component.html' , styleUrls : [ './baby-control-room.component.scss' ] } ) export class BabyControlRoomComponent implements OnInit { babyId : string ; constructor ( private activatedRoute : ActivatedRoute , private firebaseApp : FirebaseApp , private mdSnackBar : MdSnackBar , private randomPicker : RandomPickerService ) { } ngOnInit ( ) { this . activatedRoute . parent . params . subscribe ( p => this . babyId = p [ 'id' ] ) ; } babyHungry ( ) { this . showMessage ( ) ; const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } /hunger ` ) ; statRef . transaction ( stat => stat + 10 ) ; } babyShitty ( ) { this . showMessage ( ) ; const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } /shittiness ` ) ; statRef . transaction ( stat => stat + 10 ) ; } babySleepy ( ) { this . showMessage ( ) ; const statRef = this . firebaseApp . database ( ) . ref ( ` /babies/ ${ this . babyId } /sleepiness ` ) ; statRef . transaction ( stat => stat + 10 ) ; } showMessage ( ) { this . mdSnackBar . open ( this . randomPicker . pickAtRandom ( messages ) , null , { duration : 3000 } ) ; } }

The final step is to deploy the first version of our app to the internets and make it available to the world with the aid of the Angular cli and Firebase Hosting.

Deploying Your App With the Angular CLI and Firebase Hosting

In addition to offering a helping hand during development and testing, the Angular cli also allows you to create a production optimized build with a single command:

PS > ng build - prod - aot

The -prod flag will tell angular to create a production build and the -aot flag will enable Ahead of Time compilation which will result in a smaller package and faster Angular loading times. The process will take a short while and at the end you’ll have a production-ready version of your application under the dist folder in your application root directory.

What is Ahead Of Time (AOT) compilation? The easiest way to explain AOT compilation is to start by explaining its opposite: JIT or Just-In-Time compilation. Any Angular application can be seen as a tree of components. For an Angular application to run in the browser we need to compile these components using the Angular compiler. By default, Angular uses Just-In-Time compilation and compiles your entire application (unless you use lazy loading for some of your modules) before loading it and before the user can start interacting with it. An important optimization when going into production is to do this compilation ahead of time. That is, instead of compiling your application each time the user loads it, we compile it as a build step and serve the user an already compiled version of your app. This is great for two reasons: The user doesn't need to wait for the Angular compiler to compile your application before he or she can start using it We don't even need to send the Angular Compiler to the user If you want to learn more about the Angular Compiler and the role of Compilation in Angular take a look at this great article by Victor Savkin.

So now that we have a production-ready version of our app sitting cozy inside the dist folder, the next thing is to use Firebase hosting to bring the baby-gotchi goodness to the world.

The best way to learn how to deploy your app to Firebase is to go to the Firebase Console, select your project, then go to Hosting and click on the Get Started button.

A beautifully looking dialog will open and prompt you to install the firebase-tools command line interface via npm. You install it globally:

PS > npm install - g firebase - tools

And after that you can use it through the firebase command.

First, we’ll need to sign up:

PS > firebase login

And setup your app as a Firebase project using the init command:

PS > firebase init

The init command will trigger a super duper awesome (look at those flames) step-by-step menu that will guide you through the setup process:

You basically need to enable Firebase Hosting and select the dist folder as the one that will hold your application files. As a result, the setup process will create a Firebase config file firebase.json that should look like this:

{ "hosting": { "public": "dist", "rewrites": [ { "source": "**", "destination": "/index.html" } ] } }

Where the rewrites section redirects any url to the source of your app which ensures that the Angular router will take care of every possible route.

The next step is to use this configuration to deploy your site. Type the following command:

PS > firebase deploy

And magic! Your site is now deployed on Firebase. When the deployment finishes take a look at your site by following the URL that the Firebase tools cli displays on your console.

Congratulations! You have deployed your baby-gotchi app into Firebase! Rejoice!!

Up Next! Cloud Functions and PWAs

Let’s make a quick summary of what you have achieved. In this part of the series you continued developing the baby-gotchi baby simulator and created new components to see the baby status, take care and control the baby.

Along the way you learnt a lot of new concepts like:

Using Angular route parameters and ActivatedRoute to load a baby detail view and get hold of the baby id

to load a baby detail view and get hold of the baby id How to use the AngularFireDatabase and FirebaseObjectObservable to get a single baby object and make it available to the template

and to get a single baby object and make it available to the template How to refactor your Angular application to create smaller components with a single responsibility

How to use lots of Angular Material components

How to setup and use nested routes

How to do transactional updates in Firebase to take care or control your baby

Building a production ready Angular application with the help of the Angular cli

The Benefits of Ahead of Time compilation

Deploying your app to Firebase Hosting using the firebase-tools

That was an awful lot of things! Congrats! Pat yourself in the back.

For our next feature, we will develop a baby heartbeat or baby lifecycle that updates the baby status over time using Firebase Cloud Functions. And in the last part of the series, we will give the baby-gotchi an awesome mobile experience by turning it into a Progressive Web App.

Until next time, take care and be awesome and kind!

The next part in the series is ready!