$scope inaccessible in nested function

2019-08-31 02:19发布

问题:

I'm trying to build a service for geolocation in angularjs, however I wanted to give it a try in my controller first then move it out. Right now I'm not able to access the $scope variable when I get my position.coords.latitude/longitude values.

Can someone explain to me why it's not accessible? I don't have in depth knowledge in javascript, but is it because parent variables aren't accessible for some reason? and What would be a good way to work around this kind of limitation?

I'm tagging this javascript too since I'm not sure if this is a language design characteristic or something I'm just missing because I'm blind.

I do see the lat/long print to the console so I know I'm getting valid data.

//geolocation.js

angular.module('myapp', [])
    .controller('MyController', ['$scope',
        function($scope) {
            if ("geolocation" in navigator) {
                var watchID = navigator.geolocation.watchPosition(function(position) {
                    $scope.latitude = position.coords.latitude;
                    $scope.longitude = position.coords.longitude;
                    console.log($scope.latitude);
                    console.log($scope.longitude);
                }, function() {}, {
                    enableHighAccuracy: true,
                    maximumAge: 30000,
                    timeout: 27000
                });
            } else {
                /* geolocation IS NOT available */
            }
        }
    ]);

and

//index.html
<!doctype html>
<html ng-app="myapp">

<head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.js">
    </script>
    <script src="geolocation.js">
    </script>
</head>

<body ng-controller="MyController">
    Hello
    <div>
        <p>{{latitude}}</p>
        <p>{{longitude}}</p>
    </div>
</body>

</html>

Ok so I added

$scope.$apply($scope.latitude);

Right after the console.log's but still in the function.

Both latitude and longitude update. I tried just a vanilla $scope.$apply(); but that didn't do anything. I guess it's working the first way so I'll stick with that.

I have updated to $scope.coords = position.coords and now $scope.$apply($scope.coords);

in the html I'm doing {{coords.latitude}} and longitude etc, and it works fine.

For anyone interested. Also I'm planning to move to a service not sure how that'll play out.

回答1:

Well, you're seeing the values print out to the console so you know that you are in fact accessing the $scope variable. You just don't happen to see the changes in the HTML, correct? You're not seeing these changes because angular isn't aware that the scope is being changed. The short answer is, you need to wrap changes to the scope with $apply to let angular know they're being changed.

Here's a related answer you may find useful: How do I use $scope.$watch and $scope.$apply in AngularJS?



回答2:

Ok, first guess is you are hitting the infamous/nasty gotcha with prototype chains of angular scopes when setting scalar values. Many folks have been surprised by this and it is well documented. Try refactoring your code to make $scope.coords an Object (essential to the fix) with nested sub-properties $scope.coords.latitude and $scope.coords.longitude. What is probably happening is your child scope is shadowing the scalar latitude attribute so the parent scope can't access/see it.