AngularJS Service中$ scope对象的更新不会更新View

时间:2015-06-22 12:52:43

标签: javascript angularjs google-maps cordova ionic-framework

我正在尝试在Angular / IonicFramework中实现Google地图。我正在使用指令,服务和控制器。我在$scope中有一个地图,标记和地理位置对象。视图中的地图对象和标记对象将从服务更新,但地理位置对象不会更新。

模板/视图:

<div class="item item-input item-stacked-label item-icon-right">
  <div>
    Location
    <a ng-click="centerOnMe()">
      <i class="icon ion-android-locate" style="font-size:24px"></i>
    </a>
  </div>
  <textarea style="margin-top: 0px; margin-bottom: 0px; height: 45px;" placeholder="Location not found." disabled>{{geoloc.addr}}</textarea>
</div>
<div class="item item-input">
  <div class="input-label">Map</div>
</div>
<div class="item item-input" style="height:15em;">
  <ion-content scroll="false">
    <map on-create="mapCreated(map, geoloc, marker)"></map>
  </ion-content>
</div>

地图指令:

angular.module('starter.directives', [])

.directive('map', function(MapService) {
  return {
    restrict: 'E',
    scope: {
      onCreate: '&'
    },
    link: function ($scope, $element, $attr) {
      function initialize() {
        var mapOptions = {
          center: new google.maps.LatLng(43.07493, -89.381388),
          zoom: 16,
          mapTypeId: google.maps.MapTypeId.ROADMAP
        };

        var map = new google.maps.Map($element[0], mapOptions);
        var geoloc = {
          lat: null, lng: null, str: null, brgy: null,
          muni: null, reg: null, addr: null
        };
        var marker = new google.maps.Marker({
          map: map
        });

        $scope.onCreate(
          {
            map: map,         //link map to map in controller
            geoloc: geoloc,   //link geoloc to geoloc in controller
            marker: marker    //link marker to marker in controller
          });

        // Stop the side bar from dragging when mousedown/tapdown on the map
        google.maps.event.addDomListener($element[0], 'mousedown', function (e) {
          e.preventDefault();
          return false;
        });
      }

      if (document.readyState === "complete") {
        initialize();
      } else {
        google.maps.event.addDomListener(window, 'load', initialize);
      }
    }
  }
});

地图控制器:

angular.module('starter.controllers', [])

.controller('MapCtrl', function($scope, $ionicLoading, MapService) {
  $scope.mapCreated = function(map, geoloc, marker) {
    $scope.map = map;       //sets the map from the directive to the $scope
    $scope.geoloc = geoloc; //sets the geoloc from the directive to the $scope
    $scope.marker = marker; //sets the marker from the directive to the $scope
  };

  $scope.centerOnMe = function () {
    console.log('Centering..');
    if (!$scope.map && !$scope.marker && !$scope.geoloc) {
      return;
    }
    $scope.loading = $ionicLoading.show({
      template: 'Getting current location...',
      noBackdrop: true
    });

    $scope.geoloc = MapService.getCurrentLocation($ionicLoading, $scope.map, $scope.geoloc, $scope.marker);
    // ^^^ This doesn't seem to work. $scope.geoloc doesn't get updated immediately, while $scope.map and $scope.marker gets updated immediately. Has to be invoked twice for $scope.geoloc to be updated.
  }
});

地图服务:

angular.module('starter.services', [])

.factory('MapService', function() {
  return {
    getCurrentLocation: function($ionicLoading, map, geoloc, marker) {
      navigator.geolocation.getCurrentPosition(function (pos) { //callback if get location succeeds

          geoloc.lat = pos.coords.latitude;
          geoloc.lng = pos.coords.longitude;

          var latlngpos = new google.maps.LatLng(pos.coords.latitude, pos.coords.longitude);
          var geocoder = new google.maps.Geocoder();

          geocoder.geocode({'latLng': latlngpos}, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
              if (results[0]) {
                map.setZoom(16);
                marker.setOptions({
                    position: latlngpos,
                    map: map
                });

                geoloc.str = results[0].address_components[0].short_name; //type:route
                geoloc.brgy = results[0].address_components[1].short_name; //type:neighborhood
                geoloc.muni = results[0].address_components[2].short_name; //type:locatlity
                geoloc.reg = results[0].address_components[3].short_name; //type:admnistrative_area_level_1

                geoloc.addr = results[0].formatted_address;

              } else {
                console.log('No results found');
              }
            } else {
              console.log('Geocoder failed due to: ' + status);
            }
          });

          map.setCenter(latlngpos);
          $ionicLoading.hide();
      }, function (error) { //callback if get location fails
        alert('Unable to get location: ' + error.message);
      });

      return geoloc;
    }
  } 
})
;

我的实施基于此:

http://www.jeffvandalsum.com/integrating-google-maps-api-with-angular/

我已按照此处建议的解决方案,但$scope.geoloc对象仍未更新:

Angular directive scope between google maps and a controller

Phonegap not firing GoogleMaps v3 domListener function inside Angularjs directive

2 个答案:

答案 0 :(得分:0)

尝试包装

$scope.geoloc = MapService.getCurrentLocation($ionicLoading,$scope.map, $scope.geoloc, $scope.marker);

$timeout

angular.module('starter.controllers', [])

.controller('MapCtrl', function($scope,$timeout, $ionicLoading, MapService) {
    $scope.mapCreated = function(map, geoloc, marker) {
    $scope.map = map;       //sets the map from the directive to the $scope
    $scope.geoloc = geoloc; //sets the geoloc from the directive to the $scope
    $scope.marker = marker; //sets the marker from the directive to the $scope
  };

  $scope.centerOnMe = function () {
     console.log('Centering..');
     if (!$scope.map && !$scope.marker && !$scope.geoloc) {
       return;
     }
     $scope.loading = $ionicLoading.show({
       template: 'Getting current location...',
       noBackdrop: true
     });
    $timeout(function(){
         $scope.geoloc = MapService.getCurrentLocation($ionicLoading, $scope.map, $scope.geoloc, $scope.marker);
         // ^^^ This doesn't seem to work. $scope.geoloc doesn't get updated immediately, while $scope.map and $scope.marker gets updated immediately. Has to be invoked twice for $scope.geoloc to be updated.
    });
  }
});

旁注:这不一定是最佳方式,但它应该会触发$scope.geoloc来正确更新。

我还建议Gajotres's tutorial

希望这有用!

答案 1 :(得分:0)

我刚刚重写了我的指令,服务和控制器,现在它正在工作。现在数据包含在服务中。然后我将服务注入指令和控制器。

地图服务:

.factory('MapService', function() {
  var service = {};
  service.map = null;
  service.marker = null;
  service.geoloc = {
      lat: 0.0,
      lng: 0.0,
      str: "",
      brgy: "",
      muni: "",
      reg: "",
      addr: ""  
  };

  service.init = function(map, marker) {
    this.map = map;
    this.marker = marker;
  }

  service.getCurrLoc = function($ionicLoading) {

    navigator.geolocation.getCurrentPosition(function (pos) { //callback if get location succeeds
      service.geoloc.lat = pos.coords.latitude;
      service.geoloc.lng = pos.coords.longitude;

      var latlngpos = new google.maps.LatLng(pos.coords.latitude, pos.coords.longitude);
      var geocoder = new google.maps.Geocoder();

      service.marker = new google.maps.Marker({
        position: latlngpos,
        map: service.map
      });

      //get location
      geocoder.geocode({'latLng': latlngpos}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          if (results[0]) {
            service.map.setZoom(16);
            service.marker.setOptions({
                position: latlngpos,
                map: service.map
            });

            service.geoloc.str = results[0].address_components[0].short_name; //type:route
            service.geoloc.brgy = results[0].address_components[1].short_name; //type:neighborhood
            service.geoloc.muni = results[0].address_components[2].short_name; //type:locatlity
            service.geoloc.reg = results[0].address_components[3].short_name; //type:admnistrative_area_leveservice
            service.geoloc.addr = results[0].formatted_address;


            service.map.setCenter(latlngpos);
            $ionicLoading.hide(); //hide loading prompt
          } else {
            console.log('No results found');
          }
        } else {
          console.log('Geocoder failed due to: ' + status);
        }
      });                     
    },
    function (error) { //callback if get location fails
    },
    { enableHighAccuracy: true }); //geolocation options
  }
  return service;
})

地图指令:

.directive('map', ["MapService", function(MapService) {
  return {
    restrict: 'E',
    scope: {
      onCreate: '&'
    },
    link: function ($scope, $element, $attr) {
      function initialize() {
        var mapOptions = {
          //set to Philippines
          center: new google.maps.LatLng(14.6839606, 121.0622039),
          zoom: 16,
          mapTypeId: google.maps.MapTypeId.ROADMAP
        };

        MapService.map = new google.maps.Map($element[0], mapOptions);

        MapService.marker = new google.maps.Marker({
          map: MapService.map
        });

        $scope.onCreate(
          {
            map: MapService.map,         //link map to map in controller
            marker: MapService.marker,   //link marker to marker in controller
            geoloc: MapService.geoloc    //link geoloc to geoloc in controller
          }
        );

        // Stop the side bar from dragging when mousedown/tapdown on the map
        google.maps.event.addDomListener($element[0], 'mousedown', function (e) {
          e.preventDefault();
          return false;
        });
      }

      if (document.readyState === "complete") {
        initialize();
      } else {
        google.maps.event.addDomListener(window, 'load', initialize);
      }
    }
  }
}])

地图控制器:

.controller('MapCtrl', ["$scope", "$ionicLoading", "MapService", function($scope, $ionicLoading, MapService) {
  $scope.mapCreated = function(map, marker, geoloc) {
    $scope.map = map;       //sets the map from the directive to the $scope
    $scope.marker = marker; //sets the marker from the directive to the $scope
    $scope.geoloc = geoloc; //sets the geoloc from the directive to the $scope
    console.log('$scope.geoloc in $scope.mapCreated', $scope.geoloc);


    $scope.centerOnMe();
  };

  $scope.centerOnMe = function () {
    console.log("Centering");
    if (!$scope.geoloc && !$scope.map && !$scope.marker) {
      console.log($scope.map);
      console.log($scope.marker);
      console.log($scope.geoloc);

      return;
    }
    $scope.loading = $ionicLoading.show({
      template: 'Getting current location...',
      noBackdrop: true
    });

    MapService.getCurrLoc($ionicLoading);

  }
}])