0

TL;DR: I apologise for how unnecessary this task is.

Outline:
I have a portfolio project that I had completed, but apparently, I haven't done it according to the specification. So I have been instructed to redo a large portion of it in line with their guidelines.

It is a Gazetteer website project using leaflet.js and it must be constructed using jQuery, plain javaScript, and PHP routines to access multiple APIs to populate different Bootstrap Modals. I have produced something that I personally believe works perfectly well enough for the scope of this portfolio project.

You can try it out yourself here: https://kizzysinar.co.uk/project1/index.html

I was given this file: countryBorders.geo.json, which contains a bunch of different features:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "name": "Bahamas",
        "iso_a2": "BS",
        "iso_a3": "BHS",
        "iso_n3": "044"
      },
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [
            [
              [-77.53466,23.75975],
              [-77.78,23.71],
              [-78.03405,24.28615],
              [-78.40848, 24.57564],
              [-78.19087,25.2103],
              [-77.89,25.17],
              [-77.54,24.34],
              [-77.53466,23.75975]
            ]
          ],
          [
            [
              [-77.82,26.58],
              [-78.91,26.42],
              [-78.98,26.79],
              [-78.51,26.87],
              [-77.85,26.84],
              [-77.82,26.58]
            ]
          ],
          [
            [
              [-77,26.59],
              [-77.17255,25.87918],
              [-77.35641,26.00735],
              [-77.34,26.53],
              [-77.78802,26.92516],
              [-77.79,27.04],
              [-77,26.59]
            ]
          ]
        ]
      }
    }, 
    {..... MORE FEATURES
  ]
}

I was under the impression that I could use the file to populate the <select> dropdown options and to generate the map borders.
I utilised this locally stored file in the following ways:

  1. Used it to populate the <select> dropdown box:
result['data'].features.forEach(function (feature) {
                $("<option>", {
                    value: feature.properties.iso_a3,
                    text: feature.properties.name
                }).appendTo("#countrySelect")
  1. Since this is a locally stored file I chose to use the leaflet.ajax to parse the coordinates in the countryBorders.geo.json and create a layer of the multi polygons (features->properties->geometry->coordinates) for each feature.
var geoJSONLayer = new L.GeoJSON.AJAX('vendors/json/countryBorders.geo.json',{
    style: myStyle, 
    onEachFeature: onEachFeature
}).addTo(mymap);

To zoom into/ set the view of the map when the user selected a country, I used the stored value: feature.properties.iso_a3 to send an AJAX request to REST Countries API using the iso_a3 code to set the map view to the selected country according to the latlng of the returned results:

function setView() {
    $.ajax({
        url: "libs/php/locateCountry.php",
        type: 'POST',
        dataType: 'json',
        data: {
            iso: $('#countrySelect option:selected').val()
        },
        success: function(result) {

            if (result.status.name == "ok") {

                mymap.setView(result['coordinates']);

            }
      
        },

Problem:
But I, apparently, must use jQuery/AJAX to make a PHP request to access that locally stored countryBorders.geo.json and return the coordinates that match a given iso_a3. It's bonkers, and in my opinion, it makes almost zero sense to handle it this way.

Essentially, (what is meant to happen) when a user selects a country from the country list, the data stored in the selections value is used in an AJAX call to a PHP file getCountryBorders.php which I use the function file_get_contents to get the JSON data and return with the correct featureCollection/set of coordinates that matches the requested iso code and that is then passed to create an L.geoJSON layer in which the user can then trigger the bootstrap modal.

<select>/<option:selected> -> value: iso_a3 -> AJAX iso: iso_a3 request iso -> PHP cURL -> countryBorders.geo.json -> match feature.properties.iso_a3 == 'iso' -> $output = border coordinates -> AJAX success function generates a new L.geoJSON of the border coordinates of that country.

What I need help with:
This is the example PHP file I was given which of course is a bit naff:

<?php
    ini_set('display_errors', 'On');
    error_reporting(E_ALL);

    $executionStartTime = microtime(true);

    $result=file_get_contents('C:\xampp\htdocs\project1\vendors\json\countryBorders.geo.json');

    $decode = json_decode($result,true);    

    $output['status']['code'] = "200";
    $output['status']['name'] = "ok";
    $output['status']['description'] = "success";
    $output['status']['returnedIn'] = intval((microtime(true) - $executionStartTime) * 1000) . " ms";
    $output['data'] = $decode;

    header('Content-Type: application/json; charset=UTF-8');

    echo json_encode($output); 
?>

I've tried to rewrite it and thought an foreach statement would suffice, but I've hit a bit of a brick wall regarding how to search through a .json file in PHP and capture the corresponding object's coordinate array.

<?php
    ini_set('display_errors', 'On');
    error_reporting(E_ALL);

    $start=microtime( true );
    $file=file_get_contents('vendors\json\countryBorders.geo.json');

    $json=json_decode($file, true);

    foreach ($json->features->properties as $object) {
        if ($object->iso_a3 == $_REQUEST['iso']) {
            $output=array(
                'border'    => $object->coordinates,
                'status'    =>  array(
                    'code'          =>  200,
                    'name'          =>  'ok',
                    'description'   =>  'success',
                    'returnedIn'    =>  intval( ( microtime( true ) - $start ) * 1000 ) . 'ms'   
                ),
            ); 
        } else {
            $output=$json;
        }
    }

    header('Content-Type: application/json; charset=UTF-8');
    exit( json_encode( $output ) );
    
?>
function setView() {
    $.ajax({
        url: "libs/php/getCountryBorders.php",
        type: 'POST',
        dataType: 'json',
        data: {
            iso: $('#countrySelect option:selected').val() //getting iso from the value in the option
        },
        success: function(result) {

            if (result.status.name == "ok") {

                console.log(result['border']); //currently just logging the result

            }
      
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.log(jqXHR);
        }
    });
};

Right now, the code isn't searching/iterating through the countryBorders.geo.json and I get a number of errors:

{readyState: 4, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …}
script.js:69 parsererror
script.js:70 SyntaxError: Unexpected token < in JSON at position 0
    at parse (<anonymous>)
    at jquery.min.js:2
    at l (jquery.min.js:2)
    at XMLHttpRequest.<anonymous> (jquery.min.js:2)
Ranisimo
  • 35
  • 13
  • https://stackoverflow.com/questions/37280274/syntaxerror-unexpected-token-in-json-at-position-0 – CBroe Aug 26 '21 at 07:30
  • Are you actually _required_ to use the `iso_a3` to identify the correct record? Because if not, you could simply use the _index_ of the elements inside `feature` as the value for your select options - then you can access the needed element _directly_ via that on the server side, and don't have to "search" the array for it. – CBroe Aug 26 '21 at 07:32
  • Is `getCountryBorders.php` returning valid JSON? That parse error suggests it might be returning HTML (or something else with a < in it). – peeebeee Aug 26 '21 at 13:11
  • @CBroe Unfortunately I am required to use the `iso_a3`. Although thank you for your suggestion, I wish I could go that route instead. – Ranisimo Aug 26 '21 at 13:37
  • @peeebeee It isn't, and I'm not sure why. I checked out the link CBroe commented and it would be likely that it is returning HTML and not JSON. I'm still trying to work out why, and it could be something to do with my AJAX call itself. Anywho, the `parsererror` is just one of the problems now bundled on top! – Ranisimo Aug 26 '21 at 13:39
  • Use your browser dev tools, network panel, to inspect the response for that AJAX request. If your PHP code created any errors or warning, then it is very likely that you get HTML tags in the output due to that (default for config option `html_errors` is true.) – CBroe Aug 26 '21 at 13:47
  • Regarding the filtering inside your loop - what is the `else` branch supposed to be good for? Remove that. And instead of overwriting `$output` each time the condition is true, _add_ new items to it - initialize it properly as an empty array before your loop, and then inside, do `$output[] = ...` – CBroe Aug 26 '21 at 13:50
  • Yep, okay it appears to be an issue with accessing properties in an array. b>Warning: Attempt to read property "feature" on array in C:\xampp\htdocs\project1\libs\php\getCountryBorders.php on line 13

    Warning: foreach() argument must be of type array|object, null given in C:\xampp\htdocs\project1\libs\php\getCountryBorders.php on line 13
    – Ranisimo Aug 26 '21 at 14:52
  • Changing `foreach ($json->feature as $object)...` to `foreach ($json["features"] as $object)` resolved that issue – Ranisimo Aug 26 '21 at 14:55

0 Answers0