I am having trouble understanding the hierarchy of scopes in a nested scenario.
I am using UI router. My home template contains the;
ui-view and a directive 'gmap-locator'.
ui-view loads the following template/controller as default 'LocationFilter.Html/locationfilter', within which I am nesting a directive A
within which I am nesting a directive B
within which I am nesting a directive C
... From C I am calling a function 'funcXYZ()' on an ng-click.
I have my 'funcXYZ()' declared at home controller and 'gmap-locator' directive's controller.
I expected the 'funcXYZ()' in the home controller to be invoked but to my surprise 'funcXYZ()' in the 'gmap-locator's controller is getting called until I comment that out(then it propogates to the home controller's function).
It doesn't fall in the right hierarchy of propogation, atleast with my understanding.. any thoughts?
I am using UIRouter and my routing looks like this:
app.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/searchModeList');
$stateProvider
.state('home', {
url: '/',
templateUrl: '/templates/Index.html',
controller: 'homeController'
})
.state('home.searchModeList', {
url: 'searchModeList',
templateUrl: '/templates/SearchModeList.html',
controller: 'searchModeListController'
})
.state('home.countyList', {
url: 'countyList',
templateUrl: '/templates/countyList.html',
controller: 'countyListController'
})
.state('home.locationFilters', {
url: 'locationFilters',
templateUrl: '/templates/locationFilters.html',
controller: 'locationFiltersController'
})
});
Gmap_locator directive code.. Sorry Its long/crude and has to be refactored.. but just for the reference purpose..
app.directive('gmapLocator', function ($timeout, $modal, AppModesService,$rootScope) {
var link = function (scope, element, attrs) {
scope.mapParameters = {
mapContainerID: 'mappe',
initialSettings: {
zoom: 10,
Lat: 39.1686269,
Lng: -76.7757216
},
markerIcon: '../Content/Images/roundblue.png',
markerSelectedIcon: '../Content/Images/orangeround.png',
markerZoomIcon: '../Content/Images/roundgreen.png',
crashIcon: '../Content/Images/redcrossconfirm.png'
}
var map, mapOptions, bounds, markers = [], previousSelectedMarker, previousCrashLocation, mapClickListener,
prevLabel, line, mapZoomMode = 'init', lineCoordinates;
var lat = scope.mapParameters.initialSettings.Lat;
var lng = scope.mapParameters.initialSettings.Lng;
mapOptions = {
mapTypeId : google.maps.MapTypeId.ROADMAP,
center: new google.maps.LatLng(lat, lng),
zoom: scope.mapParameters.initialSettings.zoom
};
function initMap() {
map = new google.maps.Map(document.getElementById(scope.mapParameters.mapContainerID), mapOptions);
}
$timeout(function () { initMap() },100);
var mapFullZoom = function (map,position) {
(new google.maps.MaxZoomService()).getMaxZoomAtLatLng(position, function (response) {
var zoom = 19;
if (response.status == google.maps.MaxZoomStatus.OK) {
zoom = response.zoom;
}
map.setZoom(zoom);
map.setMapTypeId(google.maps.MapTypeId.HYBRID);
});
}
var setMarker = function (position,title,id) {
var marker,
markerClickTimer, currentZoom,currentZoom;
scope.zoomLevel = 'normal';
scope.mapZooms = {};
markerOptions = {
position: position,
map: map,
title: title,
id: id,
icon: scope.mapParameters.markerIcon
};
var markerClickZoomIncrement = 0;
var referencePointsCount = scope.referencePoints.length;
if (referencePointsCount < 15) markerClickZoomIncrement = 1;
else if((referencePointsCount >15) && (referencePointsCount < 50)) markerClickZoomIncrement = 2;
else if(referencePointsCount>50) markerClickZoomIncrement =4;
marker = new google.maps.Marker(markerOptions);
google.maps.event.addListener(marker, 'click', function () {
var element = this;
//scope.searchBy.keyword = null; // To reset the Reference Point filter search textbox
//scope.pointNotFound = false; // To reset the PointNotFound button selection
scope.referencePointChanged();// call parent scope function
scope.referencePointSelectMode = 'map';
AppModesService.setResult('Lat',marker.position.lat());
AppModesService.setResult('Long', marker.position.lng());
map.panTo(marker.position);
if ((previousSelectedMarker) && (previousSelectedMarker.id != marker.id)) {
previousSelectedMarker.setIcon(scope.mapParameters.markerIcon);
mapZoomMode = 'init';
}
if ((mapZoomMode == 'init') || (previousSelectedMarker.id != marker.id)) {
mapZoomMode = 'selected';
scope.selectIntersectionId = element.id;
AppModesService.setSelectedReferencePoint(element.id);
AppModesService.setResult('ReferenceRoadName', element.title);
clearMapClickListener();
clearCrashMarker();
if (!scope.mapZooms.initZoomLevel) {
currentZoom = map.getZoom();
scope.mapZooms.initZoomLevel = currentZoom;
scope.mapZooms.initCenter = map.getCenter();
}
if (map.getMapTypeId() !== google.maps.MapTypeId.ROADMAP) {
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setZoom(scope.mapZooms.initZoomLevel + markerClickZoomIncrement);
}
if (scope.zoomLevel == 'normal') {
map.setZoom(currentZoom + markerClickZoomIncrement);
scope.zoomLevel = 'lightZoom';
}
element.setIcon(scope.mapParameters.markerSelectedIcon);
previousSelectedMarker = element;
}
else if(previousSelectedMarker.id == marker.id){
if (mapZoomMode == 'selected') {
mapZoomMode = 'confirmed';
map.setZoom(30);
map.setMapTypeId(google.maps.MapTypeId.HYBRID);
element.setIcon(scope.mapParameters.markerZoomIcon);
setMapClickEvent();
}
}
$timeout(function () {
scope.$apply();
});
});
bounds.extend(position);
markers.push(marker);
};
var setMapClickEvent = function () {
mapClickListener = google.maps.event.addListener(map, 'click', function (event) {
clearCrashMarker();
previousCrashLocation = new google.maps.Marker({
position: event.latLng,
map: map,
title: 'Crash Location',
icon: scope.mapParameters.crashIcon,
draggable: true
});
if ((!AppModesService.getMissingPointMode()) && (!AppModesService.getMissingPointMode())) {
prevLabel = document.getElementsByClassName('GLabel');
clearLabel();
label = new Label({
map: map
});
var offset = getOffset(event.latLng, previousSelectedMarker.position);
label.bindTo('position', previousCrashLocation, 'position');
label.set('text', offset);
lineCoordinates = getLineCoordinates(event);
clearLine();
drawLine(lineCoordinates);
AppModesService.setResult('Distance', offset);
}
setCrashLatLong(event.latLng);
crashMarkerClickListener = google.maps.event.addListener(previousCrashLocation, 'click', function (event) {
if ((!scope.pointNotFound) && (!scope.routeNotFound)) scope.openVerifyForm();
else scope.openMissingForm();
});
google.maps.event.addListener(previousCrashLocation, 'dragstart', function () {
if (!scope.pointNotFound) {
clearLine();
label.set('text', '_ _ _');
}
});
google.maps.event.addListener(previousCrashLocation, 'dragend', function (event) {
if (!scope.pointNotFound) {
var offset = getOffset(event.latLng, previousSelectedMarker.position);
label.set('text', offset);
lineCoordinates = getLineCoordinates(event);
clearLine();
drawLine(lineCoordinates);
AppModesService.setResult('Distance', offset);
}
setCrashLatLong(event.latLng);
});
// Set crash location data //
});
}
var clearMapClickListener = function () {
if (mapClickListener) {
google.maps.event.removeListener(mapClickListener);
}
}
var setCrashLatLong = function (latLng) {
AppModesService.setResult('CrashLat', latLng.lat());
AppModesService.setResult('CrashLong', latLng.lng());
}
var getLineCoordinates = function (event) {
return lineCoordinates = [
event.latLng,
previousSelectedMarker.position
];
}
var drawLine = function (lineCoordinates) {
var lineSymbol = {
path: 'M 0,-1 0,1',
strokeOpacity: .8,
scale: 6,
strokeWeight: 2,
strokeColor: 'red'
};
line = new google.maps.Polyline({
path: lineCoordinates,
strokeOpacity: 0,
icons: [{
icon: lineSymbol,
offset: '0',
repeat: '20px'
}],
map: map
});
}
var clearCrashMarker = function () {
if (previousCrashLocation) {
if (crashMarkerClickListener) {
google.maps.event.removeListener(crashMarkerClickListener);
}
previousCrashLocation.setMap(null);
}
clearLabel();
clearLine();
}
var createLabel = function () {
label = new Label({
map: map
});
}
var clearLabel = function () {
if ((prevLabel != null) && (prevLabel.length > 0)) {
prevLabel[0].parentNode.removeChild(prevLabel[0]);
}
}
var clearLine = function () {
if (line != null) {
line.setMap(null);
}
}
Number.prototype.toRad = function () { return this * Math.PI / 180; }
var getOffset = function (eventPosition, markerPosition) {
var result = -1;
var lat1 = eventPosition.lat(),
lon1 = eventPosition.lng(),
lat2 = markerPosition.lat(),
lon2 = markerPosition.lng();
//var R = 6371; // km
var R = 3961; // miles
var dLat = (lat2 - lat1).toRad();
var dLon = (lon2 - lon1).toRad();
var lat1 = lat1.toRad();
var lat2 = lat2.toRad();
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
if (d > 1) result = d.toFixed(2) + ' miles(s)';
else result = (d * 1760).toFixed(2) + ' yards(s)'
return result; // yards and miles
}
var getMarkerIndexById = function (id) {
var referencePointIndex = scope.referencePoints.map(function (element) {
return element.id
}).indexOf(id);
return referencePointIndex;
}
scope.setpointNotFound = function () {
AppModesService.setRouteNotFound(false);
AppModesService.setPointNotFound(true);
resetMarkers();
map.fitBounds(bounds);
}
var resetMarkers = function () {
mapZoomMode = 'init';
if (previousSelectedMarker) {
previousSelectedMarker.setIcon(scope.mapParameters.markerIcon);
}
clearCrashMarker();
clearLine();
clearLabel();
scope.selectIntersectionId = null;
previousSelectedMarker = null;
map.setMapTypeId(google.maps.MapTypeId.ROADMAP)
}
var removeMarkers = function () {
for (var markerItem in markers) {
markerItem.setMap(null);
}
}
var resetMap = function () {
resetMarkers();
initMap();
}
scope.openVerifyForm = function (size) {
var modalInstance = $modal.open({
animation: true,
templateUrl: '../templates/VerifyForm.html',
controller: verifyFormModalController,
size: 'lg'
});
}
scope.$watch(function () { return scope.selectIntersectionId }, function () {
if ((markers.length > 0) && (scope.referencePointSelectMode == "list") && (scope.selectIntersectionId != null)) {
var referencePointIndex = getMarkerIndexById(scope.selectIntersectionId);
new google.maps.event.trigger(markers[referencePointIndex], 'click');
}
});
scope.$watch(function () { return scope.referencePoints; }, function (newValue, oldValue) {
for (var count = 0; count < markers.length; count++) {
markers[count].setMap(null);
}
markers = [];
bounds = new google.maps.LatLngBounds();
initMap();
if(scope.referencePoints.length>0) {
angular.forEach(scope.referencePoints, function (value, key) {
var position = new google.maps.LatLng(value.latitude, value.longitude);
setMarker(position, value.title, value.id);
});
map.fitBounds(bounds);
}
}, true);
//Changing watch to broadcast listener
$rootScope.$on('pointNotFound.Changed', function (event,args) {
if (args.state == true) setMapClickEvent();
else clearMapClickListener();
scope.pointNotFound = args.state;
});
$rootScope.$on('routeNotFound.Changed', function (event, args) {
if (args.state == true) setMapClickEvent();
else clearMapClickListener();
scope.routeNotFound = args.state;
});
scope.$watch(function () { return scope.clearCrashMarker }, function (newValue, oldValue) {
if (newValue == true) {
clearCrashMarker();
}
});
// receive broadcasted events
scope.$on('clearCrashMarkerEvent', function (event, args) {
scope.clearCrashMarker = args.state;
});
}
return {
restrict: 'EA',
template: "<div id='mappe' style='height:693px;width:100%'></div>",//'../templates/gomap.html',
link: link,
scope: false,
replace:false
}
});