Again the main feature for users is the ability to add their favorite cities so they can easily see and track their temperatures on the home page.

Firebase Service:

Before we dive into any HTML or CSS we should set up a service that the “add component” will consume in order to write to the Firebase Firestore database for which cities the user decides to add.

Create a new service for Firebase and call it fb.service.ts or you can just run the CLI command: ng g s services/fb/fb

import AngularFireLiteFirestore from angularfire-lite and inject it in the constructor. Then create a new function called addCity( cityName ) which will use the AngularFireLite write function to write to the database inside the document uid/cityName . As we are creating the function that will write to the database I thought of the Home component that will fetch this data when the user logs in so I let’s create also a function to read the cities that the user added and call it getCities()

Note this.auth.uid() is used from AngularFireLiteAuth service to retrieve the currently signed in user ID (will cover authentication later in this tutorial)

Add City Component:

let's start with the layout and here I thought of having a search input and next to it a place to display a featured city that the user can follow (I chose Rome here for example but you can easily make it random and fetch an image of each city using Unspalsh free and public API).

going through the major parts of this HTML line by line: 👊

line 1: just a wrapper for the entire HTML component

line 4: main card wrapper

line 8: wrapper for the left part of the card (search section)

line 10: card left section header wrapper

line 11: card left section title

line 12: card left search input wrapper

line 13–17: card left search input with 2-way data binding using [(ngModel)] , (keyup.enter) event to search for the city when the user hits the enter on his keyboard, auto-complete directive to instruct angular to use the library @ngui/auto-complete , [source] to feed the library with auto-complete options available to the user that we will fetch from an api and store inside a variable holding all the capital cities

line 18: simple button with a click event listener that will trigger our city search function

line 19: search icon inside the button

line 28: card left body where the searched card will appear

line 29: a notice text in a span with conditional *ngIf to show it only when its needed

line 30: reusing the app-weather-card component to show the city that the user searched and we pass in all the necessary props in order for the component to properly render the city.

the left card section:

the autocomplete component functionality is imported the @ngui/auto-complete library and before we cover the right section HTML make sure to do a quick npm install @ngui/auto-complete and then import its module inside the imports array of app.module.ts like so:

import {NguiAutoCompleteModule} from '@ngui/auto-complete'; @NgModule({

...

imports: [ NguiAutoCompleteModule ...],

....

})

now let's tackle the card right section

line 38: card right section wrapper

line 40: card right section background image (using absolute positioning)

line 44: card right section header wrapper containing a simple h3 tittle, a small text wrapped in a span and hr tag as a visual separator

line 50–115: card right section body section containing an svg at the top to display the weather conditions of the featured city (in this case Rome) using the *ngSwitch directive and at the bottom we find simple interpolation to display the {{ temp }} variable in order to show the city temperature in the template(HTML)

and now let’s jump to the component CSS

If you are still not used to large Angular components you might think that around 600 lines of CSS are overwhelming but honestly, this is nothing and the CSS above is pretty easy as most of the proprieties are self-explanatory and repetitive but still…I will go through some of them quickly with you:

we used flexbox by setting the display property to flex and we used justify-content to move the content on the horizontal axis and align-items on the vertical axis (if the flex-flow is set to column the axis flip)

and we used to move the content on the horizontal axis and on the vertical axis (if the flex-flow is set to column the axis flip) margin or padding are used to create a space around an item

color / background color used for setting the text and background color

used for setting the text and background color border-radius used to make the borders rounded

used to make the borders rounded overflow used to control how the browser deals with content outside a div for example (hide it or show scroll bar and allow the user to scroll)

used to control how the browser deals with content outside a div for example (hide it or show scroll bar and allow the user to scroll) letter/word-spacing used to increase the space between the letters or words. this trick is used in design to enhance readability or drive emphasis to a text (Text Kerning)

used to increase the space between the letters or words. this trick is used in design to enhance readability or drive emphasis to a text (Text Kerning) box-shadow used to add a light shadow behind a div and make it look like a card

📱 Making It Responsive + Generating Media Queries

using intab.io to test Minimus in iPhone 11 + pixel devices with realtime sync

as you can see in the last part of add.component.css most of the CSS is wrapped within a media queries which looks something like this

@media screen and (max-width:1919px) { CSS goes here… }

basically these means do not apply the CSS inside the brackets unless the screen is smaller than `1919px` but the question is how did you know which screen size to use. well, every app is different and there is no rule other than testing which works best.

you can resize the browser to find out the perfect media query size but I personally find resizing and switching back and forth between the code editor and the browser is tedious and time-consuming so I use intab.io (but you don’t have to) a browser extension I created to test and generate media queries for various mobile/tablets sizes. It is just a faster way to test and make a website responsive.

🧪 you can test it live — no sign up required at intab.io

Now moving on to the component logic in add.component.ts

at the top, we import everything we need from the Angular HttpClient & both the WeatherService and FbService then we inject them in the constructor.

if you are still not familiar with the different component life cycle hooks, they simply function that fire at specific points of time during the life of a component. For example, ngOnInit() will fire when Angular initialized the component and this is the best place to make any HTTP calls. on the other hand, ngOnDestroy() will fire just before the component gets destroyed (removed from the page) and it is the best place to unsubscribe from any ongoing subscriptions we made during the component initialization to avoid memory leaks.

ngOnInit breakdown:

line 30–33: calling the getWeather function found inside the WeatherService to get the weather conditions of the city the user searched for and storing the temperature and the weather condition inside the appropriate variables (temp & state)

line 35–42: using the HttpClient to call the “resetcountries” API which will return to us a list of all cities that we will use to feed the search autocomplete input with it. ( no need to unsubscribe here because it’s a one time call and piping the RXJS first() operator helps us to do so)

line 44–51: calling the firebase database to check if the user has already followed the city of the month to conditionally display (Followed or Follow +) inside the button as well as change the button style using [ngClass]

<button> {{followedCM ? "FOLLOWED" : "FOLLOW"}} </button>

functions breakdown:

selectCity: this will get executed when the user hits search and basically here we check if the city name is valid (a capital city) then we show the add city card otherwise we toggle a Boolean value to show a warning note to the user

addCityOfTheMonth: calls the addCity method found in fb.service.ts to add the city of the month inside the user collection of cites stored in Firebase Firestore database.

ngOnDestory: just calling unsubscribe on the ongoing subscription in the component.