0

I am trying to add custom content in the popup template from a service returned results. The service function is working in the ngOninit() or in a custom function which is not a part of the popup template function. When ever using in the popup custom template function, the service is failed to collect the results.

Please find the code below (included only the major part), importing the custom service.

import { CustomService } from '../shared/service/custom.service';


 constructor(private customService: CustomService){}

 // Formation of the popup template
      var popupTrailheads = {
        title: "Unique id: {ID}",
        content: this.getcustomcontent,
      };

forming the feature layer the popup should come from this layer.

this.layer_fifteen = new FeatureLayer({
        url: `${this.esriURL}/15`,
        visible: true,
        outFields: ['*'],
        popupTemplate: popupTrailheads
      });

The below function getcustomcontent() collects the details from the service.

 public getcustomcontent(feature) {

// the service code
 this.customService.getIdDetails(popup_id).subscribe((posts) => {
//required to get the result from the service
}
}

When I use try-catch, it shows 'TypeError: Cannot read property 'customService' of null'. How can I use service in popup template?

Adam-KER
  • 67
  • 9

1 Answers1

0

I think you are having a context problem. The value of this inside getcustomcontent is null when it is executed to render the template.

There are some options to set the execution context of a function. In the example below I am using bind.

popupTemplate: {
  content: this.customPopupFunction.bind(this) // <- here
}

Basically, I am indicating that when customPopupFunction is call it should be bind to the component. That is why this inside the function works, and it renders madeBy property of the comoponent in the popup template content.

Mozilla Docs - bind

import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from "@angular/core";
import { loadModules } from "esri-loader";

@Component({
  selector: 'app-esri-map',
  templateUrl: './esri-map.component.html',
  styleUrls: ['./esri-map.component.scss']
})
export class EsriMapComponent implements OnInit, OnDestroy {

  @ViewChild("mapViewNode", { static: true }) private mapViewEl: ElementRef;
  view: any;

  // to keep loaded esri modules
  esriModules = {
    layers: {
      FeatureLayer: null
    }
  };

  madeBy = '@cabesuon';

  constructor() {}

  async initializeMap() {
    try {
      // Load the modules for the ArcGIS API for JavaScript
      const [
        Map,
        MapView,
        FeatureLayer
      ] = await loadModules([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer"
      ]);

      // save the modules on a property for later
      this.esriModules.layers.FeatureLayer = FeatureLayer;

      // Create the FeatureLayer

      // USA counties layer
      var countiesLayer = new FeatureLayer({
        portalItem: {
          id: "cd13d0ed1c8f4b0ea0914366b4ed5bd6"
        },
        outFields: ["*"],
        minScale: 0,
        maxScale: 0,
        popupTemplate: {
          content: this.customPopupFunction.bind(this)
        }
      });

      // Configure the Map
      const mapProperties = {
        basemap: "streets",
        layers: [countiesLayer]
      };

      const map = new Map(mapProperties);

      // Initialize the MapView
      const mapViewProperties = {
        container: this.mapViewEl.nativeElement,
        map,
        zoom: 5,
        center: [-107.3567, 37.7705]
      };

      this.view = new MapView(mapViewProperties);
      await this.view.when(); // wait for map to load
      return this.view;
    } catch (error) {
      console.error("EsriLoader: ", error);
    }
  }

  ngOnInit() {
    this.initializeMap().then(_ => {
      // The map has been initialized
      console.log("mapView ready: ", this.view.ready);
    });
  }

  ngOnDestroy() {
    if (this.view) {
      // destroy the map view
      this.view.container = null;
    }
  }

  customPopupFunction(feature) {
    return `<p>This is <strong>${feature.graphic.attributes.NAME}</strong> county, state of <strong>${feature.graphic.attributes.STATE_NAME}</strong></p>` +
    `<p>This is an example of a custom popup content made by <span style="color:blue;">${this.madeBy}</span></p>`;
  }

}

cabesuon
  • 4,860
  • 2
  • 15
  • 24
  • Thank you so much Cabesuon. The bind is working! and thank uou so much for your sample code. Can we enbale the pop up only in some predifined zoom levels? – Adam-KER Oct 12 '20 at 17:24
  • Glad it helps you!! .. You could listen to the `zoom` property of the `MapView`, and depending on the value toggle `popupEnable` property of the layer. – cabesuon Oct 12 '20 at 18:18
  • Hi Cabesuon, If you have time can you please check this one. https://stackoverflow.com/questions/64336716/prevent-popup-template-to-shows-multiple-feature-in-arcgis-4-16-angular-10 – Adam-KER Oct 13 '20 at 14:25