1

I am adding geojson sources from multiple datasets via an internal URI. My addSources() function loops through ds_list, an array of IDs needed to make each call. If I fetch each dataset in a map.addSource() call, this works (example #1), but then I don't have access to the feature IDs from all datasets, for styling, interaction, etc.

So I want to get each geojson object as a variable, but in example #2, the first dataset is fetched and source/layers rendered, but the following one returns the error There is already a source with this ID. the thing is, at the time the second addSource() call is made, the ID (ds.label) has changed, as proven with console.log()

Example #1

# works, but feature IDs are not available
function addSources(ds_list){
  sources=[]
  for(d in ds_list){
    ds = ds_list[d]
    mappy.addSource(ds.label, {
      'type': 'geojson',
      'data': '/datasets/'+ds.id+'/geojson'
    });
    sources.push(ds.label)
    renderSourceLayers(ds.label, d)
  }
}

Example #2

# error after 1 dataset: 'There is already a source with this ID'
function addSources(ds_list){
  sources=[]
  for(d in ds_list){
    ds = ds_list[d]
    console.log('now doing...', ds.label)
    $.getJSON('/datasets/'+ds.id+'/geojson')
      .done(function(dsdata) {
        mappy.addSource(ds.label, {
          'type': 'geojson',
          'data': dsdata
        });
        console.log('just added dsdata', ds.label, dsdata)
        sources.push(ds.label)
        renderSourceLayers(ds.label, d)
    })
  }
}

This rendering function works fine for Example #1 and never gets called for second dataset in example #2

renderSourceLayers()

function renderSourceLayers(dslabel, i){
  mappy.addLayer({
    'id': 'gl_'+dslabel+'_poly',
    'type': 'fill',
    'source': dslabel,
    'visibility': 'visible',
    'paint': {
      'fill-color': 'rgba(245,245,245, 0.5)',
      'fill-opacity': 0.2,
      'fill-outline-color': 'black'
    },
    'filter': ['==', '$type', 'Polygon']
  }, 'z-index-1');
  
  mappy.addLayer({
    'id': 'gl_'+dslabel+'_point',
    'type': 'circle',
    'source': dslabel,
    'visibility': 'visible',
    'paint': {
      'circle-color': colors_point[i],
      'circle-radius': {
        stops: [[1, 2], [3, 3], [16, 20]]
      }        
    },
    'filter': ['==', '$type', 'Point']
  }, 'z-index-2');  
  
}

The dataset list, for reference. Used for this and to generate a select dropdown, and bounds for flyTo():

ds_list = [
  {
    "id": 1,
    "label": "dataset01",
    "title": "wordy title 01",
    "bbox": {"type": "Polygon","coordinates": [[],[],[],[],[]]}
  },{
    "id": 2,
    "label": "dataset02",
    "title": "wordy title 02",
    "bbox": {"type": "Polygon","coordinates": [[],[],[],[],[]]}
  }
]

kgeo
  • 412
  • 5
  • 19
  • 1
    `console.log` is lazy (well, kinda -- see https://stackoverflow.com/a/23392650/88411), so I wouldn't trust your `console.log(..., ds.label, ...)` line 100%. `$.getJSON` is async, so that's where I would be looking. Do you have a buildable public repo for this project? – simon Jul 30 '21 at 20:04
  • Not buildable yet. The relevant code is [here](https://github.com/WorldHistoricalGazetteer/whgazetteer/blob/063205c003e74865cb6a15d3e49a4b84d39ba336/collection/templates/collection/collection_places.html#L295) and thereabouts. Sure would help if addSource() reported what the id it considers duplicate id. I thought the '.done()' takes care of timing. Stumped. – kgeo Jul 30 '21 at 23:53

1 Answers1

0

The problem was the async nature of $.getJSON, and the answer, I'm embarrassed to say, was simple: use map.forEach(), in this case...

function addSources(ds_list){
  ds_list.forEach(function(ds,i){
    $.getJSON('/datasets/'+ds.id+'/geojson')
      .done(function(dsdata) {
        mappy.addSource(ds.label, {
          'type': 'geojson',
          'data': dsdata
        });
        renderSourceLayers(ds.label, i)
    })
  })
} 

Hadn't used javascript Map this way before. Live and learn...publicly

kgeo
  • 412
  • 5
  • 19