Define your model using interfaces

Now that your View and ViewModel are in place, you need to define your Model. If you look back on the design, you will see that the component needs to display:

  • City
  • Country
  • Current date
  • Current image
  • Current temperature
  • Current weather description

You will first create an interface that represents this data structure:

  1. In the terminal, execute npx ng generate interface ICurrentWeather
  2. Observe a newly generated file named icurrent-weather.ts with an empty interface definition that looks like this:
src/app/icurrent-weather.ts
export interface ICurrentWeather {
}

This is not an ideal setup, since we may add numerous interfaces to our app and it can get tedious to track down various interfaces. Over time, as you add concrete implementations of these interfaces as classes, then it will make sense to put classes and their interfaces in their own files.

Why not just call the interface CurrentWeather? This is because later on we may create a class to implement some interesting behavior for CurrentWeather. Interfaces establish a contract, establishing the list of available properties on any class or interface that implements or extends the interface. It is always important to be aware of when you're using a class versus an interface. If you follow the best practice to always start your interface names with a capital I, you will always be conscious of what type of an object you are passing around. Hence, the interface is named ICurrentWeather.

  1. Rename icurrent-weather.ts to interfaces.ts
  2. Correct the capitalization of the interface name to ICurrentWeather
  1. Also, implement the interface as follows:
src/app/interfaces.ts
export interface ICurrentWeather {
city: string
country: string
date: Date
image: string
temperature: number
description: string
}

This interface and its eventual concrete representation as a class is the Model in MVVM. So far, I have highlighted how various parts of Angular fit the MVVM pattern; going forward, I will be referring to these parts with their actual names.

Now, we can import the interface into the component and start wiring up the bindings in the template of CurrentWeatherComponent.

  1. Import ICurrentWeather
  2. Switch back to the templateUrl and styleUrls
  3. Define a local variable called current with type ICurrentWeather
src/app/current-weather/current-weather.component.ts
import { Component, OnInit } from '@angular/core'
import { ICurrentWeather } from '../interfaces'

@Component({
selector: 'app-current-weather',
templateUrl: './current-weather.component.html',
styleUrls: ['./current-weather.component.css'],
})
export class CurrentWeatherComponent implements OnInit {
current: ICurrentWeather

constructor() {}

ngOnInit() {}
}

If you just type current: ICurrentWeather, you can use the auto-fixer to automatically insert the import statement.

In the constructor, you will temporarily populate the current property with dummy data to test your bindings.

  1. Implement dummy data as a JSON object and declare its adherence to ICurrentWeather using the as operator:
src/app/current-weather/current-weather.component.ts
...
constructor() {
this.current = {
city: 'Bethesda',
country: 'US',
date: new Date(),
image: 'assets/img/sunny.svg',
temperature: 72,
description: 'sunny',
} as ICurrentWeather
}
...

In the src/assets folder, create a subfolder named img and place an image of your choice to reference in your dummy data.

You may forget the exact properties in the interface you created. You can get a quick peek at them by holding Ctrl + hover-over the interface name with your mouse, as shown:

Ctrl + hover-over the interface

Now you update the template to wire up your bindings with a rudimentary HTML-based layout.

  1. Implement the template:
src/app/current-weather/current-weather.component.html
<p>
<p>
<span>{{current.city}}, {{current.country}}</span>
<span>{{current.date | date:'fullDate'}}</span>
</p>
<p>
<img [src]='current.image'>
<span>{{current.temperature | number:'1.0-0'}}</span>
</p>
<p>
{{current.description}}
</p>
</p>

To change the display formatting of current.date, we used the DatePipe above, passing in 'fullDate' as the format option. In Angular, various out-of-the-box and custom pipe | operators can be used to change the appearance of data without actually changing the underlying data. This is a very powerful, convenient, and flexible system to share such user interface logic without writing repetitive boilerplate code. In the preceding example, we could pass in 'shortDate' if we wanted to represent the current date in a more compact form. For more information on various DatePipe options, refer to the documentation at https://angular.io/api/common/DatePipeTo format current.temperature so that no fractional values are shown, you can use DecimalPipe. The documentation is at https://angular.io/api/common/DecimalPipe.

Note that you can render ℃ and ℉ using their respective HTML codes:  for ℃ and  for ℉.

  1. If everything worked correctly, you app should be looking similar to this screenshot:

App after wiring up bindings with dummy data

Congratulations, you have successfully wired up your first component.