2016-03-27 73 views
0

我的應用程序具有一個具有經度和緯度屬性的Event概念。客戶端,我想使用navigator.geolocation來計算每個事件的當前距離並在視圖中顯示它。在ngResource對象上創建異步「實例方法」

以下是我到目前爲止。它運行,但它陷入了一個無限循環(下面的錯誤)。

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:

https://plnkr.co/edit/zk5ETxCzvzKYAJOlUPPA?p=preview

+0

其不斷變化.. – amanuel2

+0

創建一個運動員 –

+0

@DrJones plunker補充 - 謝謝! – jsharpe

回答

0

我「固定」這一點。所以,在控制器內部迭代了$ scope.events,並調用了一個方法,1)展開承諾2)直接設置對象的距離值。

0

所以,我看到了無限循環的錯誤,如果我選擇了 「塊」 的時候,瀏覽器請求的地理位置。如果我說「允許」,它就起作用了。話雖如此,我認爲代碼可以整理一些並分解成單個操作單元,以便更輕鬆地跟蹤錯誤並使應用程序更具可讀性。附件是我可以採取的方法: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; 
    }); 
    }); 
}]);