I'd like to read a table of JSON formatted cells into a Leaflet map using the Tabletop extension of leaflet.

However, my script only reads the first object. Any advice on how to create an array of features that can be visualized? I feel that I need a for loop, but I can't figure out where that should go given my current architecture.

I have a feeling the adjustment needs to be at this point:

  for (var row in data) { 
    var geojsonStates = JSON.parse(data[row].geometry);

Note that I'm building off the good work from Chris Arderne.

function init() {

var polyURL = "https://docs.google.com/spreadsheets/d/1-m5yUoIJph-Kyi7-lnUOL-hAMUxRi2SAepaswd3043Q/edit?usp=sharing";

  Tabletop.init( { key: polyURL,
    callback: addPolygons,
    simpleSheet: true } );
window.addEventListener("DOMContentLoaded", init);

var map = L.map("map").setView([40, -100], 4);

var basemap = L.tileLayer("https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}{r}.png", {
  attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> &copy; <a href="http://cartodb.com/attributions">CartoDB</a>',
  subdomains: "abcd",
  maxZoom: 19

var sidebar = L.control.sidebar({
  container: 'sidebar',
  closeButton: false,
  position: 'right'

panelID = 'my-info-panel'
var panelContent = {
  id: panelID,                     
  tab: '<i class="fa fa-bars active"></i>', 
  pane: '<p id="sidebar-content"></p>',       
  title: '<h2 id="sidebar-title"> No state selected</h2>',  
  position: 'top'               

map.on('click', function (feature, layer) {


var polygonLayer;
var pointGroupLayer;

function addPolygons(data) {
  if (polygonLayer != null) {

  var geojsonStates = {
    "type": "FeatureCollection",
    "features": []

  for (var row in data) {

    var geojsonStates = JSON.parse(data[row].geometry);


  var polygonStyle = {"color": "#2ca25f", "fillColor": "#99d8c9", "weight": 1.5};
  var polygonHoverStyle = {"color": "green", "fillColor": "#2ca25f", "weight": 3};

  polygonLayer = L.geoJSON(geojsonStates, {
    onEachFeature: function (feature, layer) {
        mouseout: function(e) {
        mouseover: function(e) {
        click: function(e) {


    style: polygonStyle

Your problem is that you iterate through rows of data without processing them, and so at the end when loop is finished you process only last row.

Taken into account that each of your rows contains one feature, you could in your loop first combine them into feature collection. This way you would process whole collection at once in your L.geoJSON call.

Your loop (simplified for proof of concept) could look something like this (tested):

var featureCollection = {"type":"FeatureCollection", "features":[]};

function init() {
  Tabletop.init( {key: 'https://docs.google.com/spreadsheets/d/1-m5yUoIJph-Kyi7-lnUOL-hAMUxRi2SAepaswd3043Q/edit?usp=sharing',
                  callback: showInfo,
                  simpleSheet: true } )

function showInfo(data, tabletop) {
  for (var row in data) {
  featureLayer = L.geoJSON(featureCollection).addTo(map);

window.addEventListener('DOMContentLoaded', init);
  • Oh man, thanks so much. I had the same thought that we'll need to process the rows as the script iterates. I tried this block of (and a few iterations), but still needs a little work. Since the json is already formatted, i.e. {"type":"Feature","properties":{"Date":"Sat Jul 20 2019","ID":1563658378402},"geometry":{"type":"LineString","coordinates":[[-80.004404,40.472562],[-90.9018, 31.9686]]}}, I tried the following without success. – bikingman Aug 31 '19 at 22:09
  • var featureCollection = []; var delim = ','; for (var row in data) { featureCollection = data[row].geometry + delim; } var geojsonStates = JSON.parse(featureCollection); As well as a few iterations. – bikingman Aug 31 '19 at 22:14
  • I modified my code a bit and tested it on your data. – TomazicM Sep 1 '19 at 9:53

ok, thank you @TomazicM for the lesson in json objects creation/manipulation!

The following scripts returns a json object of all google spreadsheet objects/rows that can be parsed into a geojson for leaflet operations.

  var featureCollection = '{"type":"FeatureCollection", "features":[';
  var delim = '';

  for (var row in data) {
    featureCollection = delim + featureCollection + data[row].geometry + ',';
    delim = '';

//  featureCollection = featureCollection + ']};';
featureCollection = featureCollection.substring(0, featureCollection.length - 1);
featureCollection = featureCollection + ']}'
  var geojsonStates = JSON.parse(featureCollection);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.