Krullmizter
Krullmizter

Reputation: 567

Leaflet.js TypeError: t is undefined with multiple maps

I'm trying to display three maps on one page with leaflet.js and mapquests API. I've created a jQuery for-loop to read a unique postal code, then convert it (via mapquest) to latitude and longitude, and lastly create three maps, and add the matching latitude and longitude to every map. This would then result in three different maps, displayed on one page.

I've somewhat achieved this with the code below. Every "card" has its own card number (from 1 to 3), postal code, and corresponding map and map ID.

Edit I also get this jQuery error:

jQuery.Deferred exception: t is undefined addTo@https://unpkg.com/[email protected]/dist/leaflet.js:5:64070
MYWEBSITEURL/map.js:38:6
e@https://code.jquery.com/jquery-3.5.1.min.js:2:30005
l/</t<@https://code.jquery.com/jquery-3.5.1.min.js:2:30307
 undefined

The issue I now have is that when my jQuery runs I get this console error: TypeError: t is undefined. I've narrowed it down to it having something to do with either the L.tileLayer() and/or L.circle() functions. I've added the latest jQuery and leaflet.js to the page.

Edit Changed the question after @ivansanchez answer, but still the same issues.

Edit Changed the leaflet.js to leaflet-sr.js and I now get the error: TypeError: map is undefined

map.js:

$(document).ready(function(){

var postalCodes = [];
var latLng      = [];
var lat         = [];
var lng         = [];
var maps        = [];

for(var n = 0; n < 3; n++) {

    console.log('Maps for-loop count: '+n);

    postalCodes.push($('.card'+[n]+' .card__info--postal > span').html());

    $.ajax({ // Get lat & long from postal code
        async: false,
        url: 'https://www.mapquestapi.com/geocoding/v1/address?key=MYAPIKEY&postalCode='+postalCodes[n]+'&country=finland',
        success: function(obj) {
            latLng[n] = obj.results[0].locations[0].latLng;
            lat[n]    = latLng[n].lat;
            lng[n]    = latLng[n].lng;
        },
        error: function(xhr) {
            console.log('Map error', xhr);
        }
    });

    console.log(latLng[n], lat[n], lng[n]);

    var map = L.map('mapid'+[n]).setView([lat[n], lng[n]], 13);

    L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
        maxZoom: 18,
        id: 'mapbox/streets-v11',
        tileSize: 512,
        zoomOffset: -1,
        accessToken: 'MYAPIKEY'
    }).addTo(maps[n]);

    L.circle([lat[n], lng[n]], { // Map out area of the postal code
        color: 'rgb(218, 65, 103)',
        fillColor: 'rgb(218, 65, 103)',
        fillOpacity: 0.5,
        radius: 500
    }).addTo(maps[n]);

    maps.push(map);
}
});

Upvotes: 0

Views: 970

Answers (2)

IvanSanchez
IvanSanchez

Reputation: 19069

You're doing...

 var maps = [ L.map('mapid'+[n]).setView([lat[n], lng[n]], 13) ]; // Creates three maps, that corresponds with three mapids in my HTML

...and that doesn't do what you think it does. You're creating an array of one element, and assigning it to maps, and you're doing that three times. Therefore, at the second pass of the loop, when the code refers to maps[1], that has an undefined value.

Instead, you probably want to do something like...

var maps = [];
for(var n = 0; n < 3; n++) {
   /* stuff */
   maps.push( L.map( /*stuff*/ ) );
   L.tileLayer( /* stuff */ ).addTo(maps[n]);
}

...or even...

var maps = [];
for(var n = 0; n < 3; n++) {
   /* stuff */
   var map = L.map( /*stuff*/ );
   L.tileLayer( /* stuff */ ).addTo(map);
   maps.push(map);
}

On the other hand, you have a good ol' race condition regarding the values of latLng[n], lat[n] and lng[n]. Since those values are only set when the network operation has finished (since AJAX is async, etc etc), they are (most probably) undefined when they are used. You might want to delay adding data to each map until you actually got said data, like e.g.

var maps = [];
for(var n = 0; n < 3; n++) {
   var map = L.map( /*stuff*/ );
   fetch(url)
     .then(function(response){return response.json})
     .then(function(json)){
       L.circle(json.results[0].locations[0]).addTo(map);
     });
   L.tileLayer( /* stuff */ ).addTo(map);
   maps.push(map);
}

Note that the sequence of events here is: a network request is initiated, the map is instantiated, the tilelayer is instantiated, the network request completes, the circle gets instantiated.

(And why yes, I prefer the fetch API over jQuery any day).

Remember that, in Leaflet, it's usually nice to change leaflet.js into leaflet-src.js to get better stack traces, and that using the browser's developer tools to set breakpoints prior to exceptions will allow you to see which values are undefined at that time.

Upvotes: 1

Falke Design
Falke Design

Reputation: 11348

Change your code to:

maps[n] = L.map('mapid'+[n]).setView([lat[n], lng[n]], 13); 

Upvotes: 0

Related Questions