创建异步'实例方法'在ngResource对象

时间:2016-03-27 17:31:15

标签: angularjs geolocation promise prototype-programming

我的应用有一个具有纬度和经度属性的事件概念。客户端,我想使用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:

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

2 个答案:

答案 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)直接在对象上设置距离值。