Sibling interactions with subjects

The main reason for components to interact is to send or receive updates to data either provided by the user or received from the server. In Angular, your services expose RxJS.Observable endpoints, which are data-streams that your components can subscribe to. RxJS.Observer compliments RxJS.Observable as a consumer of events emitted by Observable. RxJS.Subject brings the two sets of functionalities together, in an easy to work with object. You can essentially describe a stream that belongs to a particular set of data, such as the current weather data that is being displayed, with subjects:

src/app/weather/weather.service.ts
import { Subject } from 'rxjs'
...
export class WeatherService implements IWeatherService {
currentWeather: Subject<ICurrentWeather>
...
}

currentWeather is still a data stream and does not simply represent one data point. You can subscribe to changes to currentWeather data with subscribe, or you can publish changes to it as follows:

example
currentWeather.subscribe(data => (this.current = data))
currentWeather.next(newData)

The default behavior of Subject is very much like generic pub/sub mechanisms, such as jQuery events. However, in an asynchronous world where components are loaded or unloaded in ways that are unpredictable, using the default Subject is not very useful.

There are three different types of Subjects:

  • ReplaySubject: It will remember and cache all data points occurred within the data stream so that a subscriber can replay all events at any given time
  • BehaviorSubject: It remembers only the last data point, while continuing to listen for new data points
  • AsyncSubject: This is for one-time only events that are not expected to reoccur

ReplaySubject can have severe memory and performance implications on your application, so it should be used with care. In the case of current-weather, we are only interested in displaying the latest weather data received, but through user input or other events we are open to receiving new data, so we can keep the current-weather component up to date. The BehaviorSubject would be the appropriate mechanism to meet these needs:

  1. Define BehaviorSubject in weatherService and set a default value:
app/src/weather/weather.service.ts
import { BehaviorSubject } from 'rxjs'
...
export class WeatherService implements IWeatherService {
currentWeather = new BehaviorSubject<ICurrentWeather>({
city: '--',
country: '--',
date: Date.now(),
image: '',
temperature: 0,
description: '',
})
...
}
  1. Update the current-weather component to subscribe to the new BehaviorSubject:
app/src/current-weather/current-weather.component.ts
...
ngOnInit() {
this.weatherService.currentWeather.subscribe(data => (this.current = data))
}
...
  1. Update the city-search component to publish the data it receives to BehaviorSubject:
app/src/city-search/city-search.component.ts
...
this.weatherService
.getCurrentWeather(
userInput[0],
userInput.length > 1 ? userInput[1] : undefined
)
.subscribe(data => this.weatherService.currentWeather.next(data))
...
  1. Test your app in the browser; it should look as follows:
Weather Information for Bursa, Turkey

When you type in a new city, the component should update for the current weather information for that city.

There's still room for improvement; the default experience looks broken when the app first loads. There are at least two different ways to handle this. The first is at the app component level to hide the entire component if there's no data to display. For this to work, we will have to inject weatherService to the app component, ultimately leading to a less flexible solution. Another way is to be able to better handle missing data within the current-weather component.

To make the app better, you can implement geolocation to get weather for the user's current location at launch of the app. You can also leverage window.localStorage to store the city that was last displayed or the last location that was retrieved from window.geolocation on initial launch.

Don't forget to execute npm test and npm run e2e before moving on. It is left as an exercise for the reader to fix the unit and end-to-end tests.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.245.233