Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

geojson bindPopup(text) not filtering empty values #248

Open
goodyis opened this issue Mar 3, 2024 · 9 comments
Open

geojson bindPopup(text) not filtering empty values #248

goodyis opened this issue Mar 3, 2024 · 9 comments

Comments

@goodyis
Copy link

goodyis commented Mar 3, 2024

Using the Wordpress plugin, and the geojson mapping is working. So long as all the fields I call are either populated and/or present. Meaning I'll locations that might have all 8 data-properties, but some locations will only have 5 data-points. The shortcode template is calling all data points. But I can't have locations showing the empty 'key/value' pair for data that is not assigned to the property.

I'm hoping I'm over thinking this; maybe there is a way to tell the shortcode to check for empty values and to not display that section, or there is a better way then editing the 'GeoJSON Shortcode Class' file. Because I've been able to check that value/key pairs and remove any that are empty, but then 'feeding' them back into the text var isn't allowing the shortcode to function properly.

So with no filtering/edits, the shortcode works and pulls the geojson and displays as I would like, expect it displays values that are empty. With the edits, the geojson value is still pushed through and without empty values, but then ignores the shortcode 'instructions.'

Here is wordpress shortcode entry:

[leaflet-map fitbounds scrollwheel  zoomcontrol !detect-retina show_scale draggable height="500"]
[leaflet-geojson src="xxxx" fitbounds="1" iconUrl="xxxx" iconSize="80,50" iconAnchor="40,60"]
<b>{location-name}</b></br><span class="map-link">{loc-address}</span>
</br>Manager: {loc-manager}
<a href="tel:{loc-number}"/>{loc-number}</a> Direct
<a href="tel:{manager-cell}"/>{manager-cell}</a> Cell</br>
</hr>
Assistant Manager: {loc-assistant}
<a href="tel:{assist-cell}"/>{assist-cell}</a> Cell</br>
</hr>
More Info: {popup-text}
[/leaflet-geojson]

Here is the json sample data:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "location-name": "Name",
        "loc-address": "1122 South, State US 12345",
        "loc-number": "888-888-8888",
        "loc-manager": "Manager Name",
        "manager-cell": "111-111-1111",
        "loc-assistant": "Assistant Name",
        "assist-cell": "111-111-1111",
        "popup-text": "This Location accepts Cash Only"
        },
      "geometry": {
        "type": "Point",
        "coordinates": [
        -xx.xxxxxx,
        xx.xxxxxx
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "location-name": "Location2",
        "loc-address": "2211 North, State US 12345",
        "loc-number": "888-888-8882",
        "loc-manager": "Second Manager",
        "manager-cell": ""
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
        -xx.xxxxxx,
        xx.xxxxxx
        ]
      }
    }
    
  ]
}

Here is the js I've been editing:

function checkProperties(obj) {
    for (var key in obj) {
        if (obj[key] !== null && obj[key] != "")
            return false;
    }
    return true;
}
function onEachFeature (feature, layer) {
    var props = feature.properties || {};
    var text;
    console.log(text);
    if (<?php echo $table_view; ?>) {
        text = window.WPLeafletMapPlugin.propsToTable(props);
    } else {
        
        Object.keys(window.WPLeafletMapPlugin.template(feature.properties)).forEach(function(key, index) {
            //removeEmpty(this[key]);
            if ( checkProperties(this[key]) )
            {
                //given key does not exist or it has "" or NULL value
                console.log("other: " +this[key]);
                text += "<span class='hide'>"+this[key]+"</span>";
            } else {
                console.log("happy: " + this[key]);
                text += "<span class='show'>"+this[key]+"</span>";
            }
            
  
}, window.WPLeafletMapPlugin.template(feature.properties));
    console.log(text);
        
        /* text = popup_property
            ? props[ popup_property ]
            : window.WPLeafletMapPlugin.template(
                popup_text, 
                feature.properties
            ); */
            
    }
    if (text) {
        layer.bindPopup( text );
        
    }
}
@bozdoz
Copy link
Owner

bozdoz commented Mar 3, 2024

You're looking for something like a full template engine for the geojson? Like having an if statement to conditionally show the assistant info?

@goodyis
Copy link
Author

goodyis commented Mar 4, 2024

@bozdoz Not really a full templating system, just a way to check if a json key/pair is empty before showing it.

so something like::

[leaflet-map fitbounds scrollwheel  zoomcontrol !detect-retina show_scale draggable height="500"]
[leaflet-geojson src="xxxx" fitbounds="1" iconUrl="xxxx" iconSize="80,50" iconAnchor="40,60"]
<b>{location-name}</b></br><span class="map-link">{loc-address}</span>
</br>Manager: {loc-manager}
<a href="tel:{loc-number}"/>{loc-number}</a> Direct
<a href="tel:{manager-cell}"/>{manager-cell}</a> Cell</br>
</hr>

if ({loc-assistant} & {assist-cell}) {
   Assistant Manager: {loc-assistant}
   <a href="tel:{assist-cell}"/>{assist-cell}</a> Cell</br>
}



if ({popup-text}) {
  </hr>
  More Info: {popup-text}
}
[/leaflet-geojson]

The goal being this popup below would not show the "More Info: {popup-text}"
Because the json for that element is "popup-text": "",
While the same thing happens if the element doesn't have popup-text listed as a parameter.
Screenshot 2024-03-04 at 1 43 29 PM

@goodyis
Copy link
Author

goodyis commented Mar 4, 2024

@bozdoz
So a weird work around, if I could get the javascript to actually run after the elements are loaded is to change someof the 'class.geojson-shortcode.php' code to the following:

function checkProperties(obj) {
    for (var key in obj) {
        if (obj[key] !== null && obj[key] !== "") {
            return false;
        }
    }
    return true;
}

function removeEmpty(obj) {
    return Object.entries(obj)
        .filter(([_, v]) => v !== null && v !== "")
        .reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {});
}
function onEachFeature (feature, layer) {
    var props = feature.properties || {};
    //console.log(props);
    var text;
    //console.log(text);
    if (<?php echo $table_view; ?>) {
        text = window.WPLeafletMapPlugin.propsToTable(props);
    } else {
        
        var text = "";  // Initialize text variable



// Assuming window.WPLeafletMapPlugin.template(feature.properties) returns an object
var templateProperties = window.WPLeafletMapPlugin.template(feature.properties);

Object.keys(templateProperties).forEach(function (key) {
    var value = templateProperties[key];
    
    if (checkProperties(value)) {
        // Given key does not exist or it has "" or NULL value
        //console.log("other: " + value);
        // If you want to remove empty properties, use removeEmpty function
        //templateProperties[key] = removeEmpty(value);
        templateProperties[key] = "<span class='removeMe'>n\/a</span>";
        
    } else {
        //console.log("happy: " + value);
        // Add the non-empty value to the text variable
        //text += value;
    }
});
            text = popup_property
            ? props[ popup_property ]
            : window.WPLeafletMapPlugin.template(
                popup_text, 
                feature.properties
            );
    }
    if (text) {
        layer.bindPopup( text );
        
    }
}

Then change the shortcode to have the section wrapped in a span with class like:

<span class="parent"><hr/>More Info: {popup-text}</span>[/leaflet-geojson]

Then have the following js added:

<script>
jQuery( document ).ready(function($) {
    console.log( "ready!" );
  $('.removeMe').closest('.parent').remove();
});
</script>

This seems like non-scalable workaround.

I'm hoping you have a cleaner idea.

@goodyis
Copy link
Author

goodyis commented Mar 5, 2024

@bozdoz I've get it working. I don't think you would call this a 'template engine'

Could you add a hook where I/others could override this file or functions?

  • because I imagine someone somewhere would have an issue with each empty value getting wrapped in a span element
    ===

  • add checkProperties function to class.geojson-shortcode.php

function checkProperties(obj) {
    for (var key in obj) {
        if (obj[key] !== null && obj[key] !== "") {
            return false;
        }
    }
    return true;
}
  • modify the onEachFeature function to include a call to the checkProperties function created
  • modify output of a property that doesn't have contain a value to be wrapped in a span with a class
  • optional include the text N/A in that span for new default text
function onEachFeature (feature, layer) {
    var props = feature.properties || {};
    var text;
    if (<?php echo $table_view; ?>) {
        text = window.WPLeafletMapPlugin.propsToTable(props);
    } else {
        
        var text = "";  // Initialize text variable

        // Assuming window.WPLeafletMapPlugin.template(feature.properties) returns an object
        var templateProperties = window.WPLeafletMapPlugin.template(feature.properties);
        
        Object.keys(templateProperties).forEach(function (key) {
            var value = templateProperties[key];
            
            if (checkProperties(value)) {
                // Given key does not exist or it has "" or NULL value
                // Replaces empty values with N/a and class name so it can be removed
                templateProperties[key] = "<span class='removeMe'>n\/a</span>";
            }
        });

        // the following is unchanged
        text = popup_property
        ? props[ popup_property ]
        : window.WPLeafletMapPlugin.template(
            popup_text, 
            feature.properties
        );
    }
    if (text) {
        layer.bindPopup( text );
    }
}
  • then when shortcode used in wordpress, wrap each section with a .parent span
[leaflet-geojson src="XXX.map.geojson" fitbounds="1" iconUrl="pathToImage.png" iconSize="80,50" iconAnchor="40,60"]
<span class="parent"><b>{location-name}</b></span>
<span class="parent"></br><span class="map-link">{loc-address}</span></span>
<span class="parent"></br>Manager: {loc-manager}</span>
<span class="parent"><a href="tel:{loc-number}"/>{loc-number}</a> Direct</span>
<span class="parent"><a href="tel:{manager-cell}"/>{manager-cell}</a> Cell</br></span>
<span class="parent"><hr/>Assistant Manager: {loc-assistant}
  <a href="tel:{assist-cell}"/>{assist-cell}</a> Cell</br></span>
<span class="parent"><hr/>More Info: {popup-text}</span>[/leaflet-geojson]
  • then very simple CSS; could be placed in theme, or in the wordpress block where shortcode is called
.parent:has(.removeMe) {
  display: none;
}

@bozdoz
Copy link
Owner

bozdoz commented Mar 5, 2024

I think all you may need is a hook in the onEachFeature function

bozdoz pushed a commit that referenced this issue Mar 5, 2024
@bozdoz
Copy link
Owner

bozdoz commented Mar 5, 2024

What do you think of this? #249

@goodyis
Copy link
Author

goodyis commented Mar 5, 2024

@bozdoz That did the trick; thank you sir.
Since that passed tests on the pull request, will you be pushing that on your next update?

@bozdoz
Copy link
Owner

bozdoz commented Mar 6, 2024

actually on second thought, it should just be a javascript implementation, instead of php

@bozdoz
Copy link
Owner

bozdoz commented Mar 6, 2024

On third thought, it may be way less maintainable to move it to javascript. I'll reconsider

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants