3
votes

I'm currently trying to create a leaflet map inside an angular material2 tab-group as below

import {Component, NgModule} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { MaterialModule } from '@angular/material';

import { Component, OnInit, OnDestroy } from '@angular/core';
import 'leaflet';

@Component({
  selector: 'minimap',
  template: `<div #minimap [id]="id" class=leaflet-map></div>`
})
export class MiniMap implements OnInit, OnDestroy {
  map: L.Map = null;
  id: string;

  constructor() { 
    this.id = "map" + Date.now();
  }

  ngOnInit() {
    this.map = L.map(this.id).setView([54.5, -115.0], 13);
    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution:
      '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(this.map);
  }

  ngOnDestroy() { }
}

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <md-tab-group>
      <md-tab label="tab 1">
      tab 1 content
      </md-tab>
      <md-tab label="tab 2">
      tab 2 content
      </md-tab>
      <md-tab label="map tab">
      <minimap></minimap>
      </md-tab>
      </md-tab-group>
    </div>
  `,
})
export class App {
  name:string;
  constructor() {
    this.name = 'Angular2'
  }
}

https://plnkr.co/edit/dLwhv3XoMWMYFkqztkuR?p=preview

Unfortunately when it tries to create the map in the component it throws an error saying that the map container doesn't exist yet. my interpretation is that the code is currently running before the DOM object is created.

What is the correct way of creating the map such that the code is called when the DOM object exists??

2
What happens if you try to do this in ngAfterViewInit()? - developer033
Sorry, forgot to mention, I'm seeing the same behaviour putting the map initialisation in the AfterContentInit and in the AfterViewInit - Bjorn Harpe

2 Answers

5
votes

Looks like referencing directly the map container Element (through @ViewChild) is working without issue.

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

@Component({
    selector: 'minimap',
    template: `<div #mapDiv></div>`
})
export class MiniMap implements OnInit {
    @ViewChild('mapDiv') mapContainer;

    ngOnInit() {
        this.map = L.map(this.mapContainer.nativeElement);
    }
}

Updated Plunk: https://plnkr.co/edit/HGWb3J1f5HL8shFW9EUN?p=preview

However, it seems that you need to re-initialize the map size once the tab is revealed (at least the first time). See Data-toggle tab does not download Leaflet map

1
votes

Try reading the documentation for the lifecycle hook:

https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html