Joh
Joh

Reputation: 171

How to update global data in clickMapObject listener from AmChart

I'm learning about AmChart js lib and I have some doubts.

I have one map that show all devices registered in my database (look the print below)

enter image description here

So, I would like to implement one functionality for when the user clicks on the bubble from one country in the map, the table list is filtered by country, so, in the device, table should show only devices from the country of the bubble that user clicked.

for to do this filter when a user clicks in the bubble, I'm using the addListener from Amchart (clickjMapObject) as the example below.

 this.map.addListener('clickMapObject', function (event) {
    console.log(event);
    console.log(this.deviceList).
 });

the console.log(event) it's working, but When I try to print "deviceList" not working. I get the following error:

ERROR TypeError: Cannot read property 'devicesList' of undefined

I don't know if it's possible to access global array in the listener, So, I don't know what's the problem. Could you please help me?

follow my complete code below. (in this code you can see how to I populate the "deviceList")

export class DevicesLocationComponent implements OnInit {

  public devicesList: Device[];
  public images = [];
  public country_location = [];
  public map: any;

  @ViewChild(DatatableComponent) table: DatatableComponent;

  constructor(private http: HttpClient, private deviceService: DeviceService) 
  {
    this.getCountryLocationJSON().subscribe(data => {
      this.country_location = data;
    });
  }


  /**
   * Build initial the chart and load devices location
   *
   * @memberof DevicesLocationComponent
   */
   public ngOnInit() {
     this.loadDeviceDataTable();
   }


   /**
    * This function is responsible to load datatable with devices data
    */
    private loadDeviceDataTable() {

      // load last used devices data
      this.deviceService.getAllDevices()
         .subscribe(((listDevices: Device[]) => {
              this.devicesList = listDevices;

             this.buildMapChart();   
      }));
    }

    /**
     * This function is responsible to build the map chart after load devices data on datatable.
     */
     private buildMapChart() {

        // get min and max values for define bubble size frm map chart
        const minBulletSize = 10;
        const maxBulletSize = 40;
        let min = Infinity;
        let max = -Infinity;
        for (const key in this.tardisDevicesGrouped) {
           if (this.tardisDevicesGrouped.hasOwnProperty(key)) {
               const value = this.tardisDevicesGrouped[key].length;
               if ( value < min ) {
                  min = value;
               }
               if ( value > max ) {
                 max = value;
               }
           }
        }

       // it's better to use circle square to show difference between values, not a radius
      const maxSquare = maxBulletSize * maxBulletSize * 2 * Math.PI;
      const minSquare = minBulletSize * minBulletSize * 2 * Math.PI;

      // create circle for each country
      for (const key in this.tardisDevicesGrouped) {
        if (this.tardisDevicesGrouped.hasOwnProperty(key)) {
          const value = this.tardisDevicesGrouped[key].length;
          const country_location = this.getLatLongCountry(key);

          // calculate size of a bubble
         let square = ( value - min ) / ( max - min ) * ( maxSquare - minSquare ) + minSquare;
         if ( square < minSquare ) {
           square = minSquare;
         }
         const size = Math.sqrt( square / ( Math.PI * 2 ) );

         // set each bubble size, value and colors for each country
         this.images.push( {
         'type': 'circle',
         'theme': 'light',
         'width': size,
         'height': size,
         'longitude': country_location.longitude,
         'latitude': country_location.latitude,
         'color': country_location.color,
         'title': country_location.country_name,
         'selectable': true,
         'value': value
       });
     }
   }

   this.map = AmCharts.makeChart('allocation-map', {
     'type': 'map',
     'hideCredits': true,
     'theme': 'light',
     'colorSteps': 10,
     'dataProvider': {
       'map': 'worldLow',
       'images': this.images,
       'zoomLevel': 1.0,
       'zoomLongitude': 10,
       'zoomLatitude': 52
     },
     'areasSettings': {
        'autoZoom': true,
        'selectable': true
     }
   });

   console.log(this.devicesList);  // It's working 

   this.map.addListener('clickMapObject', function (event) {
     console.log(event);
     console.log(this.devicesList);   // It's not working
    });
  }
}

Upvotes: 0

Views: 395

Answers (1)

Osakr
Osakr

Reputation: 1066

Above the event listener you should declare a variable storing the current scope

var self = this

Then inside the function triggered at the event you should change the this reference to self

console.log(self.devicesList);

At the end your code should look like this:

 console.log(this.devicesList);  // It's working 
 var self = this;
   this.map.addListener('clickMapObject', function (event) {
     console.log(event);
     console.log(self.devicesList);   // Now it will work
    });
  }

This happens because the scope is changing depending on where you are, so "this" doesn't mean the same inside an event listener than inside a component, the reference changes

Upvotes: 2

Related Questions