Sign up ×
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other. Join them, it only takes a minute:

I am trying to bind data between a service, controller and a view. Below, I have provided plunker link for the app.

Basically 'dataService' has a function to find geolocation. The function sets the variable dataService.locationDone.

The dataService is assigned to $scope.data in the 'HomeController'.

In home.html, I refer the value of data.locationDone to show different labels.

The issue is, after the locationDone variable is modified in the dataService, the labels in the home.html does not change.

plunker link: http://embed.plnkr.co/BomSztgC7PzGMzJyDKoF/preview

Service:

storelocator.factory('dataService', [function() {
    var data = {
        locationDone: 0,
        position: null,
        option: null
    }

    var getLocation = function() {
        data.locationDone = 0;

        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(function (pos) {
                data.locationDone = 1;
                data.position = pos;
                console.log('got location ', data.locationDone);
            }, function () {
                data.locationDone = 2;
            });
        } else {
            data.locationDone = 3;
        }
    };

    getLocation();

    return data;
}]);

Controller:

storelocator.controller('HomeController', ['$scope', '$location', 'dataService', function ($scope, $location, dataService) {
        $scope.data = dataService;
        console.log('Home ctrl', $scope.data.locationDone);

        $scope.fn = {};
        $scope.fn.showOne = function () {
            $scope.data.option = 3;
            $location.path('/map');
        };

        $scope.fn.showAll = function () {
            $scope.data.option = 99;
            $location.path('/map');
        };
}]);

view:

<div layout="column" layout-align="start center">
    <div layout="column" layout-margin layout-padding>
        <div flex layout layout-margin layout-padding>
            <md-whiteframe flex class="md-whiteframe-z1" layout layout-align="center center" ng-show="data.locationDone==0">
                <span flex>Awaiting location information.</span>
            </md-whiteframe>
            <md-whiteframe flex class="md-whiteframe-z1" layout layout-align="center center" ng-show="data.locationDone==2"><span flex>Error in getting location.</span>
            </md-whiteframe>
            <md-whiteframe flex class="md-whiteframe-z1" layout layout-align="center center" ng-show="data.locationDone==3"><span flex>The browser does not support location.</span>
            </md-whiteframe>
        </div>
        <md-button flex ng-show="data.locationDone==1" class="md-accent md-default-theme md-raised" ng-click="fn.showOne()">Find Nearest Three Stores</md-button>
        <div flex></div>
        <md-button ng-show="data.locationDone==1" flex class="md-accent md-default-theme md-raised" ng-click="fn.showAll()">Find All Stores</md-button>

    </div>
</div>
share|improve this question

1 Answer 1

up vote 1 down vote accepted

You are updating the variable locationDone defined in the scope of the service. It will not have any impact on the object that you have returned during in the service (when updated later). Instead predefine an object in your service and update the property on the reference rather than a variable. Also note that since you are using native async api, which runs out of the angular context you would need to manually invoke digest cycle by doing $rootScope.$apply() in your case or just use $timeout wrap your updates in $timeout. However better approach would be to property create an api in dataService with method returning $q promise.

With timeout

.factory('dataService', ['$timeout', function($timeout) {

    var service = { //Define here;
        locationDone: 0,
        position: null,
        option: null
    }

    var getLocation = function() {
        service.locationDone = 0;

        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(function (pos) {
              $timeout(function(){
                service.locationDone = 1;
                service.position = pos;
              });
            }, function () {
              $timeout(function(){
                service.locationDone = 2;
              });
            });
        } else {
            service.locationDone = 3;
        }
    };

    getLocation();

    return service; //return it
 }]);

With qpromise implementation:

.factory('dataService', ['$q', function($q) {


    return {
      getLocation:getLocation
    };

   function getLocation() {

        if (navigator.geolocation) {
          var defer = $q.defer();
            navigator.geolocation.getCurrentPosition(function (pos) {
                defer.resolve({locationDone : 1,position : pos})
            }, function () {
               defer.resolve({ locationDone : 2});
            });
          return defer.promise;
        }

        return $q.when({locationDone : 3});

    };


 }]);

And in your controller:

    $scope.data = {};
    dataService.getLocation().then(function(result){
      $scope.data = result;
    });

Demo

angular.module('app', []).controller('HomeController', ['$scope', '$location', 'dataService', function ($scope, $location, dataService) {
        $scope.data = {};
        dataService.getLocation().then(function(result){
          $scope.data = result;
        })
        
        console.log('Home ctrl', $scope.data.locationDone);

        $scope.fn = {};
        $scope.fn.showOne = function () {
            $scope.data.option = 3;
            $location.path('/map');
        };

        $scope.fn.showAll = function () {
            $scope.data.option = 99;
            $location.path('/map');
        };
}]).factory('dataService', ['$q', function($q) {
   
    
    return {
      getLocation:getLocation
    };

   function getLocation() {
          
        if (navigator.geolocation) {
          var defer = $q.defer();
            navigator.geolocation.getCurrentPosition(function (pos) {
                defer.resolve({locationDone : 1,position : pos})
            }, function () {
               defer.resolve({ locationDone : 2});
            });
          return defer.promise;
        }
            
        return $q.when({locationDone : 3});
        
    };

   
 }]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="HomeController">
  <div layout="column" layout-align="start center">
    <div layout="column" layout-margin layout-padding>
        <div flex layout layout-margin layout-padding>
            <md-whiteframe flex class="md-whiteframe-z1" layout layout-align="center center" ng-show="data.locationDone==0">
                <span flex>Awaiting location information.</span>
            </md-whiteframe>
            <md-whiteframe flex class="md-whiteframe-z1" layout layout-align="center center" ng-show="data.locationDone==2"><span flex>Error in getting location.</span>
            </md-whiteframe>
            <md-whiteframe flex class="md-whiteframe-z1" layout layout-align="center center" ng-show="data.locationDone==3"><span flex>The browser does not support location.</span>
            </md-whiteframe>
        </div>
        <md-button flex ng-show="data.locationDone==1" class="md-accent md-default-theme md-raised" ng-click="fn.showOne()">Find Nearest Three Stores</md-button>
        <div flex></div>
        <md-button ng-show="data.locationDone==1" flex class="md-accent md-default-theme md-raised" ng-click="fn.showAll()">Find All Stores</md-button>

    </div>
</div>
</div>

share|improve this answer
    
I made those changes and its still not working. The plunker link in my post is updated. – Srik Jan 21 at 19:18
    
I cannot really access plunker. – PSL Jan 21 at 19:34
    
I have updated the code above. – Srik Jan 21 at 19:37
    
@Srik navigator.geolocation.getCurrentPosition is async right and non angular? you may inject $timeout and wrap data.locationDone = 1; data.position = pos; inside $timeout – PSL Jan 21 at 19:51
    
Yes. It's async and comes along with the browser. w3schools.com/HTML/html5_geolocation.asp – Srik Jan 21 at 19:54

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.