Skip to content

Commit 4af7b4b

Browse files
author
Andrew Evans
committed
error handling setup with NgRx
1 parent b8a2f4f commit 4af7b4b

File tree

9 files changed

+44
-19
lines changed

9 files changed

+44
-19
lines changed

src/app/actions/location.actions.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,24 @@ export enum LocationActionTypes {
99
export class LocationAction implements Action {
1010
type: string;
1111
payload: {
12-
locationData: LocationData
12+
locationData: LocationData,
13+
error: string
1314
};
1415
}
1516

1617
export class LoadLocations implements Action {
1718
readonly type = LocationActionTypes.LoadLocations;
1819

19-
constructor(readonly payload: {locationData: LocationData}) {
20+
constructor(readonly payload: {locationData: LocationData, error: null}) {
2021

2122
}
2223
}
2324

2425
export class LocationsError implements Action {
2526
readonly type = LocationActionTypes.LocationsError;
2627

27-
constructor(errorMessage: string) {
28-
alert(errorMessage);
28+
constructor(readonly payload: {locationData: null, error: string}) {
29+
2930
}
3031
}
3132

src/app/cards/about-desktop/about-desktop.component.html

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
<li>Goose Picture was made at <a href="https://www.flaticon.com/authors/smalllikeart" title="smalllikeart">smalllikeart</a> from
1111
<a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by
1212
<a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></li>
13-
<li>Time displayed is Eastern Standard Format</li>
1413
<li>Temperature displayed is in Fahrenheit</li>
1514
<li>Speed displayed is in Miles Per Hour</li>
1615
</ul>

src/app/cards/about-mobile/about-mobile.component.html

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
<li>Goose Picture was made at <a href="https://www.flaticon.com/authors/smalllikeart" title="smalllikeart">smalllikeart</a> from
1313
<a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by
1414
<a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></li>
15-
<li>Time displayed is Eastern Standard Format</li>
1615
<li>Temperature displayed is in Fahrenheit</li>
1716
<li>Speed displayed is in Miles Per Hour</li>
1817
</ul>

src/app/effects/weather.effects.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { AppState } from '../reducers';
66
import { Store } from '@ngrx/store';
77
import { WeatherService } from '../services/weather.service';
88
import { LocationActionTypes, LocationsError, LoadLocations } from '../actions/location.actions';
9-
import { of } from 'rxjs';
9+
import { of, throwError } from 'rxjs';
1010

1111
@Injectable()
1212
export class WeatherEffects {
@@ -20,7 +20,7 @@ export class WeatherEffects {
2020
map(weather => {
2121
this.store.dispatch(new LoadWeather({weatherData: weather}));
2222
}),
23-
catchError((error) => of(new LocationsError(error)))
23+
catchError((errorMessage) => throwError(this.store.dispatch(new LocationsError({locationData: null, error: errorMessage}))))
2424
))
2525
);
2626

src/app/reducers/index.ts

+14-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { WeatherData } from '../models/weather-data/weather-data';
44
import { WeatherActionTypes, WeatherAction } from '../actions/weather.actions';
55
import { LocationActionTypes, LocationAction } from '../actions/location.actions';
66
import { LocationData } from '../models/location-data/location-data';
7+
import { state } from '@angular/animations';
78

89
export interface WeatherState {
910
weatherData: WeatherData| null;
@@ -15,10 +16,12 @@ const initialWeatherState: WeatherState = {
1516

1617
export interface LocationState {
1718
location: LocationData| null;
19+
error: string| null;
1820
}
1921

2022
const initialLocationState: LocationState = {
21-
location: null
23+
location: null,
24+
error: null
2225
};
2326

2427
export interface AppState {
@@ -42,7 +45,14 @@ export function locationReducer(state: LocationState = initialLocationState, act
4245
switch (action.type) {
4346
case LocationActionTypes.LoadLocations:
4447
return {
45-
location: action.payload.locationData
48+
location: action.payload.locationData,
49+
error: null
50+
};
51+
52+
case LocationActionTypes.LocationsError:
53+
return {
54+
location: null,
55+
error: action.payload.error
4656
};
4757

4858
default:
@@ -58,4 +68,6 @@ export const reducers: ActionReducerMap<AppState> = {
5868

5969
export const selectWeather = (state: AppState) => state.weather.weatherData;
6070

71+
export const selectError = (state: AppState) => state.location.error;
72+
6173
export const metaReducers: MetaReducer<any>[] = !environment.production ? [] : [];

src/app/weather/weather.component.html

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
</mat-toolbar-row>
1919
</mat-toolbar>
2020
<div class="page">
21+
<div *ngIf="error != undefined">
22+
<h1 class="alert alert-danger">Error: {{ error }}</h1>
23+
</div>
2124
<mat-grid-list cols="3" rowHeight="29em">
2225
<mat-grid-tile *ngFor="let card of cards | async" [colspan]="card.cols" [rowspan]="card.rows">
2326
<mat-card class="dashboard-card">

src/app/weather/weather.component.ts

+18-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Component, OnInit } from '@angular/core';
2-
import { map, startWith } from 'rxjs/operators';
1+
import { Component, OnInit, OnDestroy } from '@angular/core';
2+
import { map, startWith, takeUntil } from 'rxjs/operators';
33
import { Breakpoints, BreakpointObserver } from '@angular/cdk/layout';
44
import { WeatherService } from '../services/weather.service';
55
import { CurrentConditionsComponent } from '../cards/current-conditions/current-conditions.component';
@@ -9,11 +9,11 @@ import { HourlyForecastComponent } from '../cards/hourly-forecast/hourly-forecas
99
import { AboutDesktopComponent } from '../cards/about-desktop/about-desktop.component';
1010
import { AboutMobileComponent } from '../cards/about-mobile/about-mobile.component';
1111
import { Store } from '@ngrx/store';
12-
import { AppState } from '../reducers';
12+
import { AppState, selectError } from '../reducers';
1313
import { LoadLocations } from '../actions/location.actions';
1414
import { LocationData } from '../models/location-data/location-data';
1515
import { FormControl } from '@angular/forms';
16-
import { Observable } from 'rxjs';
16+
import { Observable, Subject } from 'rxjs';
1717
import * as USCities from '../../assets/us_cities.json';
1818
import { City } from '../models/city/city';
1919
import { MatAutocompleteSelectedEvent } from '@angular/material';
@@ -24,7 +24,7 @@ import { LoadWeather } from '../actions/weather.actions';
2424
templateUrl: './weather.component.html',
2525
styleUrls: ['./weather.component.css']
2626
})
27-
export class WeatherComponent implements OnInit {
27+
export class WeatherComponent implements OnInit, OnDestroy {
2828

2929
lat: string;
3030
long: string;
@@ -38,6 +38,8 @@ export class WeatherComponent implements OnInit {
3838
filteredCities: Observable<City[]>;
3939
cities = [];
4040
mobileView = false;
41+
error: string;
42+
private unsubscribeError: Subject<void> = new Subject<void>();
4143

4244
cards = this.breakpointObserver.observe(Breakpoints.Handset).pipe(
4345
map(({ matches }) => {
@@ -159,6 +161,11 @@ export class WeatherComponent implements OnInit {
159161
}
160162

161163
ngOnInit(): void {
164+
this.store
165+
.select(selectError)
166+
.pipe(takeUntil(this.unsubscribeError))
167+
.subscribe((error) => this.error = error);
168+
162169
try {
163170
navigator.geolocation.getCurrentPosition((position) => {
164171
this.savePosition(position);
@@ -178,7 +185,7 @@ export class WeatherComponent implements OnInit {
178185
}
179186
}
180187

181-
this.store.dispatch(new LoadLocations({locationData: this.locationData}));
188+
this.store.dispatch(new LoadLocations({locationData: this.locationData, error: null}));
182189
}
183190

184191
onSelectionChanged(event: MatAutocompleteSelectedEvent) {
@@ -187,10 +194,14 @@ export class WeatherComponent implements OnInit {
187194
this.locationData.latitude = city.latitude;
188195
this.locationData.longitude = city.longitude;
189196
this.store.dispatch(new LoadWeather({weatherData: null}));
190-
this.store.dispatch(new LoadLocations({locationData: this.locationData}));
197+
this.store.dispatch(new LoadLocations({locationData: this.locationData, error: null}));
191198
break;
192199
}
193200
}
194201
}
195202

203+
ngOnDestroy() {
204+
this.unsubscribeError.next();
205+
}
206+
196207
}

src/environments/environment.prod.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export const environment = {
22
production: true,
3-
openWeatherMapAPIKey: 'f415e81f4b5b26584ae0621649972862',
3+
openWeatherMapAPIKey: 'OPEN_WEATHER_MAP_API_KEY',
44
noaaMetaDataEndpoint: 'https://api.weather.gov/points/'
55
};

src/environments/environment.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
export const environment = {
66
production: false,
7-
openWeatherMapAPIKey: 'f415e81f4b5b26584ae0621649972862',
7+
openWeatherMapAPIKey: 'OPEN_WEATHER_MAP_API_KEY',
88
noaaMetaDataEndpoint: 'https://api.weather.gov/points/'
99
};
1010

0 commit comments

Comments
 (0)