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.
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
- Built the
BabiesComponentas 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
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:
1 2 3
The short-hand notation is surprisingly easy to guess. Just pick the first letter of a word (like
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 :
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:
1 2 3 4 5
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
The Baby Status Component
Let’s start with the component for the baby status. Again, Angular cli for the win:
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
A couple of things happen in this template:
- We use the
[class]property binding to set a class on the
.babyelement 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:
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
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
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:
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:
1 2 3 4 5
We also update its styles
1 2 3 4 5 6 7
And, of course, its underlying component class
1 2 3 4 5 6 7 8 9 10 11 12
Using this new component will make our original
BabyStatusComponent less wordy and simpler:
1 2 3 4 5 6 7 8 9 10 11 12
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
baby.component.html which looked like this:
We can continue by substituting that with this:
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
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:
1 2 3 4 5
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
baby.component.ts we write the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
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?
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
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:
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
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:
1 2 3 4 5 6 7 8 9 10 11 12
And our routing configuration in
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
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
- Clean: To clean the baby’s outputs. Effect: reduce Shittiness indicator
- Sleep: To put the baby to sleep and give him the rest he or she needs. Effect: reduce sleepiness indicator
- 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
1 2 3 4 5 6 7 8
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
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
ActivatedRouteservice. Since this is a nested route we use the
activantedRoute.parentproperty to access the parent route parameters.
- We take a direct reference to the babies
hungerproperty 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
hungervalue at the same time.
We now can extend the same logic to all of our caring methods:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
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:
We update the
BabyControlRoomComponent template within
baby-control-room.component.html to display a bunch of buttons:
1 2 3 4 5 6 7 8
And we implement these
babySleepy methods in the component class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
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.
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:
Let’s update our
BabyCareComponent class to show a message to the dad every time they do a caring action:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
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:
-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.
Using the Firebase Tools To Deploy Your App
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:
And after that you can use it through the
First, we’ll need to sign up:
And setup your app as a Firebase project using 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:
1 2 3 4 5 6 7 8 9 10 11
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:
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
ActivatedRouteto load a baby detail view and get hold of the baby id
- How to use the
FirebaseObjectObservableto 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
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!