diff --git a/src/app/city/city-selector.component.ts b/src/app/city/city-selector.component.ts index 69954124..05de6b4f 100644 --- a/src/app/city/city-selector.component.ts +++ b/src/app/city/city-selector.component.ts @@ -20,7 +20,7 @@ export class CitySelectorComponent { ) {} public cities: City[] = this.dataService.getLocationMetadata()[1]; - public cityObservable: Observable = this.cityService.city; + public cityObservable: Observable = this.cityService.city; changeCity(city: City): void { this.layoutService.flyToCity(city); diff --git a/src/app/city/city.service.ts b/src/app/city/city.service.ts index 57a24960..7d0a8232 100644 --- a/src/app/city/city.service.ts +++ b/src/app/city/city.service.ts @@ -89,8 +89,8 @@ type _CheckCityAndFountainDoNotOverlapp = ExpectNever(null); - get city(): Observable { + private readonly citySubject = new BehaviorSubject(undefined); + get city(): Observable { return this.citySubject.asObservable(); } setCity(city: City) { diff --git a/src/app/core/selector.component.ts b/src/app/core/selector.component.ts index cbf28b97..b2c346a9 100644 --- a/src/app/core/selector.component.ts +++ b/src/app/core/selector.component.ts @@ -10,7 +10,7 @@ import { LayoutService } from './layout.service'; export class SelectorComponent { @Input() tooltipText!: string; @Input() options!: T[]; - @Input() valueObservable!: Observable; + @Input() valueObservable!: Observable; @Input() changeHook!: (value: T) => void; @Input() translationPrefix!: string; diff --git a/src/app/data.service.ts b/src/app/data.service.ts index 3c2f22d9..010cf6c2 100644 --- a/src/app/data.service.ts +++ b/src/app/data.service.ts @@ -63,16 +63,16 @@ export class DataService { @Output() fountainSelectedSuccess: EventEmitter = new EventEmitter(); @Output() apiError: EventEmitter = new EventEmitter(); @Output() fountainsLoadedSuccess: EventEmitter = new EventEmitter(); - @Output() fountainsFilteredSuccess: EventEmitter = new EventEmitter(); + @Output() fountainsFilteredSuccess: EventEmitter = new EventEmitter(); @Output() directionsLoadedSuccess: EventEmitter = new EventEmitter(); - @Output() fountainHighlightedEvent: EventEmitter = new EventEmitter(); + @Output() fountainHighlightedEvent: EventEmitter = new EventEmitter(); private apiUrl = buildInfo.branch === 'stable' ? environment.apiUrlStable : environment.apiUrlBeta; - private _currentFountainSelector: FountainSelector | null = null; - private _fountainsAll: FountainCollection | null = null; - private _fountainsFiltered: Fountain[] | null = null; + private _currentFountainSelector: FountainSelector | undefined = undefined; + private _fountainsAll: FountainCollection | undefined = undefined; + private _fountainsFiltered: Fountain[] | undefined = undefined; private _filter: FilterData = defaultFilter; - private _city: City | null = null; + private _city: City | undefined = undefined; private _fountainPropertiesMeta: FountainPropertiesMeta = fountainProperties; private _locationsCollection: LocationsCollection = locationsCollection; @@ -112,7 +112,7 @@ export class DataService { cityObservable = this.cityService.city; - get fountainsAll(): FountainCollection | null { + get fountainsAll(): FountainCollection | undefined { return this._fountainsAll; } @@ -183,13 +183,13 @@ export class DataService { // TODO @ralf.hauser change to Observable, should not fetch data in service but pass on to component // share in order that we don't have to re-fetch for each subscription // Get the initial data - private loadCityData(city: City | null, forceRefresh = false): void { - if (city !== null) { + private loadCityData(city: City | undefined, forceRefresh = false): void { + if (city !== undefined) { console.log(city + ' loadCityData ' + new Date().toISOString()); const fountainsUrl = `${this.apiUrl}api/v1/fountains?city=${city}&refresh=${forceRefresh}`; // remove current fountains - this.fountainsFilteredSuccess.emit(null); + this.fountainsFilteredSuccess.emit(undefined); // get new fountains this.http.get(fountainsUrl).subscribeOnce( @@ -420,7 +420,7 @@ export class DataService { new Date().toISOString() ); // only filter if there are fountains available - if (this._fountainsAll !== null) { + if (this._fountainsAll !== undefined) { // console.log("'"+filterText + "' filterFountains "+new Date().toISOString()) this._fountainsFiltered = this._fountainsAll.features.filter(fountain => this.filterFountain(fountain, filterText, filter, phActive, phModeWith) @@ -460,7 +460,7 @@ export class DataService { // If only one fountain is left, select it (wait a second because maybe the user is not done searching setTimeout(() => { const filtered = this._fountainsFiltered; - if (filtered !== null && filtered.length === 1 && filtered[0] !== undefined) { + if (filtered !== undefined && filtered.length === 1 && filtered[0] !== undefined) { console.log( 'filterFountains: opening the only photo machting: ' + (phActive ? "'with" + (phModeWith ? "'" : "out'") : '') + @@ -469,7 +469,7 @@ export class DataService { new Date().toISOString() ); this.selectFountainByFeature(filtered[0]); - } else if (filtered === null || filtered.length === 0) { + } else if (filtered === undefined || filtered.length === 0) { if (null != filterText && 0 < filterText.trim().length) { const alias = lookupFountainAlias(filterText); if (null != alias && 0 < alias.trim().length) { @@ -484,7 +484,7 @@ export class DataService { } } - highlightFountain(fountain: Fountain | null): void { + highlightFountain(fountain: Fountain | undefined): void { if (!environment.production) { if (fountain) { const id = getId(fountain); @@ -500,7 +500,7 @@ export class DataService { console.log('sortByProximity ' + new Date().toISOString()); if (this._fountainsAll !== null) { this.userLocationService.userLocation.subscribeOnce(location => { - if (location !== null) { + if (location !== undefined) { console.log('sortByProximity: loc ' + location + ' ' + new Date().toISOString()); if (this._fountainsAll) { this._fountainsAll.features.forEach(f => { @@ -517,7 +517,7 @@ export class DataService { return f1.properties['distanceFromUser'] - f2.properties['distanceFromUser']; }); } - } else if (this._fountainsAll !== null) { + } else if (this._fountainsAll !== undefined) { // if no location defined, but fountains are available this._fountainsAll.features.sort((f1, f2) => { // trick to push fountains without dates to the back @@ -560,13 +560,7 @@ export class DataService { }; what = 'osmId ' + fProps['id_osm']; } else { - fountainSelector = { - queryType: 'byCoords', - lat: fountain.geometry.coordinates[1], - lng: fountain.geometry.coordinates[0], - radius: 50, - }; - what = 'coords ' + fountainSelector.lat + '/' + fountainSelector.lng; + illegalState('neither id_wikidata nor id_osm on properties defined', fProps); } if (!environment.production) { this.cityService.city.subscribeOnce(city => { @@ -938,7 +932,7 @@ export class DataService { } else { fProps['gallery'].value = this.getStreetView(fountain); } - this._currentFountainSelector = null; + this._currentFountainSelector = undefined; this.layoutService.switchToDetail(fountain, fountainSelector); if (updateDatabase) { @@ -1040,7 +1034,7 @@ export class DataService { } else { fProps['gallery'].value = this.getStreetView(fountain); } - this._currentFountainSelector = null; + this._currentFountainSelector = undefined; this.layoutService.switchToDetail(fountain, selector); if (updateDatabase) { @@ -1098,17 +1092,9 @@ export class DataService { } // force Refresh of data for currently selected fountain - forceRefresh(): void { + forceRefreshForCurrentFountain(): void { this.fountainService.fountainSelector.subscribeOnce(currentFountainSelector => { - if (currentFountainSelector !== null) { - // const coords = fountainSelected?.geometry.coordinates; - // const selector: FountainSelector = { - // queryType: 'byCoords', - // lat: coords?.[1], - // lng: coords?.[0], - // radius: 50, - // }; - + if (currentFountainSelector !== undefined) { this.selectFountainBySelector(currentFountainSelector, true); } }); @@ -1125,13 +1111,13 @@ export class DataService { this.fountainService.fountain .switchMap(fountain => { - if (fountain !== null) { + if (fountain !== undefined) { return combineLatest([ this.userLocationService.userLocation, this.languageService.langObservable, this.directionsService.travelMode, ]).switchMap(([userLocation, lang, travelMode]) => { - if (userLocation === null) { + if (userLocation === undefined) { return this.translateService.get('action.navigate_tooltip').tap(alert); } else { const url = `https://api.mapbox.com/directions/v5/mapbox/${travelMode}/${userLocation.lng},${userLocation.lat};${fountain.geometry.coordinates[0]},${fountain.geometry.coordinates[1]}?access_token=${environment.mapboxApiKey}&geometries=geojson&steps=true&language=${lang}`; diff --git a/src/app/detail/detail.component.ts b/src/app/detail/detail.component.ts index 518f28cb..7827e255 100644 --- a/src/app/detail/detail.component.ts +++ b/src/app/detail/detail.component.ts @@ -90,7 +90,7 @@ export class DetailComponent implements OnInit { combineLatest([this.fountainService.fountain, this.langObservable]).subscribe( ([fountain, lang]) => { try { - if (fountain !== null) { + if (fountain !== undefined) { this.fountain = fountain; // determine which properties should be displayed in table const fProps = fountain.properties; @@ -225,7 +225,7 @@ export class DetailComponent implements OnInit { forceRefresh(id: string): void { console.log('refreshing ' + id + ' ' + new Date().toISOString()); - this.dataService.forceRefresh(); + this.dataService.forceRefreshForCurrentFountain(); } getNearestStations(): void { diff --git a/src/app/fountain/fountain.service.ts b/src/app/fountain/fountain.service.ts index b92f28b5..2e8f926d 100644 --- a/src/app/fountain/fountain.service.ts +++ b/src/app/fountain/fountain.service.ts @@ -11,12 +11,12 @@ interface FountainAndSelector { @Injectable() export class FountainService { private readonly fountainAndSelectorSubject = new BehaviorSubject(null); - get fountain(): Observable { - return this.fountainAndSelectorSubject.map(x => (x === null ? null : x.fountain)); + get fountain(): Observable { + return this.fountainAndSelectorSubject.map(x => x?.fountain); } - get fountainSelector(): Observable { - return this.fountainAndSelectorSubject.map(x => (x === null ? null : x.selector)); + get fountainSelector(): Observable { + return this.fountainAndSelectorSubject.map(x => x?.selector); } private readonly selectedPropertySubject = new BehaviorSubject(null); diff --git a/src/app/guide/guide.component.ts b/src/app/guide/guide.component.ts index 8a9e0c0a..f3aaab00 100644 --- a/src/app/guide/guide.component.ts +++ b/src/app/guide/guide.component.ts @@ -125,7 +125,7 @@ export class GuideSelectorComponent implements OnInit { this.dataService.forceLocationRefresh(); } public forceLocalRefresh(): void { - this.dataService.forceRefresh(); + this.dataService.forceRefreshForCurrentFountain(); } openGuide(id: string | null = null): void { diff --git a/src/app/list/list.component.html b/src/app/list/list.component.html index 2576e068..c0f077a2 100644 --- a/src/app/list/list.component.html +++ b/src/app/list/list.component.html @@ -10,7 +10,7 @@
diff --git a/src/app/list/list.component.ts b/src/app/list/list.component.ts index f3a8475e..5d75d1c4 100644 --- a/src/app/list/list.component.ts +++ b/src/app/list/list.component.ts @@ -41,7 +41,7 @@ export class ListComponent implements OnInit { ngOnInit(): void { this.subscriptionService.registerSubscriptions( this.dataService.fountainsFilteredSuccess.subscribe(data => { - if (data !== null) { + if (data !== undefined) { this.fountains = data; this.total_fountain_count = this.dataService.getTotalFountainCount(); this.filtered_fountain_count = this.fountains.length; @@ -55,7 +55,7 @@ export class ListComponent implements OnInit { // TODO @ralf.hauser The following lines actually interfer with caching and should not be done here. // that's a huge side effect which not only list.component.ts depends on this.fountainService.fountain.subscribe(currentFountain => { - if (currentFountain !== null) { + if (currentFountain !== undefined) { const fountainID = currentFountain.properties['id']; for (const fountain of this.fountains) { @@ -69,7 +69,7 @@ export class ListComponent implements OnInit { ); } - public highlightFountain(fountain: Fountain | null): void { + public highlightFountain(fountain: Fountain | undefined): void { this.layoutService.isMobile.subscribeOnce(isMobile => { if (!isMobile) { this.dataService.highlightFountain(fountain); diff --git a/src/app/map/map.component.ts b/src/app/map/map.component.ts index 9956799c..64c6f342 100644 --- a/src/app/map/map.component.ts +++ b/src/app/map/map.component.ts @@ -75,7 +75,7 @@ export class MapComponent implements OnInit { // when the city is changed, update map bounds this.cityService.city.subscribe(city => { - if (city !== null) { + if (city !== undefined) { this.zoomToCity(city); console.log('city "' + city + '" ' + new Date().toISOString()); } @@ -120,7 +120,7 @@ export class MapComponent implements OnInit { // if (this.map.isStyleLoaded()) { // this.filterMappedFountains(fountainList); // } - if (fountainList !== null) { + if (fountainList !== undefined) { const fountains: FountainCollection = { features: fountainList, type: 'FeatureCollection', @@ -145,7 +145,7 @@ export class MapComponent implements OnInit { // when user location changes, update map this.userLocationService.userLocation.subscribe(location => { - if (location !== null && this.userMarker !== undefined) { + if (location !== undefined && this.userMarker !== undefined) { this.userMarker.setLngLat(location).remove().addTo(this.map); this.map.flyTo({ @@ -286,8 +286,8 @@ export class MapComponent implements OnInit { return prop['id_osm']; } - private highlightFountainOnMap(fountain: Fountain | null): void { - if (!fountain) { + private highlightFountainOnMap(fountain: Fountain | undefined): void { + if (fountain === undefined) { // hide popup, not right away setTimeout(() => { if (this.highlightPopup !== undefined) { @@ -485,7 +485,7 @@ export class MapComponent implements OnInit { }) ); this.map.on('mouseleave', 'fountains', () => { - this.highlightFountainOnMap(null); + this.highlightFountainOnMap(undefined); this.map.getCanvas().style.cursor = ''; }); this.map.on('dblclick', event => { diff --git a/src/app/map/user-location.service.ts b/src/app/map/user-location.service.ts index aa861cae..46d3d50f 100644 --- a/src/app/map/user-location.service.ts +++ b/src/app/map/user-location.service.ts @@ -4,8 +4,8 @@ import { LngLat } from '../types'; @Injectable() export class UserLocationService { - private readonly userLocationSubject = new BehaviorSubject(null); - get userLocation(): Observable { + private readonly userLocationSubject = new BehaviorSubject(undefined); + get userLocation(): Observable { return this.userLocationSubject.asObservable(); } setUserLocation(longLat: LngLat) { diff --git a/src/app/services/route-validator.service.ts b/src/app/services/route-validator.service.ts index 0c82bce4..d117e5aa 100644 --- a/src/app/services/route-validator.service.ts +++ b/src/app/services/route-validator.service.ts @@ -330,10 +330,9 @@ export class RouteValidatorService { return this.fountainService.fountainSelector.map(fountainSelector => { // Get query parameter values from app state. use short query params by default for #159 const queryParams: QueryParams = { - l: this.languageService.currentLang, // use short language by default - // mode: state.mode, + l: this.languageService.currentLang, // use short language by default// mode: state.mode, }; - if (fountainSelector !== null && !(typeof fountainSelector === 'string')) { + if (fountainSelector !== undefined) { if (fountainSelector.queryType === 'byCoords') { // if selection by coordinates queryParams.lat = fountainSelector.lat;