Reputation: 83
I'm trying to get the user's current coordinates from my controller into my template, and from there into my directive. The first half of this works, but I can't get the second half working for the life of me. In the directive, I've also tried '=' and lat=currentLat, as well as scope/$scope. What's going on?
Controller:
var posOptions = { timeout: 5000, enableHighAccuracy: true, maximumAge: 5000 };
$cordovaGeolocation.getCurrentPosition(posOptions)
.then(function (location) {
$scope.currentLat = location.coords.latitude;
$scope.currentLong = location.coords.longitude;
console.log($scope.currentLat, $scope.currentLong);
});
Template:
<div id="map" zoom="16" bgeo lat="{{currentLat}}" lng="{{currentLong}}">
Directive:
.directive('bgeo', ['$cordovaGeolocation', '$cordovaBackgroundGeolocation', '$http', function ($cordovaGeolocation, $cordovaBackgroundGeolocation, $http) {
return {
scope: {
lat: '@',
lng: '@'
},
link: function (scope) {
console.log("directive: ", scope.lat, scope.lng);
}
}}])
Full code of test app can be found here: https://github.com/sahiltalwar88/binding-geolocation-issue
Upvotes: 4
Views: 105
Reputation: 83
This is what ended up working:
Template:
<ion-scroll zooming="true" direction="xy" style="width:90%">
<div ng-if="loaded" bgeo lat="currentLat" lng="currentLong">
<div id="map" style="width: 600px; height: 500px;"></div>
</div>
</ion-scroll>
Controller:
angular.module('testApp.controllers', ['ionic', 'ngCordova.plugins.geolocation', 'ngCordova.plugins.backgroundGeolocation'])
.controller('MapCtrl', ['$scope', '$ionicPopup', '$cordovaGeolocation', '$cordovaBackgroundGeolocation', '$timeout', '$http',
function ($scope, $ionicPopup, $cordovaGeolocation, $cordovaBackgroundGeolocation, $timeout, $http) {
$scope.loaded = false;
var posOptions = { timeout: 5000, enableHighAccuracy: true, maximumAge: 5000 };
$cordovaGeolocation.getCurrentPosition(posOptions)
.then(function (location) {
$scope.currentLat = location.coords.latitude;
$scope.currentLong = location.coords.longitude;
$scope.loaded = true;
});
}])
Directive:
.directive('bgeo', ['$cordovaGeolocation', '$cordovaBackgroundGeolocation', '$http',
function ($cordovaGeolocation, $cordovaBackgroundGeolocation, $http) {
return {
scope: {
lat: '=',
lng: '='
},
link: function (scope) {
console.log("directive: ", scope.lat, scope.lng);
myLatLng = new google.maps.LatLng(scope.lat, scope.lng);
mapOptions = {
zoom: 16,
center: myLatLng
};
map = new google.maps.Map(document.getElementById('map'), mapOptions);
marker = new google.maps.Marker({
position: myLatLng,
map: map,
draggable: false,
icon: 'small-orange-pin.png'
});
}
}
}])
Upvotes: 0
Reputation: 191799
When you use @
in the template it is a one time string binding. Since you are waiting on the asynchronous .getCurrentPosition
to complete the values are not updated until after they are already linked in the directive. The linking function is only called when the directive is compiled.
Instead you will want to defer the directive's loading until the scope values are loaded. You can prevent compiling of the directive by leaving it out of the DOM via ng-if
:
<div bgeo ng-if=loaded lat={{currentLat}} lng={{currentLng}}>
The directive won't be compiled or linked until loaded
is set to true which you can do in the .getCurrentPosition
callback:
http://plnkr.co/edit/eYWXCA5UE6dUu9RM5mdj?p=preview
You can also use data binding with =
in the isolate scope definition. However, note that the directive is still only linked after it is initially compiled so the console.log
will be called too early. It would make more sense to do this if you were using the bound values in a template or controller -- particularly if you will alter them and have that propogate back to the parent controller.
http://plnkr.co/edit/ZXwDr3Tq3w046G7FM4mK?p=preview
Upvotes: 4