0

I am experiencing a strange issue. I am receiving an error message that reads "ERROR TypeError: Cannot read properties of null (reading 'map_') on line 29". Even though I am able to loop the layers on the map to get the list of features on hover (line 23). Please see my code below and let me know if you have any advice on what I can do to fix this.

The way this is set up is, that my component is using a service that holds the information about the map and overlay. All I want to do is set the position of overlay on hover.

Component

import { Component, OnInit } from '@angular/core';
    import { Map } from 'ol';
    import { GeneralMapService } from 'src/app/services/general-map.service';
    
    @Component({
      selector: 'app-application-map',
      templateUrl: './application-map.component.html',
      styleUrls: ['./application-map.component.css']
    })
    
    export class WhereisMapComponent implements OnInit {

  map_: Map;
  overlay: any;

  constructor(private generalMap: GeneralMapService) {
    this.map_ = this.generalMap.map
    
    this.map_.on("pointermove", (e) => {
      
      const positionOfMouse = e.coordinate
      
      this.map_.forEachFeatureAtPixel(e.pixel, function (feature) {
        
        if (feature) {
          const { as_tr_name, ass_track, id, descriptio, media } = feature.getProperties();

          // I receive an error message here.
          console.log(this.map_.getView())
          this.map_.getView().mapOverlay.setPosition(positionOfMouse);
        }

      })

    })

    this.overlay = document.getElementById('informationOverlay')
    this.generalMap.mapOverlay.set("id", "informationOverlay")
    this.generalMap.mapOverlay.setElement(this.overlay)

  }

  ngOnInit(): void {
  }

  ngAfterViewInit() {
    this.map_.setTarget("map")  

  }

}

General Service

import { Injectable } from '@angular/core';
import { Map, Overlay, Tile, View } from 'ol';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';
import { Zoom, ZoomSlider, FullScreen } from 'ol/control';
import XYZ from 'ol/source/XYZ';
import BingMaps from 'ol/source/BingMaps';
import LayerGroup from 'ol/layer/Group';

import { mapDefaultCenter, mapeDefaultZoom } from '../shared/maptilerkey';
import { CreateLayerService } from './create-layer.service';
import { Fill, Stroke, Style } from 'ol/style';
import CircleStyle from 'ol/style/Circle';
import { OverlayService } from './overlay.service';

@Injectable({
  providedIn: 'root'
})
export class GeneralMapService {

  map: Map;
  zoomSlider: ZoomSlider = new ZoomSlider({
    className: "zoom-slider-dashboard"
  })
  mapLayers: LayerGroup = new LayerGroup({
    layers: []
  })
  mapOverlay: Overlay;

  constructor(private createLayers: CreateLayerService, overlayService: OverlayService) {

    const topographicLayer = new TileLayer({
      source: new XYZ({
        url: "https://api.maptiler.com/maps/topographique/{z}/{x}/{y}@2x.png?key=WYPadsIvfisd0PUHFJ6K"
      }),
      visible: false
    })
    topographicLayer.set('name', 'topographic');

    const openStreetMap = new TileLayer({
      source: new OSM(),
      visible: true
    })
    openStreetMap.set('name', 'openstreetmap');

    const bingMaps = new TileLayer({
      preload: Infinity,

      source: new BingMaps({
        key: 'AngczjEvgHNjwD8lTQe3DJ6CoFxavJfGTFCxxaGbS3bIgUW5_qn4k_m510RR53fe',
        imagerySet: "Aerial",
        hidpi: true,
        maxZoom: 19
      }),
      visible: false
    })
    bingMaps.set('name', 'bingmap');

    this.map = new Map({
      view: new View({
        center: mapDefaultCenter,
        zoom: mapeDefaultZoom,
        minZoom: 5,
        projection: "EPSG:3857",
        extent: [15766342.542104144, -5590291.031415702, 16739198.402589425, -4713511.626202316]
      }),
      controls: []
    })

    const mapLayerGroup = new LayerGroup({
      layers: [topographicLayer, openStreetMap, bingMaps]
    })

    this.map.setLayerGroup(mapLayerGroup)
    this.map.addControl(this.zoomSlider)

    // vector layer
    const walkPointStyle = new Style({
      image: new CircleStyle({
        radius: 6,
        fill: new Fill({
          color: '#44c4a1',
        }),
        stroke: new Stroke({
          color: '#fff',
          width: 2,
        }),
      }),
    })

    const walkPoints = this.createLayers.createVectorLayer("/assets/data/walking-data.geojson", walkPointStyle)
    const builtMapLayers = [
      walkPoints
    ]

    this.map.getLayers().extend(builtMapLayers)

    // Overlay registration
    this.mapOverlay = overlayService.overlay
    this.map.addOverlay(this.mapOverlay)
    console.log("this.map", this.map.getOverlays())

  }

  ngAfterContentInit() {

  }

  returnMap() {
    return this.map;
  }

  setMap(updatedMap: Map) {
    this.map = updatedMap;
  }
}

Any sort of help would be appreciated!

Sarbraj Dulai
  • 180
  • 10
  • "_Map is coming up as undefined_" - No, that is not what the error says. It says "Cannot read properties of null (reading 'map_')". You are reading `map_` from `this`, so `this` is `null` there. – Ivar Aug 22 '22 at 14:25

1 Answers1

0

It looks like you need to store context somewhere and then try to use that context forEachFeatureAtPixel method.

Let me show an example:

let that = this;

this.map_.forEachFeatureAtPixel(e.pixel, function (feature) {
        
    if (feature) {
      // ... other code is omitted for the brevity
     
      console.log(that.map_.getView())
      that.map_.getView().mapOverlay.setPosition(positionOfMouse);
    }
StepUp
  • 36,391
  • 15
  • 88
  • 148
  • 1
    @Ivar yeah, you are right that question was asked many times before, but sometimes people do not know how correctly apply theory in practise. So, community is here to help with that – StepUp Aug 22 '22 at 15:04
  • No, that's not what the community is for. Stack Overflow's one and only goal is to be a repository of high quality questions and answers meant to help future visitors that are facing the same problem. For those, this answer will be just as useful as the previous 1000 answers. We close questions [as duplicates](https://stackoverflow.com/help/duplicates) so that all the relevant and up-to-date information stays in one place. Very unlikely that this answer will be updated once new features come out. – Ivar Aug 22 '22 at 15:16
  • (In fact, new features have already come out. An arrow function is likely a cleaner solution here.) – Ivar Aug 22 '22 at 15:16