Hands on

Display HERE Maps within your Angular Web Application

By Nic Raboy | 05 September 2018

It is incredibly easy to include a map within your web application using the HERE JavaScript API as long as you’re using vanilla JavaScript, but how do you include a map in your application if you’re using one of the more popular frameworks like Angular? Frameworks like Angular typically have a transpile process and a specific way to do business.

We’re going to see numerous approaches to including a map in your Angular application using the HERE JavaScript API and how easy it is to do so in comparison to vanilla JavaScript.

The goal of this project will be to render a map that looks like the following:

here-map-angular

While it is a basic project, we’re going to see two different approaches towards solving the problem with Angular.

The Requirements

There are a few requirements that must be met prior to developing a web application with Angular and displaying a map on the screen.

  1. The Angular CLI must be installed and configured.
  2. A HERE developer account must have been registered with an App ID and App Code available.

If you’re new to Angular, the Angular CLI can be obtained through the Node Package Manager (NPM). A HERE developer account can be created for free from the Developer Portal.

Creating a New Angular Project with the Angular CLI

With the development prerequisites in place, the next logical step is to create a fresh project to work with. Somewhere on your computer, execute the following command from your command line:

ng new here-project

The above command will create a new project directory with the appropriate Angular boilerplate files.

With the project created, the appropriate JavaScript libraries must be loaded to work with maps and the other location services.

Open the project’s src/index.html file and include the following:

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>HERE with Angular</title>
        <base href="/">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="icon" type="image/x-icon" href="favicon.ico">
    </head>
    <body>
        <app-root></app-root>
        <script src="https://js.api.here.com/v3/3.0/mapsjs-core.js" type="text/javascript" charset="utf-8"></script>
        <script src="https://js.api.here.com/v3/3.0/mapsjs-service.js" type="text/javascript" charset="utf-8"></script>
    </body>
</html>

In the above HTML markup, notice that the scripts are loaded before the <body> tag closes. This will eliminate the risk of any render blocking JavaScript.

At this point in time, we can start developing an application that includes a map.

Including a HERE Map within your Angular Component

The first approach towards including a map component in our application is convenient, but probably only for the short term and not at scale. Neither approach is wrong, but it is a good idea to look at both approaches.

Open the project’s src/app/app.component.html file and include the following:

<div #map style="width: 1280px; height: 768px"></div>

If you’ve read the official documentation for the HERE API with JavaScript, the above line might look loosely familiar. Basically it is going to act as a container for the map component. However, we are no longer working with an id and instead are working with a #map. The #map acts as an Angular template variable which is more appropriate when trying to work directly with the DOM rather than using data bindings.

Now open the project’s src/app/app.component.ts file so we can add our TypeScript logic that performs the bulk of our work:

import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';

declare var H: any;

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

    private platform: any;

    @ViewChild("map")
    public mapElement: ElementRef;

    public constructor() {
        this.platform = new H.service.Platform({
            "app_id": "APP-ID-HERE",
            "app_code": "APP-CODE-HERE"
        });
    }

    public ngOnInit() { }

    public ngAfterViewInit() {
        let defaultLayers = this.platform.createDefaultLayers();
        let map = new H.Map(
            this.mapElement.nativeElement,
            defaultLayers.normal.map,
            {
                zoom: 10,
                center: { lat: 37.7397, lng: -121.4252 }
            }
        );
    }

}

In the AppComponent class we are creating a ViewChild variable using the #map variable name and assigning it to a TypeScript variable that we can continue to use.

In the constructor method we are initializing the HERE platform service using the App ID and App Code that we obtain through our developer account. The constructor method is triggered when the component is created.

This takes us to the ngAfterViewInit method which is triggered after the HTML view is initialized. Because we are working with a UI component, it is not a good idea to run any map related code until we’re sure the UI has rendered. When we initialize the map, we use the mapElement variable that is linked to the HTML.

You can test the application by executing the following from your command line:

ng serve

In this scenario everything is more or less hard-coded and is not really able to be recycled within the application. The second approach is going to change this.

Developing a Map Component with Custom Input Attributes

The next approach is to create a component to strictly maintain the map and nothing else. Within this component we can define input attributes so values can be defined via HTML attributes and not directly in the TypeScript.

With the command line within your project’s path, execute the following command:

ng g component here-map

The above command will create a new Angular component and link it within the project’s src/app/app.module.ts file.

Open the project’s src/app/here-map/here-map.component.ts file so we can define the core logic:

import { Component, OnInit, ViewChild, ElementRef, Input } from '@angular/core';

declare var H: any;

@Component({
    selector: 'here-map',
    templateUrl: './here-map.component.html',
    styleUrls: ['./here-map.component.css']
})
export class HereMapComponent implements OnInit {

    @ViewChild("map")
    public mapElement: ElementRef;

    @Input()
    public appId: any;

    @Input()
    public appCode: any;

    @Input()
    public lat: any;

    @Input()
    public lng: any;

    @Input()
    public width: any;

    @Input()
    public height: any;

    public constructor() { }

    public ngOnInit() { }

    public ngAfterViewInit() {
        let platform = new H.service.Platform({
            "app_id": this.appId,
            "app_code": this.appCode
        });
        let defaultLayers = platform.createDefaultLayers();
        let map = new H.Map(
            this.mapElement.nativeElement,
            defaultLayers.normal.map,
            {
                zoom: 10,
                center: { lat: this.lat, lng: this.lng }
            }
        );
    }

}

The above code is similar to what we’ve already seen, but not quite the same. We are creating a reference to a #map variable within our HTML, but we are also creating references to possible inputs. After the view initializes, the input values are used to initialize the map.

Let’s look at the HTML markup that pairs with our TypeScript. Open the project’s src/app/here-map/here-map.component.html file and include the following:

<div #map [style.width]="width" [style.height]="height"></div>

The above HTML also looks similar to what we’ve already seen. However, this time we are binding the public width and height variables from the TypeScript to the styling of the element. Eventually, these width and height values will be defined by the user.

Now let’s make use of our new Angular component. Going back to the project’s src/app/app.component.html file, wipe out what’s currently in there and include the following:

<here-map appId="APP-ID-HERE" appCode="APP-CODE-HERE" lat="37.7397" lng="-121.4252" width="100%" height="835px"></here-map>

We’re going to break down what is happening in the above custom HTML tag. The here-map name is derived from our TypeScript file. In the TypeScript file you’ll notice that our selector is actually here-map. All the attributes on this custom tag are actually the inputs that we defined in the TypeScript file.

By creating a component for our map, I personally think it becomes easier to manage in Angular.

Conclusion

You just saw how to use maps in your web application built with Angular and the HERE Maps API for JavaScript. Generally the setup for JavaScript UI components require a bit more configuration than vanilla JavaScript, but as you’ve seen, it isn’t too bad.

With custom tag attributes, you could link up other aspects of the API to include markers or something else, all of which we’ll explore in future Angular tutorials.