What is the best way to ensure Leaflet-Search functionality remains active even when a layerGroup is toggled off using L.control.layers

I am encountering challenges while using the Leaflet.Control.Search plugin by Stefano Cudini in conjunction with Leaflet's built-in function L.control.layers.

When all layers are active, there are no issues with locating a specific area.

However, when one of the layers is deactivated, Leaflet-Search fails to pinpoint a location. An error message appears in the search box as follows:

Uncaught TypeError: Cannot read property 'layerPointToLatLng' of null
at e.getBounds (leaflet.js:5)
at e._searchInLayer (leaflet-search.js:555)
at leaflet-search.js:594
at eachLayer (leaflet.js:5)
at e._searchInLayer (leaflet-search.js:593)
at leaflet-search.js:605
at eachLayer (leaflet.js:5)
at e._recordsFromLayer (leaflet-search.js:604)
at e._fillRecordsCache (leaflet-search.js:744)
at leaflet-search.js:706

If you re-enable the hidden layer, the search functionality returns to its normal operation.

I have created a JS Bin illustrating the issue, although it may not display the exact error details due to only showing "script error". Go ahead and try searching for a site - available names include 1000, 1100, 1110, and 1111. It should work initially. Then disable one of the layer groups from the layer control and attempt to search again - an error will be triggered. Re-enabling the layer group will restore normal functionality.

I would greatly appreciate any suggestions on what might be going wrong or potential workarounds. Thank you in advance!

In short, here is the relevant code:

The sites are defined in two arrays:

var sites1 = [
{"loc":[51.582521, -0.118155],"Site":"1000"},
{"loc":[51.587454, -0.106052],"Site":"1100"}
];

These arrays are iterated through and added to a layer group:

var layerSites1 = L.layerGroup();

for(var i in sites1) {
var title = sites1[i].Site, 
loc = sites1[i].loc,        
marker = new L.circle(new L.latLng(loc),
       {radius: 100,title: title,color: 'red'})
       .bindPopup('Site: '+ title);

layerSites1.addLayer(marker);
}

The two layer groups are designated as overlays:

var overlays = {

    "Sites1": layerSites1,
    "Sites2": layerSites2
};

L.control.layers(baseLayers,overlays).addTo(mymap);

They are then combined into a collective layer group used for searching by Leaflet Search:

var layerAll = L.layerGroup([layerSites1,layerSites2]);

The Leaflet Search configuration is outlined below:

var controlSearch = new L.Control.Search({
    position:'topright',        
    layer: layerAll,
    initial: false,
    hideMarkerOnCollapse: true,
    zoom: 17

});

mymap.addControl(controlSearch);

Answer №1

The solution turned out to be surprisingly simple. All I had to do was insert a try-catch statement in the leaflet-search.js source code.

In the latest plugin version, a try block needs to be added for the _searchInLayer function on line 528. The catch block should be added on line 599 (originally line 598 before inserting "try" on line 528).

With this update, even if one of the layer groups within the main layer group, where searching takes place, is deactivated, no exceptions are thrown; instead, the tooltip is displayed, the searched location is shown, and highlighted.

Here is how the modified code looks now:

_searchInLayer: function(layer, retRecords, propName) {
try {
var self = this, loc;

if(layer instanceof L.Control.Search.Marker) return;

if(layer instanceof L.Marker || layer instanceof L.CircleMarker)
{
  if(self._getPath(layer.options,propName))
  {
    loc = layer.getLatLng();
    loc.layer = layer;
    retRecords[ self._getPath(layer.options,propName) ] = loc;
  }
  else if(self._getPath(layer.feature.properties,propName))
  {
    loc = layer.getLatLng();
    loc.layer = layer;
    retRecords[ self._getPath(layer.feature.properties,propName) ] = loc;
  }
  else {
    //throw new Error("propertyName '"+propName+"' not found in marker"); 
    console.warn("propertyName '"+propName+"' not found in marker"); 
  }
}
if(layer instanceof L.Path || layer instanceof L.Polyline || layer instanceof L.Polygon)
{
  if(self._getPath(layer.options,propName))
  {
    loc = layer.getBounds().getCenter();
    loc.layer = layer;
    retRecords[ self._getPath(layer.options,propName) ] = loc;
  }
  else if(self._getPath(layer.feature.properties,propName))
  {
    loc = layer.getBounds().getCenter();
    loc.layer = layer;
    retRecords[ self._getPath(layer.feature.properties,propName) ] = loc;
  }
  else {
    //throw new Error("propertyName '"+propName+"' not found in shape"); 
    console.warn("propertyName '"+propName+"' not found in shape"); 
  }
}
else if(layer.hasOwnProperty('feature'))//GeoJSON
{
  if(layer.feature.properties.hasOwnProperty(propName))
  {
    if(layer.getLatLng && typeof layer.getLatLng === 'function') {
      loc = layer.getLatLng();
      loc.layer = layer;            
      retRecords[ layer.feature.properties[propName] ] = loc;
    } else if(layer.getBounds && typeof layer.getBounds === 'function') {
      loc = layer.getBounds().getCenter();
      loc.layer = layer;            
      retRecords[ layer.feature.properties[propName] ] = loc;
    } else {
      console.warn("Unknown type of Layer");
    }
  }
  else {
    //throw new Error("propertyName '"+propName+"' not found in feature");
    console.warn("propertyName '"+propName+"' not found in feature"); 
  }
}
else if(layer instanceof L.LayerGroup)
{
  layer.eachLayer(function (layer) {
    self._searchInLayer(layer, retRecords, propName);
  });
}
  }
catch(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

Verifying the content of the JSON data

If I receive JSON data that looks like this: {"d":1} Is it possible to determine whether the value after "d": is a 1 or a 0? I attempted the following method, but it always goes to the else block, even though I know the JSON data contains a 1. success: ...

What is preventing my boolean from being altered?

Creating a basic calculator that can handle single-digit arithmetic. The current code is incomplete and redundant, so please avoid commenting on that. <!doctype html> <html> <head> <title>JavaScript Learning Zone</title> ...

Utilizing the power of Vue.js and D3.js in tandem to create dynamic force simulations

Currently, I am attempting to retrieve data from a Restful API call and utilize it to create a d3.js force simulation. However, I have encountered an issue where if I use the data from the API call directly, the simulation treats it as if there is no data ...

Modify the useRef value prior to the HTML rendering (React functional component)

Hello everyone, I am attempting to update the value of useRef before the HTML is rendered. I have tried using useEffect for this purpose, but it runs after the HTML is ready, making it unsuitable for my needs. What I want to achieve is resetting the value ...

When using ng-repeat with Angular ui-bootstrap and tabs, the new tab will not be selected if there are no existing tabs present

To showcase the problem I'm facing, please refer to this link: http://codepen.io/pietrofxq/pen/ZLLJdr?editors=1010 Click on "remove tabs" and then on "add tab" The challenge at hand involves using a loop with ng-repeat to display tabs. At times, the ...

Convert a list into a hierarchical structure of nested objects

Working with angular, I aim to display a nested tree structure of folders in an HTML format like below: <div id="tree"> <ul> <li ng-repeat='folder in folderList' ng-include="'/templates/tree-renderer.html'" ...

How can I redirect to another page when an item is clicked in AngularJS?

Here is an example of HTML code: <div class="item" data-url="link"></div> <div class="item" data-url="link"></div> <div class="item" data-url="link"></div> In jQuery, I can do the following: $('.item').click ...

Calculate the sum of values in a JSON array response

I recently received a JSON string as part of an API response, and it has the following structure: { "legend_size": 1, "data": { "series": [ "2013-05-01", "2013-05-02" ], "values": { "Sign Up": { "2013-05-05": 10, ...

I'm struggling with an issue of being undefined in my React.js project

This code snippet is from my app.js file import React, { useState, useEffect } from "react"; import { v4 as uuid } from "uuid"; import "./App.css"; import Header from "./Header"; import AddContact from "./AddCo ...

Revamping the Look: Refreshing Background of Div

I'm attempting to change the background image of the body element on a webpage when I hover over links with data-* attributes. It's working perfectly, but I can't seem to figure out how to create a smooth fade between the images when a link ...

Stop Code Execution || Lock Screen

Is there a way to address the "challenge" I'm facing? I'm an avid gamer who enjoys customizing my game using JavaScript/jQuery with Greasemonkey/Firefox. There are numerous scripts that alter the DOM and input values. In my custom script, I hav ...

Troubleshooting VueJs and vue-i18n issues

Currently, I am utilizing the Webpack CLI Template. As a next step, I proceed to install using the command npm install --save vue-i18n Within my main.js file, I undertake the necessary importation and configuration by setting the locale to "en" import ...

Custom properties of an object are being erased when converting to JSON format within the canvas

I am working on a canvas project that involves multiple image objects, each with custom attributes. My goal is to save this canvas as a json object in a database, but the conversion process seems to strip away the custom attributes. Currently, I am using t ...

Using an array as a data structure for a d3.js tree layout

I'm looking to use d3.js to create a diagram using the tree layout. Instead of the typical flare json structure with hierarchical children, I have an array representing different timesteps that I want to transform into a tree. My plan is to adjust the ...

Create a bespoke AngularJS directive for a customized Twitter Bootstrap modal

I am attempting to create a unique custom Twitter Bootstrap modal popup by utilizing AngularJS directives. However, I'm encountering an issue in determining how to control the popup from any controller. <!-- Uniquely modified Modal content --> ...

What is the best way to conceal a parent element with jquery?

Let's say we have the following HTML structure: <li class="fooli"> <a class="foo" href="javascript:foo(this);">anchor</a> </li> <li class="fooli"> <a class="foo" href="javascript:foo(this);">anchor</a> ...

Use jQuery to swap out two div classes within a table cell (TD) if they are

Although I'm making progress, I must confess that jQuery and CSS are not my strong suits. The objective: To create a dynamic div within a table data cell for a calendar feature. The content of the div varies based on the date range input. A filled d ...

ng-repeat isn't displaying the data

I have always been comfortable using the ng-repeat in Angular, but this time I seem to be facing a problem. I am trying to populate my DOM with data from a JSON file, but for some reason, the fields are not displaying as expected. Is there something wrong ...

What happens when Google Polymer platform is used without defining _polyfilled?

My attempt at creating a simple example using Google Polymer's platform.js is running into an error message that says: Uncaught TypeError: Cannot read property '_polyfilled' of undefined This is what I'm attempting to achieve: <cur ...

Retrieving Hyperlinks from JavaScript Object for Integration with D3-Created Table

Issue: I'm facing a problem where the HTML link extracted from an Associative Array is treated as a string instead of being applied as a clickable link in the browser. For a detailed visual example and code snippet, visit: http://example.com/code Da ...