0

I'm creating a Javascript app (without third-party frameworks or libraries) that needs to get a list of locations from a JSON object and display only those locations in a given radius. I've figured out how to determine whether or not a location's coordinates are in the desired radius, but I can't figure out how to filter the object using those results. Here's the relevant code:

function filterObj(obj) {
    var radiusSize = 100;
    return function filter() {
        var result;
        for (var i in obj) {
            var lat = 41.8781;
            var lon = 87.6298;
            var coordinates = (obj[i].location.[0].coordinates).split(",");
            lat2 = Number(coordinates[0]);
            lon2 = Number(coordinates[1]);
            result = toRadius(getDistance(lat, lon, lat2, lon2)) <= radiusSize;
        }
        return result;
    };
}

function getObj() {
    var xml = new XMLHttpRequest();

    xml.onreadystatechange = function() {
        if (xml.readyState === XMLHttpRequest.DONE) {
            if (xml.readyState === 4 && xml.status === 200) {
                obj = JSON.parse(xml.responseText);
                var ObjFilter = filterObj(obj);
                var filtered = obj.filter(objFilter);
                displayLocations(filtered);
            } else {
              //code to handle errors
            }
        }
    };

    xml.open("GET", "/api/locations.json", true);
    xml.send(null);
}

Right now, I know that filterObj() is repeatedly returning "false" for "result" because of the for loop. I've tried to store the results of filterObj() as an array, but then "result" returns several arrays containing the results of "toRadius(getDistance())", and again I know this is because of the for loop, but moving the "result" assignment out of the loop causes every result to be "false," which is incorrect.

So, how can I use the results that "toRadius(getDistance())" generates in "filterObj()" to filter the object I fetch in "getObj()" before I pass that object to "displayLocations()"?

Here's a sample of the object I'm working with:

[
  {
    "id": 12,
    "name": "Mount Helena City Park",
    "location": [
      {
        "city": "Helena, MT",
        "address": "Mount Helena City Park \nHelena, MT 59601",
        "coordinates": "46.5889179,-112.0593352"
      }
    ]
  }
]
5
  • 1
    I think you're making this a little harder than it needs to be. Please post the structure of the data that you're returning and I think we'll be able to help get the code working in a cleaner way. Commented Aug 26, 2017 at 23:18
  • Where are lat, lon, lat2, lon2 coming from ? As your code is now, they are undefined. Commented Aug 26, 2017 at 23:27
  • If the value of JSON.parse(xml.responseText) is what you expect, then getObj is not relevant here Commented Aug 26, 2017 at 23:39
  • @ChristopherMesser I wouldn't be surprised. I've added a sample of my object to my post. Commented Aug 26, 2017 at 23:54
  • @trincot Sorry about that. I've edited the post and added them back in. Commented Aug 26, 2017 at 23:55

2 Answers 2

1

Using promises and making some assumptions about your data structure (that the resulting JSON parses to [{lat: a, lon: b, ...}, {lat: c, lon: d, ...}, ...]), all that is left is to .filter

function getFilteredLocations(lat, lon, radius) {
    const distance = item =>
        Math.pow(Math.abs(item.lat - lat), 2)
        + Math.pow(Math.abs(item.lon - lon), 2);
    const r = Math.pow(radius, 2); // rather than doing sqrts in this example

    return fetch('/api/locations.json')
        .then(
            response => response.json(),
            error => Promise.reject({message: 'Failed to fetch resource', error}))
        .then(
            arr => arr.filter(item => distance(item) <= r),
            error => Promise.reject({message: 'Failed to parse JSON', error}));
}

getFilteredLocations(51.5073, -0.12755, 0.009) // ~ 1km radius of Charing Cross, London
    .then(displayLocations)
    .catch(error => console.error(error.message, error.error));

I also heavily simplified the GPS to Pythagoras for the distance example, you'd need to use your logic to convert your coodinates property into the desired value

Sign up to request clarification or add additional context in comments.

Comments

0

Your filterObject function (which returns a filter function) should not get the obj as argument, as that defeats the purpose of such a currying function: that obj will any way be passed, element by element, to the returned function, so there is no need to get it passed here.

Instead use this opportunity to pass the desired radius. Then the returned function will work with that.

Secondly, the returned function will get an element value as argument: you need to add that parameter and work with that value only: there should be no loop over the whole object there: this is what .filter will do later.

So it could work like this (I renamed the function for clarity):

function nearerThan(radiusSize = 100) {
    return function filter(obj) {
        var lat = 41.8781;
        var lon = 87.6298;
        var coordinates = (obj.location.[0].coordinates).split(",");
        var lat2 = Number(coordinates[0]);
        var lon2 = Number(coordinates[1]);
        var result = toRadius(getDistance(lat, lon, lat2, lon2)) <= radiusSize;
        return result;
    };
}

function getObj() {
    var xml = new XMLHttpRequest();
    var nearerThan100 = nearerThan(100);

    xml.onreadystatechange = function() {
        if (xml.readyState === XMLHttpRequest.DONE) {
            if (xml.readyState === 4 && xml.status === 200) {
                obj = JSON.parse(xml.responseText);
                var filtered = obj.filter(nearerThan100);
                displayLocations(filtered);
            } else {
                //code to handle errors
            }
        }
    };

    xml.open("GET", "/api/locations.json", true);
    xml.send(null);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.