Custom Controls

As you might expect, this same method can be used to add custom controls. The list of issues is similar, with the main difference being that 'import the code' is replaced by 'create the ui'. This topic also covers CSS. A template component.ts is shown at the bottom of the page and can be copied.

The proforma template does NOT accept an options object! We are in the Angular paradigm and should be idiomatic - therefore the config options should be passed as individual parameters in the directive and not as an options object. The only parameter in the L.Control default options object is position which is dealt with in the tempate. Since we have no other legacy code, we should do everything new in Angular.

Create Typings

No typings are required for the basic control, since the @types/leaflet definition cover the basic L.Control class.

Addition typings are only required if you want to add methods to the control, and as discussed above any additional functionality should really be done in the component typescript.

Create the UI

The UI for the control is defined in the HTML for the component (in the standard cae that is ./xxx.component.html ).

There should be an element for the control (usually a DIV) that defines the UI. This is passed to the map when the control is added to the map. This element must have the id that is used in the component code - in the template this is 'custom' but that should be changed to the name of your control.

In most cases, the element needs to have a width or min-width defined. Without this, the control will not be displayed.

Note that since for the custom control the HTML is created in the Angular component, it is part of the CSS encapsulation mechanisms. Therefore, the CSS for the UI should be included in the the CSS definition for the component (in the standard case this is ./xxx.component.css .

Create a Directive

This is set in the component. The template would, for instance, create the directive :

<app-custom-control [position]='bottomright' [map]='map'></app-custom-control>

Add the Control to the Map

The template implements the same mechanism for adding the control to the map as proposed for existing controls above.

There should not be a need to do anything in addition to the basic template.

Interact with the Control

The scope for interaction with the control is, of course, as large as HTML and Angular allow!

However, there are few points to remember.

You can create map event handlers either in the leaflet .onAdd code or in the typescript. Since the lifecycle of the control is the same as a the lifecycle of the component, I prefer to do it all in the typescript to keep things clean.

If you create a listener, remember to tear it down either in .onRemove or ngOnDestroy respectively.

As described in the ngx-leaflet documentation, the leaflet map is running outside of Angular change detection to avoid a huge overhead of events swamping Angular.

This means that many events used to update the control, like for instance clicks on the map, may not change as expected.

In this case, you will have to manually trigger change detection after the data is updated. There is a worked example of this at the bottom of this page.

Template Code

The basic framework for a new custom control component is shown below.

import { Component, OnInit, OnDestroy, Input } from '@angular/core';
import {Map, Control, DomUtil, ControlPosition} from 'leaflet';

@Component({
  selector: 'app-custom-control',
  templateUrl: './custom-control.component.html',
  styleUrls: ['./custom-control.component.css']
})
export class CustomControlComponent implements OnInit, OnDestroy {
  private _map: Map;
  public custom: Control;
  @Input() position: ControlPosition;

  constructor() { 
  }

  ngOnInit() {
  }

  ngOnDestroy() {
    this._map.removeControl(this.custom)
  }

  @Input() set map(map: Map){
    if (map){
      this._map = map;
      let Custom = Control.extend({
        onAdd(map: Map) {
          return DomUtil.get('custom');
        },
        onRemove(map: Map) {}
      });
      this.custom=new Custom({
          position: this.position
        }).addTo(map);
    }
  }
  get map(): Map {
    return this._map
  }

Remember to change the names that are based on "custom" and "Custom" to the name of your custom control.

Example

To see the description of a worked example, see :

The demo code is shown in this stackblitz. Click anywhere on the map to see the control update.

Last updated