0

I have a js object like this

var routes = [
    {lat: 12.44, lng: 74.50},
    {lat: 12.54, lng: 74.60},
    {lat: 12.64, lng: 74.70},
    ...
];

I want to calculate distance between 2 points from the routes array to create a new array with lat,lng and distance from previous point. Using recursive function I can do that in sequential order, so until the http request is not resolved I do not call the next points. here is the recursive code

var finalData = [];
function getData(points, i) {
    if(points.length >= i+1) {
        var p1 = points[i];
        var p2 = points[i+1];
        var url = 'http://to/web/app/origin=' + p1.lat + ',' + p1.lng + '&destination=' + p2.lat + ',' + p2.lng;
        http.get(url, function(res) {
            var data = '';
            res.on('data', function(chunk) {
                data += chunk;
            });
            res.on('end', function() {
                var d = JSON.parse(data);
                finalData.push({
                    lat: p2.lat,
                    lng: p2.lng,
                    distance: d.dis
                });
                getData(points, i+1);
            });
        });
    }
}
getData(routes, 0);

Being new to Reactive Programming, not able to think and find out how can I achieve the same using Rxjs library? I mean some small declarative code.

Cœur
  • 37,241
  • 25
  • 195
  • 267
FarazShuja
  • 2,287
  • 2
  • 23
  • 34

2 Answers2

1

It doesn't seem like you actually need to do this recursively since you had a list of the items that you will be using:

//Make your callback function `Observable`
const observableHttp = Rx.Observable.bindCallback(http.get);
//Optionally if it is a node-style callback
//const observableHttp = Rx.Observable.bindNodeCallback(http.get);

Rx.Observable.from(routes)
  //Combine each of the elements into pairwise arrays
  .pairwise()
  //Maintain the order of the responses
  .concatMap(points => {
    const p1 = points[0];
    const p2 = points[1];
    return observableHttp(`http://to/web/app/origin=${p1.lat},${p1.lng}` + 
                          `&destination=${p2.lat},${p2.lng}`);
  },
  //Process the response along with the original array of responses 
  (points, res) => ({lat: points[1].lat, lng: points[1].lng, distance: res.dis}))
  //Gather all the values into a single array
  .toArray()
  .subscribe(x => /*Do something with your array of values*/
paulpdaniels
  • 18,395
  • 2
  • 51
  • 55
  • Actually res is not data object, instead its event object. so actual data is retrieved on res.end event, I have updated the question please review. – FarazShuja Aug 11 '16 at 08:59
1

Extending the answer by @paulpdaniels I was able to fix my code. Putting it here if someone interested.

Rx.Observable.from(data)
    .pairwise()
    .concatMap(points => {
        const p1 = points[0];
        const p2 = points[1];
        var url = `http://to/web/app?origins=${p1.lat},${p1.lng}` + 
                         `&destinations=${p2.lat},${p2.lng}`;
        return GetDataStream(url);
    },
    //Process the response along with the original array of responses 
    (points, dis) => {          
        return {lat: points[1].lat, lng: points[1].lng, distance: dis};
    })
    .toArray()
    .subscribe(x => console.log(x));

and her is the custom observable

const GetDataStream = function(url) {
    return Rx.Observable.create(observer => {
        http.get(url, res => {
            var _data = ''
            res.on('data', chunk => {
                _data += chunk;
            });
            res.on('end', () => {
                var d = JSON.parse(_data);
                var distance = d.rows[0].elements[0].distance.value;
                observer.next(distance);
                observer.complete();
            });
        });
    });
}
FarazShuja
  • 2,287
  • 2
  • 23
  • 34