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 控制台显示如下:
- 数组:
- 数组[]getParcelController.js:45:9
- 格式化地址:
- 德国柏林米特区getParcelController.js:34:17
- 德国科隆因内施塔特 getParcelController.js:34:17
- Altstadt-Lehel,慕尼黑,德国 getParcelController.js:34:17
- 德国柏林米特区getParcelController.js:34:17
- 德国科隆因内施塔特 getParcelController.js:34:17
您知道为什么控制台日志可以正常工作而数组函数却不能吗?
如果我在回调函数之外编写数组函数并且没有 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);
});
完整示例
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 控制台显示如下:
- 数组:
- 数组[]getParcelController.js:45:9
- 格式化地址:
- 德国柏林米特区getParcelController.js:34:17
- 德国科隆因内施塔特 getParcelController.js:34:17
- Altstadt-Lehel,慕尼黑,德国 getParcelController.js:34:17
- 德国柏林米特区getParcelController.js:34:17
- 德国科隆因内施塔特 getParcelController.js:34:17
您知道为什么控制台日志可以正常工作而数组函数却不能吗? 如果我在回调函数之外编写数组函数并且没有 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);
});
完整示例