Api call in helper making too may requests

I haven’t touched Meteor in a while and I’m attempting to call the Google Maps api and reverse lookup a city state based on lat/long, and everything works fine when I just console.log, but when I attempt to set a reactiveVar (thus showing location on the html page) I go over my request quota in GMaps api. I attempted to make my call in my template’s onCreated event, but I didn’t get anything returned. I’ve tried random combos of Promises, etc, but think I’m just doing something fundamentally wrong here… any tips?

Template.landing.helpers({
  currentLocation(){
    const instance = Template.instance();
    const latLng = Geolocation.latLng();
    instance.locationObj.set(latLng);
    if (GoogleMaps.loaded() && instance.locationObj.get()) {
      const geo = new google.maps.Geocoder();
      geo.geocode({
         'latLng': instance.locationObj.get()
       }, function(results, status) {
         if (status == google.maps.GeocoderStatus.OK) {
            const location = results[0].address_components;
            console.log("location in geocode", location);
            const city = location[2].short_name;
            const state = location[6].short_name;
            const locationString = `${city} , ${state}`;
            console.log('locationStringe',locationString);
            // instance.locationObj.set(locationString);
         }
         else {
           console.error("Geocode was not successful for the following reason: " + status);
        }
      })
    }
    return instance.locationObj.get().lat
  }
});

You are setting the ReactiveVar in the same helper that gets it.
When you change the value of a ReactiveVar, it invalidates all the reactive functions that depend on it, causing it to run again, and set again -> infinite loop

Your helper should just return the ReactiveVar’s value.
Then make the initial call to google maps in onCreated
And if you need to react to user input or changes, use events for that (ideally debounced / throttled) so you only make requests when necessary

2 Likes

Thank you @coagmano for getting me on the right track. Looks like I also needed a Tracker.autorun() to wrap in the onCreated event as well. For anyone else that encounters this:

Template.landing.onCreated(function() {
 this.locationObj = new ReactiveVar({});
 this.readableLocation = new ReactiveVar();

 const instance = Template.instance();
 Tracker.autorun(() => {
   const latLng = Geolocation.latLng();
   instance.locationObj.set(latLng);
   console.log('Geolocation.error:', Geolocation.error());
   if (GoogleMaps.loaded() && !Geolocation.error()) {
     const geo = new google.maps.Geocoder();
     const address = '27606';
     geo.geocode({
        'latLng': latLng
      }, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
           const location = results[0].address_components;
           console.log("location in geocode", location);
           const city = location[2].short_name;
           const state = location[6].short_name;
           const locationString = `${city} , ${state}`;
           console.log('locationString',locationString);
           instance.readableLocation.set(locationString);
        }
        else {
          console.error("Geocode was not successful for the following reason: " + status);
       }
     })
   }
 })
})
1 Like