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

Navigating Date Conversion within Component in Angular 2 Application

Searching for a way to update the display of certain dates in my Angular 2 application, I encountered a roadblock. Using the date pipe in conjunction with string interpolation wasn't viable due to the structure of my template code: <input class="a ...

Having difficulty with my async custom react hooks. Is there a way to wait for the result of one hook before using it in another hook?

Having some difficulty working with custom react hooks. I've created 2 custom hooks - one for fetching an ID and another for fetching a profile using the previously fetched ID. Since the second hook is dependent on the ID, I need to await the promise ...

Using Next.js with Firebase emulators

I've been struggling to configure Firebase's V9 emulators with Next.js, but I keep running into the same error message. See it here: https://i.stack.imgur.com/Uhq0A.png The current version of Firebase I'm using is 9.1.1. This is how my Fir ...

Is there a way for my extension to prevent a rickroll from starting before the video even begins?

I'm working on creating a Chrome extension that prevents rick rolls. Here's an overview of my manifest.json file: { "name": "AntiRick", "version": "1.0", "description": "Introduci ...

Excessive form inputs extend beyond the modal when utilizing Bootstrap 3

Having an issue loading a modal with Angular and populating it with a template. The main problem I'm facing is that the inputs are extending beyond the boundaries of the modal - attached below is a screenshot illustrating the problem: Below is the c ...

Troubleshooting issue with changing class based on input values

It appears that there is an issue with the functionality when switching values on page load. Initially, I was able to make it work for a single switch, but now that there are multiple switches on the page, toggling affects all of them. How can I modify it ...

Steps for adding a PHP dropdown menu to an HTML/Javascript webpage

Hey there, this is only my second post and I have to admit that I am a newbie in the world of web development. I'm spending countless hours scouring different websites for guidance, and I'm finally starting to grasp some concepts (at least for no ...

Switch out 2 Bootstrap columns for 2 concealed columns with just a click. Utilizing Rails 4 and Bootstrap

Using Twitter Bootstrap 3 for a column system showcasing four similar advertisements at the bottom of the page. Code Snippet: <div class="row similar"> <% @recomended_ads.each do |advertisement| %> <div class="col- ...

Using JSON data to populate an HTML page

I'm currently working on a project that involves creating a "Twitter" page. The idea is to utilize the JSON file available at to display some of its content. However, I'm facing an issue where my page only shows the table headers and nothing els ...

Which is better: express.Router() or app.get() for serving routes

I am currently working with Express 4 server for Node.js Express comes with a built-in router, which is utilized as follows: in app.js var router = express.Router(); app.use(router); app.use('/users', usersRoutes); in userRo ...

How to Use Google Tag Manager to Track Forms with Various Choices

Currently, I am facing a challenge in setting up conversion tracking using GTM for a form that offers users multiple options via a drop-down menu. When the user clicks on an option, they are presented with choices like A, B, C, and D. After selecting an ...

Utilizing Radio buttons to establish default values - a step-by-step guide

I am utilizing a Map to store the current state of my component. This component consists of three groups, each containing radio buttons. To initialize default values, I have created an array: const defaultOptions = [ { label: "Mark", value: & ...

Handling JSON Objects with Next.js and TypeScript

Currently, I am working on a personal project using Next.js and Typescript. Within the hello.ts file that is included with the app by default, I have added a JSON file. However, I am facing difficulties in mapping the JSON data and rendering its content. T ...

Creating custom elements for the header bar in Ionic can easily be accomplished by adding your own unique design elements to the header bar or

I'm a beginner with Ionic and I'm looking to customize the items on the header bar. It appears that the header bar is created by the framework within the ion-nav-bar element. <ion-nav-bar class="bar-positive"> <ion-nav-back-button> ...

Safari Displaying Error Message "Unhandled Promise Rejection: [object DOMError]" While Playing MP4 Video

I am facing an issue with playing a group of MP4 videos on hover in a container. You can view a demonstration by clicking the link below: While this functionality works smoothly in Chrome, it seems to be causing problems in Safari. Upon hovering, the vide ...

Is it considered proper to initialize an empty array within the data object of a Vue.js component?

For my component, I am in need of multiple empty arrays and predefined objects. The data object structure provided below seems to be effective for my purpose. However, I am uncertain if this is the optimal pattern and whether it might lead to unforeseen co ...

Include web browsing history

In my ASP.Net/VB project, I am facing an issue with floating DIVs. Whenever users try to close the floating DIV by clicking on the back button in their browser, it creates a confusing experience. My solution is to add a "#" entry to the browser history wh ...

In Javascript, create a variable that dynamically updates for every child element

While this might appear to be a simple question, it has been troubling me for some time now. Let me elaborate on what I am trying to accomplish. I have a collection of images in a gallery, and my goal is to center each image vertically within its contain ...

How can you resize a circle in Three.js without resizing its outline?

I'm currently using a THREE.Path to generate a Circular path and then utilizing a TubeGeometry to form a circle with transparent fill and an adjustable stroke thickness. My main query revolves around the process of scaling up the Circular path dynamic ...

Jquery Plugin fails to generate dynamic elements effectively

I developed a masking jQuery script that dynamically adds elements to an existing input element. var link = $('<a title="show" role="link" href="#" class="masker-value">show</a>'); wrapper: function() { container = $(container) ...