Google 地图地理编码 AngularJS 忽略回调

Google Maps Geocode AngularJS ignores callback

AngularJS 中 Google 地图的 JavaScript 地理编码 Api 我遇到了一个奇怪的问题。

首先我做了一些研究,我发现我必须使用 javascript 回调函数来从坐标中获取格式化地址。

我是这样实现回调函数的:

"use strict";

var getParcelApp = angular.module("getParcelApp", []);

function getStartAddress(latlng, callback) {
    var geocoder = new google.maps.Geocoder;

    geocoder.geocode({ 'location': latlng }, function(results, status) {
        if (status === google.maps.GeocoderStatus.OK) {
            callback(results[2].formatted_address); // HERE THE CALLBACK
        }
    });
};

var GetParcelAppController = function($scope, $http) {
    $http.get("/umbraco/surface/ParcelSurface/GetLatLngParcel")
        .success(function(result) {
            $scope.coordinates = result;
            $scope.getStartCoordinate();
        })
        .error(function(data) {
            console.log(data);
        });

    $scope.getStartCoordinate = function() {
        var latlng;

        $scope.listOfCoordinates = [];

        for (var i = 0; i < $scope.coordinates.length; i++) {
            latlng = { lat: $scope.coordinates[i].Latitude, lng: $scope.coordinates[i].Longitude };

            getStartAddress(latlng, function(formattedAddress) {
                console.log(formattedAddress); // HERE formattedAddress WORKS
                var coordinate = {
                    id: $scope.coordinates[i].Id,
                    waypointId: $scope.coordinates[i].WaypointId,
                    latitude: $scope.coordinates[i].Latitude,
                    longitude: $scope.coordinates[i].Longitude,
                    address: formattedAddress // HERE formattedAddress ISN'T WORKING
                };
                $scope.listOfCoordinates.push(coordinate);
            });
        }
        console.log($scope.listOfCoordinates);

    };
};

getParcelApp.controller("getParcelAppCtrl", GetParcelAppController);

如您所见,我想要一组 坐标对象 。但我真的不知道为什么 console.log 显示正确的结果并且数组 complete empty?

Firefox 控制台显示如下:

您知道为什么控制台日志可以正常工作而数组函数却不能吗? 如果我在回调函数之外编写数组函数并且没有 address: 则创建数组。

更详细:

我想在 select 下拉框中显示坐标的格式化地址。这在 html 文件中定义为

<select id="getParcel" class="form-control"></select>

我编辑了 getStartAddress 调用,如下所示:

$scope.getStartCoordinate = function() {
    var latlng;
    var selectBox = document.getElementById("getParcel");

    $scope.listOfCoordinates = [];

    for (var i = 0; i < $scope.coordinates.length; i++) {
        latlng = { lat: $scope.coordinates[i].Latitude, lng: $scope.coordinates[i].Longitude };

        getStartAddress(latlng, function(formattedAddress) {
            var coordinate = {
                id: $scope.coordinates[i].Id,
                waypointId: $scope.coordinates[i].WaypointId,
                latitude: $scope.coordinates[i].Latitude,
                longitude: $scope.coordinates[i].Longitude,
                address: formattedAddress
            };
            $scope.listOfCoordinates.push(coordinate);
            console.log($scope.listOfCoordinates);

            var selectElement = document.createElement("option");
            selectElement.textContent = coordinate.address;
            selectElement.value = coordinate.address;

            selectBox.appendChild(selectElement);
        });
    }

};

我真的不是javascript方面的专家,但据我了解,在获取回调数据时会调用getStartAddress中的函数吗? 所以回调完成后select下拉框应该填上地址,不是吗?

好的,我用 forEach 而不是简单的 for 循环解决了这个问题。

所以结果如下:

"use strict";

var getParcelApp = angular.module("getParcelApp", []);

function getStartAddress(latlng, callback) {
    var geocoder = new google.maps.Geocoder;

    geocoder.geocode({ 'location': latlng }, function(results, status) {
        if (status === google.maps.GeocoderStatus.OK) {
            callback(results[2].formatted_address);
        }
    });
};

var GetParcelAppController = function($scope, $http) {
    $http.get("/umbraco/surface/ParcelSurface/GetLatLngParcel")
        .success(function(result) {
            $scope.coordinates = result;
            $scope.getStartCoordinate();
        })
        .error(function(data) {
            console.log(data);
        });

    $scope.getStartCoordinate = function() {
        var latlng;
        var selectBox = document.getElementById("getParcel");

        $scope.listOfCoordinates = [];

        $scope.coordinates.forEach(function(point) {
            latlng = { lat: point.Latitude, lng: point.Longitude };

            getStartAddress(latlng, function (formattedAddress) {
                var coordinate = {
                    id: point.Id,
                    waypointId: point.WaypointId,
                    latitude: point.Latitude,
                    longitude: point.Longitude,
                    address: formattedAddress
                };
                $scope.listOfCoordinates.push(coordinate);

                var selectElement = document.createElement("option");
                selectElement.textContent = formattedAddress;
                selectElement.value = formattedAddress;

                selectBox.appendChild(selectElement);
            });
        });
    };
};

getParcelApp.controller("getParcelAppCtrl", GetParcelAppController);

您正在循环中处理 async google.maps.Geocoder.geocode 函数。为此,您可能希望利用 $q.all 将许多承诺组合成一个,只有在所有承诺都得到解决后才会得到解决

在你的情况下,让我们首先介绍一个 promise 来获取地址:

$scope.getStartAddressPromise = function (latlng) {
    var deferred = $q.defer();
    getStartAddress(latlng, function (formattedAddress) {
        console.log(formattedAddress); // HERE formattedAddress WORKS
        var coordinate = {
            id: latlng.Id,
            waypointId: latlng.WaypointId,
            latitude: latlng.Latitude,
            longitude: latlng.Longitude,
            address: formattedAddress // HERE formattedAddress ISN'T WORKING
        };
        $scope.listOfCoordinates.push(coordinate);
        deferred.resolve();
    });
    return deferred.promise;
};

然后你可以替换:

for (var i = 0; i < $scope.coordinates.length; i++) {
    latlng = { lat: $scope.coordinates[i].Latitude, lng: $scope.coordinates[i].Longitude };

    getStartAddress(latlng, function (formattedAddress) {
        console.log(formattedAddress); // HERE formattedAddress WORKS
        var coordinate = {
            //id: $scope.coordinates[i].Id,
            //waypointId: $scope.coordinates[i].WaypointId,
            latitude: $scope.coordinates[i].Latitude,
            longitude: $scope.coordinates[i].Longitude,
            address: formattedAddress // HERE formattedAddress ISN'T WORKING
        };
        $scope.listOfCoordinates.push(coordinate);
    });
}
console.log($scope.listOfCoordinates);

与:

var promises = [];

$scope.listOfCoordinates = [];
angular.forEach($scope.coordinates, function (coordinate) {
    var latlng = { lat: coordinate.Latitude, lng: coordinate.Longitude };
    promises.push($scope.getStartAddressPromise(latlng));
});

$q.all(promises).then(function () {
    console.log($scope.listOfCoordinates);
});

完整示例

Plunker