0

Is it possible to get the position of a user every minute when the app is running? I understood that the position can only be fetched in the index.html file. Ideally I want to do this in controller.js so I can save the location to my database using an AJAX call.

I tried to run it every minute by using setTimeout(). However, I can only see that it is called once:

function onDeviceReady() {
    setTimeout(getLocation(), 60* 1000);
}

function getLocation() {
    navigator.geolocation.getCurrentPosition(onSuccess, onError);
}

I am using the cordova-plugin-geolocation plugin! I try to avoid using the plugin of Google.

  1. Can I get the position of a user every minute in the onDeviceReady() function (only when the app is running, no background refresh required)?
  2. Can I get the position of a user in the controller.js file?
nimrod
  • 5,595
  • 29
  • 85
  • 149
  • Have you tried? Yes, you can obtain position in a controller – tier1 Feb 18 '16 at 14:08
  • Though you shouldn't. Consider using a directive and setting up the `$interval` in a directive's link function. Your controllers should be very thin. You also get the benefit of being able to tie in to the `$destroy` event in the link function very nicely, so you can remove the `$interval`. – Dan Feb 18 '16 at 14:14

2 Answers2

1

Your code does not work because it is

  1. Not bound to the digest cycle (and so Angular will not perform dirty checking on it and update the view)
  2. Is using setTimeout, which only queues a one-off task, rather than one that performs at an interval.

Here's an easy adjustment that could be run in a controller:

function onDeviceReady() {
  $interval(function() {
    navigator.geolocation.getCurrentPosition(onSuccess, onError);
  }, 60000)
}

I consider this to be a bad solution in a controller, though. Controllers shouldn't access the DOM (Except component controllers), and yes, navigator is part of the DOM. Here are two alternatives that use best practices - directives or components.


Angular 1.4

class LocationCtrl {
  constructor() {
    this.position = null
  }
}

function locationContainerDirective($interval) {
  function link(scope, el, attrs, ctrl) {
    const promise = $interval(() => {
      navigator.geolocation.getCurrentPosition(function(position) {
        ctrl.onUpdatePosition({ position })
      })
    }, 60000)

    scope.$on('$destroy', () => $interval.cancel(promise))
  }

  return {
    scope: {
      onUpdatePosition: '&'
    },
    bindToController: true,
    restrict: 'E',
    require: 'location',
    controller: LocationCtrl,
    controllerAs: 'location',
    transclude: true,
    template: '<div ng-transclude></div>',
    link
  }
}

Angular 1.5 (or 1.3 with a shim)

I'd propose creating a container component that provides a position via a callback, like so:

angular.component('position', {
  outputs: {
    onUpdatePosition: '&'
  }
  controller: class PositionCtrl {
    constructor($interval) {
      this.$interval = $interval
    }

    $onInit() {
      this.$interval(() => {
        navigator.geolocation.getCurrentPosition((position) => {
          this.onUpdatePosition({ position })
        })
      })
    }
  }
})

This could then be used like so in a component:

  <position on-update-position='$ctrl.onUpdatePosition(position)'></position>
  <google-map focus='$ctrl.position'></google-map>

Where <google-map> is some arbitrary component that uses a navigator position.

Dan
  • 10,282
  • 2
  • 37
  • 64
0

You need to use window.setInterval instead of window.setTimeout to call getLocation every x seconds. See also setTimeout or setInterval? for their differences.

In the Angular way, use the $interval service.

You need to provide the function as a parameter $interval( getLocation, 60000 ) instead of calling it.

Community
  • 1
  • 1
dex
  • 137
  • 5