Bing Maps With Angular in a Spring Boot Application
How to integrate Bing Maps with Angular to show different site properties at different points in time with a Spring Boot backend.
Join the DZone community and get the full member experience.Join For Free
The purpose of the AngularAndSpringWithMaps project is to show the site properties at different points in time. To choose the site and then choose the time and have the site properties displayed in a map. New properties can be added and deleted on the map and then persisted. This article will show how to store and display company sites.
The site properties are stored in these Entities:
- CompanySite -> the site that contains the properties at the location for the year. All the necessary contained entities are loaded.
- Polygon -> a property at the CompanySite with multiple Rings; a Polygon can contain holes.
- Ring -> a ring of location points that makes up a property or a hole in a property (could be a lake).
- Location -> a location point of a ring.
The initial test data is provided by Liquibase with the files in this directory. For information about setting up Liquibase with Spring Boot, these articles (article 1, article 2) help a lot. For loading the initial data this article can help.
The CompanySiteRepository to get the site for the year:
In lines 2-3, the
companySite with a name containing the name string and the year is selected.
The company sites are loaded with the CompanySiteService:
In lines 2-6, empty titles or titles shorter than two characters are filtered out and the beginning and end of the year are set.
In lines 7-10, the
companySite are selected from the DB and the entity tree is ordered with the
In lines 13-18, the
companySite entity locations are ordered to get the property borders. This is done in code because the locations are selected by JPA.
The REST endpoint is implemented in CompanySiteController:
In lines 1-3, the base REST endpoint is defined.
In lines 5-9, the
CompanySiteService is injected with the constructor.
In lines 11-14, the REST endpoint to get a company site by
year is defined. The variables are defined in the
@RequestMapping and read in parameters with
In lines 15-19, the
companySites are read with the
CompanySiteService and then mapped in a stream with the EntityToDtoMapper to dtos for the front-end.
In lines 20-21, the result is returned in a
ResponseEntity with the HTTP status
The documentation for Bing Maps can be found here. Bing provides types for the API. Bing Maps support the data structures polygon/ring/location that are supported in the backend. For the components Material is used.
In the package.json file, the libraries are built for Ivy postinstall and the types are added:
In line 10, the libraries are built for Ivy after the install.
In line 19, the types for
bingmaps are added for TypeScript.
The map is displayed in the CompanySite component with this template:
In line 2, the formGroup
componentForm is set as reactive form for the component.
In lines 6-20, a <mat-form-field> wraps a <input> with a <mat-autocomplete> feature. The <input> is connected to the formControl
companySite. The <mat-autocomplete> is connected to the input with
#auto and the
matAutocomplete property. The <mat-options> of the <mat-autocomplete> show the titles of the
companySiteOptions observable. That is all that is needed for a typeahead with Material components.
In lines 23-26, <mat-slider> is added to select the year it starts with 1970 and ends with 2020 and is connected to the formControl
In lines 27-30, a <span> is added to display the year of the slider.
In line 36, a <div> is added with
#bingMap to provide the container that displays the map.
The CompanySite component is set up like this:
In lines 1-6, the Component is defined with the needed live cycle callback interfaces.
In lines 7-8, the
elementRef for the map is injected.
In line 11, the
map property is defined.
In line 14, the observable for the autocomplete input is defined.
In lines 15-19, the reactive form with initial values is created.
In line 25, the
containerInitSubject is created that emits when the initial values are available.
In lines 26-28, the hot subscriptions are defined to be unsubscribed in the
In lines 30-34, the needed elements get injected in the constructor. The
FormBuilder has been used to create the reactive form.
To read the companySite data the CompanySiteService is used:
This is a simple service that uses the
HttpClient to get the matching
CompanySites for the title and year.
The BingMapsService is used to load the newest version and initialize the
mapcontrol component from Bing:
In lines 1-5, the singleton service is defined with the
initialized property set to false.
In lines 8-10, it checks if Bing Maps has already been initialized.
In lines 11-12, a unique callback name for the successful load of Bing Maps is created and the URL with the name and
apiKey is set.
In lines 13-19, the new script tag in the document head is created.
In lines 20-29, the
scriptPromise is setup. The Bing Maps callback resolves and sets initialized to true. The
onerror script callback logs and rejects.
In line 30, an observable is created from the promise and gets returned.
The CompanySite is initialized like this:
In lines 8-17, the
mat-autocomplete is the service call that gets the options for the auto complete. The reactive form refreshes the options on value change and debounces it. Then there is a minimum validity check and either the matching
companySites are retrieved from the server or the empty observable is returned.
In lines 18-29, the newly selected
companySites of the auto complete are debounced and filtered for selected sites. Then they are retrieved from the server and filtered for empty responses. Then the
updateMap method is called to display the new site on the map.
In lines 30-41, the values of the
mat-slider component are debounced and there is a filter that ensures that it only works if a
companySite is selected. Then the
companySites for the selected year are retrieved from the server and are filtered for empty responses. Then the
updateMap method is called to display the site at the selected year on the map.
In lines 42-50,
forkJoin is used to send the requests for the MainConfigration with the Bing Maps key and the initial
CompanySite concurrently. The responses come in an array where the
mainConfiguration is in first element and the companySites in the second. They are set in the property and in the Container object. The Container object is send with next in the
ngAfterViewInit method, the the map of bing is initialized because the view has to be available for it. In lines 54-59, the
containerInitSubject is used to make sure the
companySite and the configuration is send. A validation check is done. Then
flatMap is used with the
BingMapsService is used to initialize the map.
In lines 64-73, the
IMapLoadOptions interface is created with the current center for the new Map.
In lines 73-75, the new map is created on the
bingContainer property with the
In line 77, the
companySite is set in the form.
In lines 78-79, the the polygons are updated for the map.
In lines 80-81, the listener for clicks on the map is set.
In lines 86-90, the
containerInitSubject gets cleared with next and the hot subscribtions are unsubscribed. The the map gets disposed.
In line 93, it is checked that the map is initialized.
In lines 94-98, the
IMapLoadOptions of the Bing Map are updated.
In lines 99-100, the entities of the map are cleared and the polygons are recreated.
Spring Boot with JPA and H2/Postgresql makes storing map data easy.
Bing Maps provides nice types for the TypeScript interface. That makes it much easier to use the API and with the types the API is easy to understand. Integrating Bing Maps was pretty straight forward. It needs to be added in the
ngAfterViewInit because the
ElementRef has to be available. The Angular Material components are easy to use and to integrate with RxJS and reactive forms.
The next article will describe how to to add and remove properties to a
companySite by clicking on the map.
The testdata for the year 2020 shows the property of a factory where the product of the article image is made.
Opinions expressed by DZone contributors are their own.