0
votes

I recently used Titanium and Alloy to develop an android application. Now I'm trying (for the first time) to sort a bound backbone collection by distance with a comparator function, but it doesn't work.

comparator: function(game) {
    var lon1, lat1, lat2, lon2;
    if (Ti.Geolocation.locationServicesEnabled) {
        Ti.Geolocation.getCurrentPosition(function(e) {
            if (e.error) {
                Ti.API.error('Error:' + e.error);
                return 0;
            } else {
                Ti.API.info(e.coords);

                lon1 = e.coords.longitude;
                lat1 = e.coords.latitude;

                Titanium.Geolocation.forwardGeocoder(game.get("camp"), function(e) {
                    if (e.success) {
                        lat2 = e.latitude;
                        lon2 = e.longitude;

                        var R = 6371; // km
                        var dLat = (lat2 - lat1) * Math.PI / 180;
                        var dLon = (lon2 - lon1) * Math.PI / 180;
                        var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                            Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
                            Math.sin(dLon / 2) * Math.sin(dLon / 2);
                        var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
                        var d = R * c;

                        console.log("KM: " + parseInt(d));

                        return parseInt(d);
                    } else {
                        console.log("Unable to find address");

                        return 0;
                    }
                });
            }
        });
    } else {
        console.log('please enable location services')

        return 0;
    }
}

In my controller, I use:

var games = Alloy.Collections.allGames;
games.sort();
games.fetch();

Can you tell me what is wrong?

1

1 Answers

1
votes

I don't use neither Titanium or Alloy, but I can see why your comparator function won't work.

Backbone collection's comparator property

First, to see why it doesn't work, you need to understand what's the collection's comparator property, what's available and how to implement one.

There are (at least) 3 types of value a collection's comparator property can take.

  • The name of an attribute as a string

    comparator: 'fieldName'
    
  • A sortBy function which takes a single argument

    comparator: function(model) {
        // return a numeric or string value by which the model 
        // should be ordered relative to others.
        return Math.sin(model.get('myNumber'));
    }
    
  • A sort function that expects two arguments

    comparator: compare(modelA, modelB) {
        var field = 'myNumber',
            numA = modelA.get(field),
            numB = modelB.get(field);
        if (numA < numB) {
            return -1;
        }
        if (numA > numB) {
            return 1;
        }
        // a must be equal to b
        return 0;
    }
    

Why yours fails?

The short answer: It only ever returns undefined or 0 depending on the value of Ti.Geolocation.locationServicesEnabled.

You have made a convoluted function to sort your models in which you use asynchronous functions (getCurrentPosition, forwardGeocoder) and you put all the logic inside callbacks which are evaluated when the collection has already finished sorting.