Reputation: 27972
I have a custom directive which is using two way binding to my controller (using '=').
<my-streetview
latitude="quickView.streetView.latitude"
longitude="quickView.streetView.longitude"
ng-if="quickView.activeTab === 'street'"
></my-streetview>
I'm using ng-if because I don't wnt the google map/streetview being loaded until the tab which it is in is opened. The trouble is that the first time it shows everything works but the second time the ng-if is true (when you click a different tab then come back to the tab) it seems to set the long and lat to undefined.
I know the following:
A) if I change ng-hide to ng-show it just works. The google map is not being destroyed and created every time you leave nad return to the tab so this makes sense. It's something to do with ng-if destroying something when it's false I think.
B) The lat and long values DO actually get changed in the parent controller because I put a $watch and a console.log() in there to test it. Basically when the ng-if is set to true the first time it creates the streetview fine, the second and subsequent times it either cannot read the values from the parent controller, or is actually setting them to undefinied.
C) Nothing else is different between the first time the ng-if is shown and subsequent times. There is no other code I can think of coming into play.
Any ideas would really be appreciated.
Here is my full code for my street view directive.
angular.module('my.directives')
.constant('myStreetviewDefaults', {
latitude: 51.816102,
longitude: -0.811619
})
.directive('myStreetview', function ($timeout, myStreetviewDefaults) {
return {
restrict: 'EA',
scope: {
latitude: '=',
longitude: '='
},
link: function ($scope, $element, $attrs) {
$scope.latitude = angular.isDefined($scope.latitude) ? $scope.$eval($scope.latitude) : myStreetviewDefaults.latitude;
$scope.longitude = angular.isDefined($scope.longitude) ? $scope.$eval($scope.longitude) : myStreetviewDefaults.longitude;
// Create the panorama
var mapEl = $('<my-streetview-map></my-streetview-map>');
mapEl.addClass('my-streetview-map-container');
$element.append(mapEl);
var panorama = new google.maps.StreetViewPanorama(mapEl[0], {
position: {
lat: $scope.latitude,
lng: $scope.longitude
},
pov: {
heading: 34,
pitch: 10
}
});
// Watch latitude and longitude to reset the center
$scope.$watchGroup(['latitude','longitude'], function (newValues, oldValues, $scope) {
panorama.setPosition({
lat: $scope.latitude,
lng: $scope.longitude
});
});
// Hack to get street view drawing properly on second load
// https://github.com/allenhwkim/angularjs-google-maps/issues/59
$timeout(function(){
google.maps.event.trigger(panorama,'resize');
}, 100);
}
};
});
This is the controller code for the Angular UI modal that the streetview sits inside.
angular.module('app')
.controller('QuickViewCtrl', function ($rootScope, $scope, $log, $http, appConfig, $u, $modalInstance, modalSettings) {
'use strict';
var master = $scope.master;
var quickView = this;
$log.info('Quick View Opened', modalSettings);
this.close = function(){
$modalInstance.close();
}
///////////////////////////////////////////////////////////////
// Initialize Page
///////////////////////////////////////////////////////////////
var init = function () {
// Set the initial tab
quickView.activeTab = modalSettings.initialPanel;
// Set up the street view
quickView.streetView = {
latitude: modalSettings.property.latitude,
longitude: modalSettings.property.longitude
};
$scope.$watch('quickView.streetView', function(newValues, oldValues){
console.log("Test watching from controller", newValues);
}, true);
};
init();
});
And this is the template for the modal window....
<div class="quickView modal-inner modal--has-header modal--has-footer">
<!-- Header -->
<div class="modal-header">
<!-- Header removed for brevity -->
</div>
<div class="modal-main">
<!-- Tabs -->
<my-tabset
my-tabset-active-tab="quickView.activeTab"
>
<div my-tabset-tabs my-tabset-tabs--equal4>
<a href="#" my-tabset-tab my-tabset-tab-name="overview" is-active="true">
<div my-tabset-tab-text>Overview</div>
</a>
<a href="#" my-tabset-tab my-tabset-tab-name="gallery">
<div my-tabset-tab-text>Gallery</div>
</a>
<a href="#" my-tabset-tab my-tabset-tab-name="map">
<div my-tabset-tab-text>Map</div>
</a>
<a href="#" my-tabset-tab my-tabset-tab-name="street">
<div my-tabset-tab-text>Street View</div>
</a>
</div>
<div my-tabset-panels>
<!-- Overview Panel -->
<div my-tabset-panel my-tabset-tab-name="overview" is-active="true">
<div ng-if="quickView.activeTab === 'overview'">
<!-- Overview removed for brevity -->
</div>
</div>
<!-- Gallery Panel -->
<div my-tabset-panel my-tabset-tab-name="gallery">
<div ng-if="quickView.activeTab === 'gallery'">
<!-- Gallery removed for brevity -->
</div>
</div>
<!-- Map Panel -->
<div my-tabset-panel my-tabset-tab-name="map">
<ui-gmap-google-map
center='quickView.map.center'
zoom='quickView.map.zoom'
options="quickView.map.options"
control="quickView.mapControl"
ng-if="quickView.activeTab === 'map'"
>
<ui-gmap-marker
idKey="'quickViewMapMarker'"
coords='quickView.map.markerPosition'
>
</ui-gmap-marker>
</ui-gmap-google-map>
</div>
<!-- Street View Panel -->
<div my-tabset-panel my-tabset-tab-name="street">
<my-streetview
latitude="quickView.streetView.latitude"
longitude="quickView.streetView.longitude"
ng-if="quickView.activeTab === 'street'"
></my-streetview>
</div>
</div>
</my-tabset>
</div>
<!-- Footer -->
<div class="modal-footer">
Footer
</div>
</div>
Upvotes: 1
Views: 764
Reputation: 49590
The offending lines are:
$scope.latitude = angular.isDefined($scope.latitude) ? $scope.$eval($scope.latitude) : myStreetviewDefaults.latitude;
$scope.longitude = angular.isDefined($scope.longitude) ? $scope.$eval($scope.longitude) : myStreetviewDefaults.longitude;
It's not clear why you are using $scope.$eval($scope.latitude)
, but it might stem from a misunderstanding of what $scope.$eval
does.
$scope.$eval
takes an expression, for example: "quickView.streetView.latitude"
, and evaluates it against the $scope
upon which the $eval
is called.
You called it with $scope.latitude
as a parameter, which means the the evaluated expression was something like 35.344542
- clearly not something defined on the scope - and so you got undefined
.
Perhaps you meant to use $attrs.latitude
- that would have given you the "quickView.streetView.latitude"
expression, but you would have needed to call it on the parent scope, since your directive uses an isolate scope that is not aware of what quickView
(etc...) is:
$scope.$parent.$eval($attrs.latitude)
But more so, you don't even need this $eval
at all, since $scope.latitude
has already acquired the evaluated value automatically via two-way binding. The following would have worked just as well:
$scope.latitude = angular.isDefined($scope.latitude) ? $scope.latitude : myStreetviewDefaults.latitude;
Upvotes: 2