Build HERE Maps with Angular
Note
The 3.1 version of this API has been deprecated. For continued support and feature development, upgrade to the latest 3.2 version.
Angular provides a set of powerful tools and features for building web applications. You can create an even more engaging experience for your users by combining these features with HERE SDKs and APIs.
For example, you can integrate HERE Maps with Angular to display interactive maps, geocode addresses, calculate routes, and more, all within the context of your Angular application.
See the following sections for step-by-step instructions on how to create a simple interactive map within the context of an Angular application.
Before you begin
Sign up for a HERE developer account and obtain your API credentials. For more information, see Get started.
Install Angular CLI
Facilitate the development of a new Angular application by using the Angular CLI.
-
In the Command Prompt, enter the following command to install Angular CLI:
npm install -g @angular/cli -
Initiate a new Angular project by entering the following command:
ng new jsapi-angular && cd jsapi-angular -
At the
Which stylesheet format would you like to use?prompt, select theCSSoption. -
At the
Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)?prompt, press theNkey, to disable server-side rendering and static site generation prerendering.Result: The system installs the required packages and creates a new
jsapi-angulardirectory, with the Angular components residing in thesrcsub-directory. Thejsapi-angulardirectory has the following structure:jsapi-angular ├── node_modules ├── package.json ├── .gitignore ├── .browserslistrc ├── .editorconfig ├── angular.json ├── karma.conf.js ├── README.md ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.spec.json ├── dist │ ├── ... └── src ├── app │ ├── app-routing.module.ts │ ├── app.component.css │ ├── app.component.html │ ├── app.component.spec.ts │ ├── app.component.ts │ └── app.module.ts ├── assets │ ├── ... ├── environments | ├── ... ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.css └── test.ts -
In your project directory, install the
maps-api-for-javascriptNPM package which is hosted at https://repo.platform.here.com/ by adding a registry entry to the NPM configuration through the following command:npm config set @here:registry https://repo.platform.here.com/artifactory/api/npm/maps-api-for-javascript/ -
Install the package from the
@herenamespace by entering the following command:npm install @here/maps-api-for-javascript@1 -
Navigate to the
jsapi-angularfolder, and then open thetsconfig.jsonfile in a preferred text editor. -
In the
tsconfig.jsonfile, add the following setting underangularCompilerOptions:"allowSyntheticDefaultImports": true -
Optional: To verify that you completed the setup successfully, perform the following actions:
-
Enter the following command:
ng serveResult: This command launches a development server with the "hot reload" functionality.
-
Initiate the Angular application by navigating to the
http://localhost:4200/address in the browser.Result: The browser displays the Angular welcome screen with the
Congratulations! Your app is running.message.Tip
For Windows operating systems, to terminate the
ng serveprocess, pressq + Enter.
-
Add a static map component
In your Angular application, generate a static map by creating a component that contains an H.Map namespace instance. This component renders the map through the corresponding container.
-
In the Angular CLI, generate the jsmap component by entering the following command:
ng generate component jsmapResult: The command creates a
jsmapfolder in thesrc/appdirectory. The folder contains all the files required to build the component:└── src ├── app │ ├── jsmap | | ├── jsmap.component.css | | ├── jsmap.component.html | | ├── jsmap.component.spec.ts | | └── jsmap.component.ts │ ├── app-routing.module.ts │ ├── app.component.css │ ├── app.component.html │ ├── app.component.spec.ts │ ├── app.component.ts │ └── app.module.ts ... -
Navigate to the
jsapi-angular/src/app/jsmapdirectory, and then open thejsmap.component.tsfile. -
In the
jsmap.component.tsfile, replace the default code with the following code:import { Component, ViewChild, ElementRef } from '@angular/core'; import '@here/maps-api-for-javascript'; @Component({ selector: 'app-jsmap', standalone: true, templateUrl: './jsmap.component.html', styleUrls: ['./jsmap.component.css'] }) export class JsmapComponent { private map?: H.Map; @ViewChild('map') mapDiv?: ElementRef; ngAfterViewInit(): void { if (!this.map && this.mapDiv) { // Instantiate a platform, default layers and a map as usual. const platform = new H.service.Platform({ apikey: '{YOUR_API_KEY}' }); const layers = platform.createDefaultLayers(); const map = new H.Map( this.mapDiv.nativeElement, // Add type assertion to the layers object... // ...to avoid any Type errors during compilation. (layers as any).vector.normal.map, { pixelRatio: window.devicePixelRatio, center: {lat: 52.5, lng: 13.4}, zoom: 13, }, ); this.map = map; } } }This code imports the HERE Maps API for JavaScript library and instantiates the map through the
ngAfterViewInithook.Note
Replace
{YOUR_API_KEY}with a valid HERE API key. -
Open the
jsmap.component.htmlfile, and then replace the file contents with the following code:<div #map id="map"></div> -
Open the
jsmap.component.cssfile, and then add the following style:#map { width: 100%; height: 500px; } -
In the
jsapi-angular/src/appdirectory, open theapp.component.htmlfile, and then replace the file content with following code:<app-jsmap></app-jsmap> -
In the same directory, open the
app.component.tsfile and add the following elements:-
Add the
JsmapComponentimport statement:import { JsmapComponent } from './jsmap/jsmap.component'; -
In the
importsarray, addJsmapComponent:imports: [RouterOutlet, JsmapComponent],
See the following updated
app.component.tsfile for reference:import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; import { JsmapComponent } from './jsmap/jsmap.component'; @Component({ selector: 'app-root', standalone: true, imports: [RouterOutlet, JsmapComponent], templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'jsapi-angular'; } -
-
Verify that the map renders correctly by navigating to the
http://localhost:4200/address in the browser.
Result: The browser renders a static map centered on Berlin, at zoom level 13, in the viewport that is 500 pixels high and takes 100% of the enclosing container's width, similar to the following example:

Resize the map
A static map with a predetermined size cannot be changed during runtime.
You can improve a static map by adding dynamic resizing to make the map canvas react and adapt to the changes in the viewport size, for example, when the user expands the browser window.
To achieve that, the map needs an explicit resize() method call to adjust to the new dimensions of the container. This example uses simple-element-resize-detector to demonstrate how you can resize a map within an Angular component.
-
In Angular CLI, ensure that your working directory is the
jsapi-angulardirectory. -
Enter the following commands :
npm install simple-element-resize-detector --save npm install @types/simple-element-resize-detector --save-dev -
From the
src/app/jsmapdirectory, open thejsmap.component.tsfile, and then adjust the import statements by adding thesimple-element-resize-detectorlibrary, as shown in the following example:import { Component, ViewChild, ElementRef } from '@angular/core'; import '@here/maps-api-for-javascript'; import onResize from 'simple-element-resize-detector'; // New import statement -
Update
ngAfterViewInitmethod with themap.getViewPort().resize()method call, as shown in the following code snippet:ngAfterViewInit(): void { if (!this.map && this.mapDiv) { const platform = new H.service.Platform({ apikey: '{YOUR_API_KEY}' }); const layers = platform.createDefaultLayers(); const map = new H.Map( this.mapDiv.nativeElement, (layers as any).vector.normal.map, { pixelRatio: window.devicePixelRatio, center: {lat: 52.5, lng: 13.4}, zoom: 13, }, ); onResize(this.mapDiv.nativeElement, () => { map.getViewPort().resize(); }); // Sets up the event listener to handle resizing this.map = map; } }
Result: The component adjusts dynamically to the changes in the size of the enclosing browser window.
Set the map to respond to input parameters
Use another component to take your input to change the zoom level and the center of the map.
-
Create a new component by entering the following command in Angular CLI:
ng generate component mapposition -
Navigate to the
src/app/mappositiondirectory, and then open themapposition.component.htmlfile. -
Replace the default content of the
mapposition.component.htmlfile with the following code:<div class="input-group"> <label for="zoom">Zoom:</label> <input id="zoom" (change)="notify.emit($event)" name="zoom" type="number" value="13" /> </div> <div class="input-group"> <label for="lat">Latitude:</label> <input id="lat" (change)="notify.emit($event)" name="lat" type="number" value="52.5" /> </div> <div class="input-group"> <label for="lng">Longitude:</label> <input id="lng" (change)="notify.emit($event)" name="lng" type="number" value="13.4" /> </div>Note
The
mappositioncomponent has three input fields:zoom,latitudeandlongitude. The new code introduces achangeevent listener that redispatches events for each input field to the parent component. -
From the
src/app/mapposition/directory, open themapposition.component.cssfile, and then replace the default contents with the following basic style configuration:.input-group { margin-bottom: 5px; margin-top: 5px; display: flex; align-items: center; } label { width: 100px; font-weight: bold; } input[type="number"] { width: 100px; padding: 5px; margin-left: 10px; border: 1px solid #ccc; border-radius: 4px; } input[type="number"]:focus { border-color: #007bff; outline: none; } -
From the
src/app/mapposition/directory, open themapposition.component.tsfile, and then replace the file content with the following code:import { Component, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-mapposition', standalone: true, templateUrl: './mapposition.component.html', styleUrls: ['./mapposition.component.css'] }) export class MappositionComponent { @Output() notify = new EventEmitter(); }Note
This TypeScript part of the component uses the
@Outputdecorator and theEventEmitterclass to notify the parent component about the changes in the user input. -
From the
src/appdirectory, open theapp.component.htmlfile, and then replace the file contents with the following code:<app-jsmap [zoom]="zoom" [lat]="lat" [lng]="lng" ></app-jsmap> <app-mapposition (notify)="handleInputChange($event)" ></app-mapposition>Note
This code uses the parent
appcomponent to pass the values between the map and input fields. -
From the
src/appdirectory, open theapp.component.tsfile, and then add a change handler by replacing the file content with the following code:import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; import { JsmapComponent } from './jsmap/jsmap.component'; import { MappositionComponent } from './mapposition/mapposition.component'; // Imports MappositionComponent @Component({ selector: 'app-root', standalone: true, imports: [RouterOutlet, JsmapComponent, MappositionComponent], // Adds MappositionComponent to the AppComponent template templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'jsapi-angular'; // Initialized by the constructor, these properties store the current zoom level and coordinates (latitude and longitude) for the map constructor() { this.zoom = 13; this.lat = 52.5; this.lng = 13.4; } zoom: number; lat: number; lng: number; // Updates the zoom, lat, and lng properties based on user input. handleInputChange(event: Event) { const target = <HTMLInputElement> event.target; if (target) { if (target.name === 'zoom') { this.zoom = parseFloat(target.value); } if (target.name === 'lat') { this.lat = parseFloat(target.value); } if (target.name === 'lng') { this.lng = parseFloat(target.value); } } } }Result: The change handler updates the values according to the user's input and Angular passes these values to the
jsmapcomponent. -
From the
src/app/jsmapdirectory, open thejsmap.component.tsfile, and then perform the following actions:- Adjust the first import statement to include
InputandSimpleChangesclasses, as shown in the following example:import { Component, ViewChild, ElementRef, Input, SimpleChanges } from '@angular/core'; - Within the
JsmapComponentclass, after the existingngAfterViewInithook definition, add@Inputdecorators for zoom, latitude, and longitude, and then add thengOnChangeshook definition, as shown in the following code snippet:@Input() public zoom = 13; @Input() public lat = 52.5; @Input() public lng = 13.4; ngOnChanges(changes: SimpleChanges) { if (this.map) { if (changes['zoom'] !== undefined) { this.map.setZoom(changes['zoom'].currentValue); } if (changes['lat'] !== undefined) { this.map.setCenter({lat: changes['lat'].currentValue, lng: this.lng}); } if (changes['lng'] !== undefined) { this.map.setCenter({lat: this.lat, lng: changes['lng'].currentValue}); } } }
- Adjust the first import statement to include
Result: Now, your Angular application can take your input with the help of the mapposition component, store the state in the app component, and then update the jsmap component so that the map responds to the input.
The following example demonstrates how the Angular application responds to the input by setting the coordinates to center the map on Berlin, and then increasing the zoom level:

Enable dragging and zooming
Further increase the interactivity of your map by enabling map manipulation in the form of dragging or zooming in or out of the view.
To achieve this behavior, add the mapviewchange listener to the H.Map instance, and then update the app state with the help of the EventEmitter.
-
In the
app.component.tsfile, update theAppstate by adding the following code:handleMapChange(event: H.map.ChangeEvent) { if (event.newValue.lookAt) { const lookAt = event.newValue.lookAt; this.zoom = lookAt.zoom; this.lat = lookAt.position.lat; this.lng = lookAt.position.lng; } } -
In the
app.component.htmlfile, replace the current content with the following code:<app-jsmap [zoom]="zoom" [lat]="lat" [lng]="lng" (notify)="handleMapChange($event)" ></app-jsmap> <app-mapposition [zoom]="zoom" [lat]="lat" [lng]="lng" (notify)="handleInputChange($event)" ></app-mapposition> -
Update the
jsmap.component.tsfile by performing the following actions:-
In the
jsmap.component.tsfile, adjust the import statement by adding theOutputandEventEmitterclasses, as shown in the following example:import { Component, ViewChild, ElementRef, Input, SimpleChanges, Output, EventEmitter } from '@angular/core'; -
Update the
ngAfterViewInithook by attaching the listener that enables the interactive behavior after the map instantiation:map.addEventListener('mapviewchange', (ev: H.map.ChangeEvent) => { this.notify.emit(ev) }); new H.mapevents.Behavior(new H.mapevents.MapEvents(map)); -
Update the
ngOnChangesmethod to throttle the unnecessary map updates:private timeoutHandle: any; @Output() notify = new EventEmitter(); ngOnChanges(changes: SimpleChanges) { clearTimeout(this.timeoutHandle); this.timeoutHandle = setTimeout(() => { if (this.map) { if (changes['zoom'] !== undefined) { this.map.setZoom(changes['zoom'].currentValue); } if (changes['lat'] !== undefined) { this.map.setCenter({lat: changes['lat'].currentValue, lng: this.lng}); } if (changes['lng'] !== undefined) { this.map.setCenter({lat: this.lat, lng: changes['lng'].currentValue}); } } }, 100); }
-
-
In the
mapposition.component.tsfile, update the component to reflect the current position of the map:- Import the
Inputdecorator from the@angular/core, as shown in the following example:import { Component, Output, EventEmitter, Input } from '@angular/core'; - Add the following input parameters in the class body:
@Input() public zoom = 13; @Input() public lat = 52.5; @Input() public lng = 13.4;
- Import the
-
In the
mapposition.component.htmlfile, adjust the template by replacing the file content with the following code:<div class="input-group"> <label for="zoom">Zoom:</label> <input id="zoom" (change)="notify.emit($event)" name="zoom" type="number" [value]="zoom" /> </div> <div class="input-group"> <label for="lat">Latitude:</label> <input id="lat" (change)="notify.emit($event)" name="lat" type="number" [value]="lat" /> </div> <div class="input-group"> <label for="lng">Longitude:</label> <input id="lng" (change)="notify.emit($event)" name="lng" type="number" [value]="lng" /> </div>
Result: The resulting application consist of the interactive map and input fields. When you interact with the map, the application automatically updates the input fields, as shown in the following example:

Optional: Add markers
The Angular application that you just created might serve as a template for adding further customizations or extensions that suit your business objectives. For example, you can add map markers to provide a quick and efficient way to visually represent the location of a point of interest on a map.
-
In the
jsmap.component.tsfile, set the modify themapproperty to center on the area where you want to place the markers, as shown in the following example:const map = new H.Map( this.mapDiv.nativeElement, (layers as any).vector.normal.map, { pixelRatio: window.devicePixelRatio, // In this example, the map centers on // the HERE Technologies office in Berlin: zoom: 19, center: { lat: 52.53074, lng: 13.38492 } }, ); -
Create a variable storing the marker SVG markup:
const mapMarkerSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48" fill="none" stroke="#0F1621" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"> <path fill="#00AFAA" d="M24 4C16.26 4 10 10.26 10 18c0 9.74 14 26 14 26s14-16.26 14-26c0-7.74-6.26-14-14-14z"/> <circle cx="24" cy="18" r="6" fill="#1D1E1F"/> </svg>` -
Set up a marker with an SVG icon at a specific location on the map by defining the following variables:
const icon = new H.map.Icon(mapMarkerSvg); const coords = {lat: 52.53074, lng: 13.38492}; const marker = new H.map.Marker(coords, { data: null, icon: icon }); -
Add the marker to the map, making it visible at the specified coordinates:
map.addObject(marker); -
Center the map view on the location of the marker:
map.setCenter(coords);
Result: The map in your Angular application now centers on and displays a marker at the selected location, as illustrated in the following figure:
For more information on markers, see Marker Objects.
Code samples
The following sections contains the full code samples for Jsmap, App, and Mapposition, which are the main Angular components used in this tutorial.
Jsmap component
View the jsmap.component.ts source code.
Click to expand/collapse the code sample
import { Component, ViewChild, ElementRef, Input, SimpleChanges, Output, EventEmitter } from '@angular/core';
import '@here/maps-api-for-javascript';
import onResize from 'simple-element-resize-detector';
@Component({
selector: 'app-jsmap',
standalone: true,
templateUrl: './jsmap.component.html',
styleUrls: ['./jsmap.component.css']
})
export class JsmapComponent {
private map?: H.Map;
@ViewChild('map') mapDiv?: ElementRef;
ngAfterViewInit(): void {
if (!this.map && this.mapDiv) {
const platform = new H.service.Platform({
apikey: 'YOUR_HERE_API_KEY'
});
const layers = platform.createDefaultLayers();
const map = new H.Map(
this.mapDiv.nativeElement,
(layers as any).vector.normal.map,
{
pixelRatio: window.devicePixelRatio,
center: {lat: 52.53074, lng: 13.38492},
zoom: 19,
},
);
onResize(this.mapDiv.nativeElement, () => {
map.getViewPort().resize();
});
this.map = map;
map.addEventListener('mapviewchange', (ev: H.map.ChangeEvent) => {
this.notify.emit(ev)
});
new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
const mapMarkerSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48" fill="none" stroke="#0F1621" stroke-width="4" stroke-linecap="round" stroke-linejoin="round">
<path fill="#00AFAA" d="M24 4C16.26 4 10 10.26 10 18c0 9.74 14 26 14 26s14-16.26 14-26c0-7.74-6.26-14-14-14z"/>
<circle cx="24" cy="18" r="6" fill="#1D1E1F"/>
</svg>`
const icon = new H.map.Icon(mapMarkerSvg);
const coords = {lat: 52.53074, lng: 13.38492};
const marker = new H.map.Marker(coords, { data: null, icon: icon });
map.addObject(marker);
map.setCenter(coords);
}
}
@Input() public zoom = 13;
@Input() public lat = 52.5;
@Input() public lng = 13.4;
private timeoutHandle: any;
@Output() notify = new EventEmitter();
ngOnChanges(changes: SimpleChanges) {
clearTimeout(this.timeoutHandle);
this.timeoutHandle = setTimeout(() => {
if (this.map) {
if (changes['zoom'] !== undefined) {
this.map.setZoom(changes['zoom'].currentValue);
}
if (changes['lat'] !== undefined) {
this.map.setCenter({lat: changes['lat'].currentValue, lng: this.lng});
}
if (changes['lng'] !== undefined) {
this.map.setCenter({lat: this.lat, lng: changes['lng'].currentValue});
}
}
}, 100);
}
}Note
Replace
YOUR_HERE_API_KEYin the previous code sample with a valid API key.
App component
View the app.component.ts source code.
Click to expand/collapse the code sample
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { JsmapComponent } from './jsmap/jsmap.component';
import { MappositionComponent } from './mapposition/mapposition.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, JsmapComponent, MappositionComponent],
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'jsapi-angular';
constructor() {
this.zoom = 13;
this.lat = 52.5;
this.lng = 13.4;
}
zoom: number;
lat: number;
lng: number;
handleInputChange(event: Event) {
const target = <HTMLInputElement> event.target;
if (target) {
if (target.name === 'zoom') {
this.zoom = parseFloat(target.value);
}
if (target.name === 'lat') {
this.lat = parseFloat(target.value);
}
if (target.name === 'lng') {
this.lng = parseFloat(target.value);
}
}
}
handleMapChange(event: H.map.ChangeEvent) {
if (event.newValue.lookAt) {
const lookAt = event.newValue.lookAt;
this.zoom = lookAt.zoom;
this.lat = lookAt.position.lat;
this.lng = lookAt.position.lng;
}
}
}Mapposition component
View the mapposition.component.ts source code.
Click to expand/collapse the code sample
import { Component, Output, EventEmitter, Input } from '@angular/core';
@Component({
selector: 'app-mapposition',
standalone: true,
templateUrl: './mapposition.component.html',
styleUrls: ['./mapposition.component.css']
})
export class MappositionComponent {
@Output() notify = new EventEmitter();
@Input() public zoom = 13;
@Input() public lat = 52.5;
@Input() public lng = 13.4;
}Optional: Switch to the HARP engine
You can configure your map to provide users with up-to-date, customizable, and visually engaging map experiences by configuring your map to use the HARP engine.
-
In the
tsconfig.jsonfile, within thecompilerOptionsobject, add the following option:"allowJs": true -
In the
main.tsfile, add the following statement:import '@here/maps-api-for-javascript/bin/mapsjs.bundle.harp' -
In the
jsmap.component.tsfile, edit thelayersandmapvariables to use the HARP engine for map instatiation, as shown in the following example:// Declare HARP as the engine type within // the layers variable const layers = platform.createDefaultLayers({ engineType: H.Map.EngineType.HARP }); const map = new H.Map( this.mapDiv.nativeElement, (layers as any).vector.normal.map, { // Set the engine type for the H.Map instance engineType: H.Map.EngineType.HARP, pixelRatio: window.devicePixelRatio, zoom: 19, center: { lat: 52.53074, lng: 13.38492 } }, );
The swich to the HARP engine is reflected by a change in the map's look and feel, as shown in the following example:
Next steps
To further explore the design and features of the Maps API for JavaScript, see the API Reference.
Updated yesterday