Display information from a Google Sheet onto a leaflet map based on specified categories

I am currently facing some challenges while creating a map with markers using data from Google Sheet and leaflet. Despite my efforts, I have encountered a few bugs that are proving to be difficult to resolve:

  1. Group Filtering - Although I can successfully filter by group, only one marker is displayed for each selected group even when there are multiple data points within the same group. You can view the output in the attached photo https://i.stack.imgur.com/uGM8e.png.
  2. Marker Replacements - My intention was for the map to display markers corresponding to the selected group exclusively. However, if I select a group (e.g., Male) and then try to switch to another group (Female), the marker representing the previous group remains visible. Check out the issue illustrated here: https://i.stack.imgur.com/wrQsG.png.

Here is a glimpse of the sample data retrieved from Google Sheet https://i.stack.imgur.com/BXnll.png.

Presented below is an excerpt of my code:

function doGet(e) {
  return HtmlService.createHtmlOutputFromFile('map');
}

function getAddress(group) {
  var ss= SpreadsheetApp.getActiveSpreadsheet();
  var groupSheet = ss.getSheetByName("Sheet1"); 
  var getLastRow = groupSheet.getLastRow();  
  var return_array = [];
  if (group === 'All'){
    return groupSheet.getRange(2, 1, getLastRow - 1, 5).getValues();  
  } else {
    for (var i = 2; i<= getLastRow; i++){
      if (groupSheet.getRange(i,3).getValue() === group){
        return_array.push(groupSheet.getRange(i,1,1,5).getValues());
      }
    }
    return return_array;
  }
}

HTML Structure

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Document</title>
    <link rel="stylesheet" href="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="741811151218110034455a435a45">[email protected]</a>/dist/leaflet.css"
        integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
        crossorigin="" />
    <script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="036f6662656f667743322d342d32">[email protected]</a>/dist/leaflet.js"
        integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
        crossorigin=""></script>
</head>
...Continued...
</style>

Your assistance in resolving these issues would be greatly appreciated!

Answer №1

Trying out maps for the first time and seeing success.

Make necessary changes to your files.

HTML_TestMap

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Document</title>
    <link rel="stylesheet" href="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f69a9397909a9382b6c7d8c1d8c7">[email protected]</a>/dist/leaflet.css"
        integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
        crossorigin="" />
    <script src="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a6cac3c7c0cac3d2e69788918897">[email protected]</a>/dist/leaflet.js"
        integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
        crossorigin=""></script>
    <style>
      body {
          margin: 0;
          padding: 0;
      }

      #viewmap {
          width: 100%;
          height: 100vh;
      }

      #text {
        font-family:Georgia,'Times New Roman', Times, serif;
      }
    </style>
  </head>
  <body>
    <div id="divfilter" class="col12" onchange="onSelect()">
      Select a group:  
        <div class="col4">
            <input type="radio" name="filGroup" value="All" checked>All
        </div>
        <div class="col4">
            <input type="radio" name="filGroup" value="Male" >Male
        </div>
        <div class="col4">
            <input type="radio" name="filGroup" value="Female" >Female
        </div>
    </div>
    <div id="viewmap"></div>
    
    <script>
      var map_init = null;
      var basemap = null;
      var map_markers = [];

      (function () {
        try {
          map_init = L.map('viewmap',{
            center: [4.042649, 103.624396],
            zoom:8
          });
          basemap = L.tileLayer ('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
            attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
          }).addTo (map_init);
        }
        catch(err) {
          alert(err);
        }
      })();

      function onSelect(){
        var map = map_init;
        var group = document.querySelector('input[name="filGroup"]:checked').value;
    
        google.script.run.withSuccessHandler(
          function(ar){
            try {
              map_markers.forEach( marker => marker.remove() );
              map_markers = [];
              ar.forEach(function(item, index){
                var group = document.querySelector('input[name="filGroup"]:checked').value;

                var marker = L.marker([item[0], item[1]]).addTo(map);
                marker.bindPopup('<div class="mapFlag" id="text"><p>Name: ' + item[3] + '<br>DOB: ' + item[4] + '</p></div>' );
                map_markers.push(marker);
              });
            }
            catch(err) {
              alert(err);
            }
          }
        ).getAddress(group);  
      }
    </script>
  </body>
</html>

Code.gs

function getAddress(group) {
  try {
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var groupSheet = ss.getSheetByName("Sheet1");
    let values = groupSheet.getDataRange().getValues();
    values.shift(); // remove headers
    if( group !== 'All' ) {
      values = values.filter( row => row[2] === group )
    }
    return values;
  }
  catch(err) {
    Logger.log(err);
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Choosing a single radio button value within a nested ng-repeat loop in AngularJS

Help needed with selecting only one radio button value in nested ng-repeat. Please review the source code and suggest any potential mistakes. <form ng-submit="save()"> <div ng-repeat="x in surveyLst"> <div class="row"> < ...

The iPad scroll did not meet the condition for reaching the bottom

Looking to modify the footer when the bottom of the page is reached via scrolling, I implemented the following code: if($(window).scrollTop() + $(window).height() == $(document).height()) This condition successfully detects whether the scroll has reached ...

Toggle checkbox feature in Bootstrap not functioning properly when placed within ng-view

When attempting to embed a bootstrap toggle checkbox within <ng-view></ng-view>, an issue arises where a regular HTML checkbox is displayed instead of the expected bootstrap toggle. Strangely, the same checkbox functions as a bootstrap toggle w ...

Monitoring Javascript inactivity timeouts

As I work to incorporate an inactivity timeout monitor on my page, the goal is to track whether individuals working from home are present at their desks or not. The Jquery plugin http://plugins.jquery.com/project/timeout that I am utilizing initiates a ti ...

What could be causing my list of files to not properly append to FormData?

I have been working on this issue for the past three days. Despite trying various solutions from different sources, including seeking help from other websites, I am still unable to resolve it. My current challenge involves sending a post request with a Fo ...

Angular8: Adjusting Activity Status After Leaving Page

When performing activities like upload, download, delete, and edit, I display statuses such as 'upload started' or 'upload completed'. This works perfectly when staying on the same page. However, there are instances where a user may nav ...

Send a redirect after a certain delay to a URL stored in a variable outside of the current scope

Upon making an ajax request, the JSON response contains a link that needs to redirect the user to another page after 3 seconds. The current approach used is: response = JSON.parse(res); var link = response.link; setTimeout("window.location.href=link",300 ...

Not all of the data is being retrieved

A form on the page contains two dropdown lists for selecting blood type and city, along with a button. When the button is clicked, information about donors matching the selected blood type and city will be displayed below the form. The postgres database co ...

What is the process of adding files to my Svelte / Sapper server build using __sapper__?

Currently, I am working on integrating a server middleware called Parse into my sapper server configuration located in sapper-project/src/server.js. express().use('/api', const api = new ParseServer({ databaseURI: 'mongodb://localhost:27 ...

Converting a JavaScript dictionary into an array of documents: The ultimate guide

I have an object that looks like this: const obj = { "restaurant": 20, "hotel": 40, "travel": 60 } Is there a way to transform it into the format below? const newArray = [ { "category_name": "restaurant", "amount": 20 }, { "category_na ...

React Router Link Component Causing Page Malfunction

Recently, I delved into a personal project where I explored React and various packages. As I encountered an issue with the Link component in React Router, I tried to find solutions online without any luck. Let me clarify that I followed all installation st ...

Customizing Google Maps API v3: Utilizing Custom Images as symbolPath Instead of Default Symbols

Recently, I discovered the fascinating feature called Symbol Animation in Google API's documentation. All aspects of my code are functioning optimally; however, I am curious to know if it is possible to substitute an image for a symbol in the followi ...

The Implementation of Comet Programming

I'm interested in creating a web application similar to Google Docs where multiple users can edit and view changes in real-time. Would Comet Programming be the best approach for this? As a newcomer to Web Development, I'm currently learning Java ...

"Implement a function to append a new item to all JSON objects in an array if they share a common value with a different JSON object in the array using

Hi there, I'm new to Vue Js and I'm currently working on adding or merging new items in all JSON objects within an array that share the same value with another JSON object. I know how to push a new JSON object into an existing one, but I would re ...

Running repetitive tasks in PHP using setInterval function

I've been working on adding a "friend request" feature to my website and I really want the requests to show up instantly without having to reload the page. After doing some research, it seems like using setInterval with Ajax is the way to go. I found ...

Updating Object Properties in Vue.js 2.0 using Methods

I am facing an issue where I have an object with blank properties in my component's data. I want to update these properties using a method that is triggered by a click event on one of the listed elements. However, when I check the click event in the c ...

Ways to require semicolons in a Typescript interface

When declaring a TypeScript interface, both , (comma) and ; (semicolon) are considered valid syntax. For example, the following declarations are all valid: export interface IUser { name: string; email: string; id: number; } export interface IUser { ...

Alternative for Jquery: a new Hash Table solution using Prototype JS

Greetings everyone! I have experience as a prototype JS developer but now I am transitioning to jQuery for work/client reasons. One feature I really liked in Prototype was the Hash class, such as var h = new Hash();. However, I understand that jQuery doe ...

Easily manipulate textboxes by dynamically adding or deleting them and then sending the data to a

Can you provide a simple example of how to dynamically add and remove textboxes and then display the results? I envision it like this: [Empty Textbox][Add button] When 'Value1' is entered into the textbox and 'add' is clicked, it s ...

Is there a way to prevent advertisements from appearing in npm?

As I execute various npm commands, my console gets bombarded with ads promoting different projects and individuals. While I enjoy contributing to open source projects, I believe the console output of a tool should not be used for advertising. Thank you fo ...