создание асинхронного «метода экземпляра» для объекта ngResource

0

В моем приложении есть концепция Event, которая имеет атрибуты широты и долготы. На стороне клиента я хотел бы использовать 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

  • 0
    Его постоянно меняется ..
  • 0
    Создать плункер
Показать ещё 1 комментарий
Теги:
promise
geolocation
prototype-programming

2 ответа

0
Лучший ответ

Я "исправил" это, признав, что вы не можете ожидать, что представление развяжет обещание. Таким образом, внутри контроллера просто повторяется над $ scope.events и называется методом, который 1) развязал обещание. 2) прямое значение расстояния на объекте.

0

Поэтому я увидел бесконечную ошибку цикла, если я выбрал "block", когда браузер попросил геолокацию. Если бы я сказал "Разрешить", это сработало. Сказав, что я думаю, что код можно было бы убрать и разбивать на отдельные единицы операции, чтобы упростить отслеживание ошибки и сделать приложение более читаемым. Прикрепленный подход, который я, возможно, принял: 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;
    });
  });
}]);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню