我的应用有一个具有纬度和经度属性的事件概念。客户端,我想使用navigator.geolocation来计算每个事件的当前距离并在视图中显示它。
以下是我到目前为止的情况。它运行,但它陷入无限循环(下面的错误)。
factory('ys$currentPosition', ['$q', '$window', function($q, $window){
'use strict';
return {
position: function(){
var deferred = $q.defer();
if ($window.navigator.geolocation) {
$window.navigator.geolocation.getCurrentPosition(
function (position) {
deferred.resolve(position);
},
function (err) {
deferred.reject(err);
}
);
} else {
deferred.reject('Geolocation not supported.');
}
return deferred.promise;
}
};
}]).
factory('Event', ['$resource', 'ys$currentPosition', function($resource, ys$currentPosition){
'use strict';
var Event = $resource($server_hostname + '/api/v4/organizations/' + $org_id + '/events/:id', {}, {});
Event.prototype.distance = function(){
var this_event = this;
return ys$currentPosition.position().then(function(position){
return getDistanceFromLatLonInMi(
position.coords.latitude,
position.coords.longitude,
this_event.latitude,
this_event.longitude
)
});
}
return Event;
}]).
View (in HAML):
%ys-index-row-right{"ng-if" => "item.distance()"}
%i.fa.fa-map-marker
%span
{{ item.distance() }} mi
这是错误:
angular-0195028….js?body=1:69 Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [[{"msg":"item.distance()","newVal":{},"oldVal":{}}],[{"msg":"item.distance()","newVal":{},"oldVal":"..."}],[{"msg":"item.distance()","newVal":{},"oldVal":"..."}],[{"msg":"item.distance()","newVal":{},"oldVal":"..."}],[{"msg":"item.distance()","newVal":{},"oldVal":"..."}]]
Plunker:
答案 0 :(得分:0)
所以我看到无限循环错误,如果我选择"阻止"当浏览器询问地理位置时。如果我说'#34;允许"有效。话虽如此,我认为代码可以整理一些并分解为单个操作单元,以便更容易地追踪错误并使应用程序更具可读性。附件是我可能采取的方法:Plunker Here
这里只是script.js代码
var app = angular.module('app', ['ngMockE2E', 'ngResource', 'controllers']);
app.run(function($httpBackend) {
events = [{title: 'hello world', latitude: '38', longitude: '-77'}];
$httpBackend.whenGET('/foos').respond(events);
});
app.factory('ys$currentPosition', ['$q', '$window', function($q, $window){
'use strict';
return {
position: function(){
var deferred = $q.defer();
if ($window.navigator.geolocation) {
$window.navigator.geolocation.getCurrentPosition(
function (position) {
deferred.resolve(position);
},
function (err) {
deferred.reject(err);
}
);
} else {
deferred.reject('Geolocation not supported.');
}
return deferred.promise;
}
};
}]).
factory('EventService', function($q, $http, ys$currentPosition) {
'use strict';
function fetchEvents() {
var deferred = $q.defer();
$http.get('/foos').then(function(result){
deferred.resolve(result.data);
});
return deferred.promise;
}
function appendDistanceFromEvents(events) {
var deferred = $q.defer();
ys$currentPosition.position().then(function(position){
_.forEach(events, function(event) {
event.distance = determineDistanceFromEvent(event, position);
});
deferred.resolve(events);
});
return deferred.promise;
}
function determineDistanceFromEvent(event, userPosition) {
var dist = getDistanceFromLatLonInMi(
userPosition.coords.latitude,
userPosition.coords.longitude,
event.latitude,
event.longitude
)
console.log(dist)
return dist;
}
var deg2rad = function(deg) {
return deg * (Math.PI/180)
}
var getDistanceFromLatLonInMi = function(lat1, lon1, lat2, lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2-lat1); // deg2rad below
var dLon = deg2rad(lon2-lon1);
var a =
Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c; // Distance in km
d = d * 0.621371;
return d;
};
return {
fetchEvents: fetchEvents,
appendDistanceFromEvents: appendDistanceFromEvents
};
});
angular.module('controllers', []).
controller('EventsController', ['$scope', '$controller', 'EventService', function($scope, $controller, EventService){
EventService.fetchEvents().then(function(events){
// real app is doing other stuff in here
// so would like to keep promise/then pattern
EventService.appendDistanceFromEvents(events).then(function(results) {
$scope.events = results;
});
});
}]);
答案 1 :(得分:0)
我已修复'通过认识到你不能期望视图解开承诺。因此,在控制器内部只是迭代$ scope.events并调用一个方法1)展开promise 2)直接在对象上设置距离值。