AngularJS - multiple Google maps not loading - angularjs

I'm developing an app (in my local machine) which displays various locations (an array that varies in size) in an accordion. I'm using the accordion and pagination directives from Angular UI Bootstrap with the Google Maps JS API-based directives from Angular Google Maps.
I have an issue where sometimes the map loads in the first item I clicked, then I click on another item in the accordion and the map doesn't load. Then a few minutes later, I'll refresh my browser and I click on the same item and the map will load. Then if I go to another page in the pagination, the maps aren't displayed there. As you can see in my code, I'm only calling the maps when I click on an item in the accordion, not when the items are loaded. I don't want a lot of maps to be loaded right away if the size of the locations array is large.
Here is a plunker demonstrating the problem, and here is a fiddle.
Here is some code from the example linked above which I think is important to the problem:
HTML body
<accordion close-others="oneAtATime">
<accordion-group is-open="status.open" ng-repeat="location in locations | startFrom: (currentPage-1)*5| limitTo: 5">
<accordion-heading >
<strong get-map-dir location-index={{$index}}>Location</strong> - {{location.address1}}
</accordion-heading>
<div id="branch_map" class="" ng-show="showMap ">
<ui-gmap-google-map center='location.mapInfo.map.center' zoom='location.mapInfo.map.zoom'>
<ui-gmap-marker coords="location.mapInfo.marker.coords" options="location.mapInfo.marker.options" idkey="location.mapInfo.marker.id">
<ui-gmap-window ng-cloak closeClick="closeClick()">
</ui-gmap-window>
</ui-gmap-marker>
</ui-gmap-google-map>
</div>
</accordion-group>
<pagination total-items="locations.length" items-per-page="itemsPerPage" ng-model="currentPage" ng-change="pageChanged()" ng-hide="locations.length < itemsPerPage"></pagination>
</accordion>
JS (partial)
.factory('anotherService', function() {
//getMap using google-maps directive from angularjs-ui
var getMap = function(locationObj, outerCallBack) {
console.info('get map');
var mapInfo = {};
var address = locationObj.address1;
var zoom = 16;
var geocoder = new google.maps.Geocoder();
console.log(locationObj);
geocoder.geocode({
"address": address, //required
"region": 'CA' //CA for canada
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
var location = results[0].geometry.location,
lat = location.lat(),
lng = location.lng();
mapInfo.map = {
center: {
latitude: lat,
longitude: lng
},
zoom: zoom
};
mapInfo.marker = {
id: 0,
coords: {
latitude: lat,
longitude: lng
},
options: {
title: address
}
};
outerCallBack({
success: true,
mapInfo: mapInfo
});
} else if (status === google.maps.GeocoderStatus.ZERO_RESULTS) {
console.info("Geocoder was sucessful but has no results");
console.info("address =" + address);
return;
} else if (status === google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
console.error("You are over your query limit");
console.info("address =" + address);
return;
} else if (status === google.maps.GeocoderStatus.REQUEST_DENIED) {
console.error("Your request has been denied by Geocoder");
return;
} else if (status === google.maps.GeocoderStatus.INVALID_REQUEST) {
console.error("Invalid Geocoder request");
return;
} else {
console.error("Google Maps in Ctrl failed");
console.error("address =" + address);
return;
}
});
};
var anotherService = {
getMap: getMap
};
return anotherService;
})
.directive('fetchMap', function($timeout, anotherService) {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
console.log("get map dir");
console.log(scope);
console.log(elem);
console.log(attrs);
elem.bind('click', function(event) {
// console.clear();
console.log("You clicked on me");
console.log(scope.locations[attrs.locationIndex].mapInfo);
if (angular.isUndefined(scope.locations[attrs.locationIndex].mapInfo)) {
anotherService.getMap(scope.locations[attrs.locationIndex], function(callBackfunc) {
console.info("Getting maps");
// scope.showPreloader = false;
scope.locations[attrs.locationIndex].mapInfo = callBackfunc.mapInfo;
$timeout(function() {
scope.showMap = true;
}, 2000);
});
}
});
}
};
})

Related

How To Update Page After Calling $http.put service in Directive Using AngularJS/Web API/Angular-ui-router

We are new to AngularJS but are working on an AngularJS/Web API application that updates a data model from an AngularJS Bootstrap popover/directive.
We've successfully updated the database from the directive/popover, however are having trouble figuring out how to refresh the data on the page with the updated data without reloading the page.
Main Page CSHTML:
<div ng-app="FFPA" ng-controller="myCtrl">
<div svg-floorplan="dataset"></div>
</div>
Popover HTML:
<div>
<div>
ID: {{ person.Id }}<br />
Name: {{ person.fullName }}<br />
Current Cube/Office: {{ person.seatId }}
<br />
Dept: {{ person.deptId }}
<br />
Job Desc: {{ person.jobDesc}}
<br />
Phone:{{ person.phone}}
<br />
<!--<input type="button" value="Click Me" ng-click="changeName()">-->
</div>
<div class="hiddenDiv" ng-hide="toggle">
<div class="form-group">
<label for="floor">Floor</label>
<input id="floor" ng-model="person.floor" type="text" ng-trim="true" class="form-control" />
</div>
<div class="form-group">
<label for="section">Section</label>
<input id="section" ng-model="person.section" ng-trim="true" type="text" class="form-control" />
</div>
<div class="form-group">
<label for="offCubeNum">offCubeNum</label>
<input id="offCubeNum" ng-model="person.offCubeNum" ng-trim="true" type="text" class="form-control" />
</div>
<div class="form-group">
<label for="cbCube">Cubicle?</label>
<input id="cbCube" ng-model="person.cbCube" type="checkbox" size="1" class="checkbox" />
</div>
</div>
<div ng-hide="buttonToggle">
<input type="button" value="Move" class="btn btn-success" ng-click="moveEmp()">
<input type="button" value="Term" class="btn btn-danger" ng-click="changeName()">
</div>
<div ng-hide="submitToggle">
<input type="button" value="Submit" class="btn btn-success" ng-click="submitMove()">
<input type="button" value="Cancel" class="btn btn-warning" ng-click="cancel()">
</div>
</div>
The main page initially gets data from a service in the angular controller:
var app = angular.module('FFPA', ['ngAnimate', 'ngSanitize', 'ui.bootstrap', 'ui.router']);
app.controller('myCtrl', function ($scope, dataService) {
$scope.test = 'test';
dataService.getData().then(function (data) {
//The reduce() method reduces the array to a single value.
$scope.dataset = data.reduce(function (obj, item) {
obj[item.seatId.trim()] = item;
item.fullName = item.fName + ' ' + item.lName;
item.deptId = item.deptId;
item.jobDesc = item.jobDesc;
item.phone = item.phone;
return obj;
}, {});
});
});
Get Data Service:
angular.module('FFPA').service('dataService', function ($http) {
this.getData = function () {
//web api call
return $http.get("api/Controller/GetData).then(
function (response) {
return response.data;
}, function () {
return { err: "could not get data" };
}
);
}
});
The Update Service is called from the Popover Directive.
Update Service:
angular.module('FFPA').service('updateService', function ($http) {
this.putData = function (oc) {
//web api call
return $http.put("api/Controller/PutUpdateData", oc).then(
function (response) {
return response.data;
}, function () {
return { err: "could not update data" };
}
);
}
});
Here is a snippet from our Popover directive where the update occurs and where we thought we could refresh the scope, and the data for the page:
updateService.putData(data).then(function (response) {
if (response == false)
alert("Move Failed!");
else {
alert("Move Succeeded.");
//$window.location.reload() causes a page reload..not desirable
//$window.location.reload();
$state.reload();
}
});
We tried a $state.reload(); in the popover directive just after updateService.putData(data), however this caused -> Error: Cannot transition to abstract state '[object Object]' error.
Here is the full Popover Directive:
angular.module('FFPA').directive('svgFloorplanPopover', ['$compile', 'updateService', 'vacancyService', 'addService', 'terminateService', '$window', '$state', function ($compile, updateService, vacancyService, addService, terminateService, $window, $state) {
return {
restrict: 'A',
scope: {
'person': '=svgFloorplanPopover',
//UPDATE 8-MAY-2017
onDataUpdate: '&'
},
link: function (scope, element, attrs) {
scope.moveToggle = true; //hide move toggle
scope.addToggle = true; //hide add toggle
scope.submitToggle = true; //hide submit toggle
scope.$watch("person", function () {
if (scope.person) {
if (scope.person.vacant == true) {
scope.addToggle = false; //show add button
scope.empInfoToggle = true; //hide emp info
}
else
scope.moveToggle = false; //show move
}
});
//add employee---------------------------------------------------------
scope.addEmp = function () {
scope.addToggle = scope.addToggle === false ? true : false;
scope.buttonToggle = true;
scope.submitToggle = false;
var data = {
deptId: scope.person.deptId,
divisionId: scope.person.divisionId,
empId: scope.person.empId,
floor: scope.person.floor,
fName: scope.person.fName,
lName: scope.person.lName,
jobDesc: scope.person.jobDesc,
officeCode: scope.person.officeCode,
phone: scope.person.phone,
section: scope.person.section,
seat: scope.person.seat,
seatId: scope.person.seatId,
seatTypeId: scope.person.seatTypeId,
vacant: scope.person.vacant
};
//call to update/move the employee
//updateService.putData(scope.person).then(function () {
addService.putData(data).then(function (response) {
if (response == false)
alert("Create Failed!");
else {
alert("Create Succeeded.");
//UPDATE 8-MAY-2017
$scope.onDataUpdate({ person: $scope.person, moreData: $scope.moreData });
//$window.location.reload();
//$route.reload();
//scope.toggle = false;
}
});
}
//cancel function---------------------------------------------------------
scope.cancel = function () {}
//Term emp---------------------------------------------------------
scope.termEmp = function () {
var data = {
seatId: scope.person.seatId,
floor: scope.person.floor
};
terminateService.putData(data).then(function (response) {
if (response == false)
alert("Term Failed!");
else {
alert("Term Succeeded.");
$window.location.reload();
//$route.reload();
//scope.toggle = false;
}
});
}
//move employee---------------------------------------------------------
scope.moveEmp = function () {
scope.toggle = scope.toggle === false ? true : false;
scope.buttonToggle = true;
scope.submitToggle = false;
if (scope.person && scope.person.fullName.indexOf('changed') === -1) {
//scope.person.fullName += ' move?';
}
//Json object to send to controller to check for vacancy
var data = {
floor: scope.person.floor,
section: scope.person.section,
seat: scope.person.offCubeNum
};
//can't send object via $http.get (?) stringigy json and cast to Office object in controller.
var json = JSON.stringify(data);
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//CHECK VACANCY service call
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vacancyService.getData(json)
.then(function (response) {
if (response == false)
alert("cube/office occupied");
else{
//+++++++++++++++++++++++++++++++++++++++++++
//UPDATE service call
//+++++++++++++++++++++++++++++++++++++++++++
//CONSTS
var CONSTFLOORPREFIX = "f";
var CONSTSEAT = "s";
var CONSTC = "c"
var floor = scope.person.floor;
var section = scope.person.section;
var offCube = scope.person.offCubeNum;
scope.person.oldSeatId = scope.person.seatId;
var newOfficeId = CONSTFLOORPREFIX + floor + CONSTSEAT; //f3s
//IF CUBE
if (scope.person.cbCube) {
var trimSection = section.trim();
newOfficeId += trimSection + CONSTC; //f3s313c
var trimOffCube = offCube.trim();
newOfficeId += trimOffCube;
}
else {
newOfficeId += 0 + CONSTC + section; //f3s0c
}
scope.person.seatId = newOfficeId;
//Json object to send to controller to check for vacancy
var data = {
Id: scope.person.Id,
seatId: scope.person.seatId,
oldSeatId: scope.person.oldSeatId,
empId: scope.person.empId,
lName: scope.person.lName,
fName: scope.person.fName,
refacName: scope.person.refacName,
deptId: scope.person.deptId,
divisionId: scope.person.divisionId,
jobDesc: scope.person.jobDesc,
seatTypeId: scope.person.seatTypeId,
officeCode: scope.person.officeCode,
phone: scope.person.phone,
floor: scope.person.floor,
section: scope.person.section,
seat: scope.person.seat,
vacant: scope.person.vacant
};
//call to update/move the employee
//updateService.putData(scope.person).then(function () {
updateService.putData(data).then(function (response) {
if (response == false)
alert("Move Failed!");
else {
alert("Move Succeeded.");
//$window.location.reload();
$state.reload();
//$route.reload();
//scope.toggle = false;
}
});
}//end else
});
}
if (element[0].querySelector('text') != null){
scope.htmlPopover = './HTML/popoverTemplate.html';
element[0].setAttribute('uib-popover-template', "htmlPopover");
element[0].setAttribute('popover-append-to-body', 'true');
element[0].setAttribute('popover-trigger', "'click'");
//element[0].setAttribute('popover-trigger', "'mouseenter'");
element[0].setAttribute('popover-placement', 'right');
element[0].removeAttribute('svg-floorplan-popover');
$compile(element)(scope);
}
}
}
}]);
UPDATED: 8-MAY-2017
Originally there is one additional data service and a directive that we left out of this post since it may be considered not essential information, however recently added since it may be needed.
SVG Load Directive:
angular.module('FFPA').directive('svgFloorplan', ['$compile', function ($compile) {
return {
restrict: 'A', //restrict attributes
templateUrl: './SVG/HQ3RD-FLOOR3v10.svg',
scope: {
'dataset': '=svgFloorplan'
},
link: {
pre: function (scope, element, attrs) {
//filter groups based on a cube/office id
var groups = element[0].querySelectorAll("g[id^='f3']");
//groups.style("pointer-events", "all");
scope.changeName = function (groupId) {
if (scope.dataset[groupId] && scope.dataset[groupId].lastName.indexOf('changed') === -1) {
scope.dataset[groupId].lastName += ' changed';
}
}
groups.forEach(function (group) {
var groupId = group.getAttribute('id');
if (groupId) {
//set vacancy colors on vacant cubes
scope.$watch("dataset", function () {
if (scope.dataset) {
if (typeof scope.dataset[groupId] !== "undefined") {
//vacant cubes and offices hover
if (scope.dataset[groupId].vacant == true) {
//seat type id 1 = cube
if (scope.dataset[groupId].seatTypeId == 1){
d3.select(group).select("rect").style("fill", "#99ff33").style("opacity", 0.4)
.style("pointer-events", "all")
.on('mouseover', function () {
d3.select(this).style('opacity', 0.9);
})
.on('mouseout', function () {
d3.select(this).style('opacity', 0.4);
})
}
//vacant office
else {
d3.select(group).select("path").style("stroke", "#ffffff").style("opacity", 1.0);
d3.select(group).select("path").style("fill", "#99ff33").style("opacity", 0.4)
.style("pointer-events", "all")
.on('mouseover', function () {
d3.select(this).style('opacity', 0.9);
})
.on('mouseout', function () {
d3.select(this).style('opacity', 0.4);
})
}
}
else { //Occupied
//seat type id 1 = cube
if (scope.dataset[groupId].seatTypeId == 1) {
d3.select(group).select("rect").style("fill", "#30445d").style("opacity", 0.0)
.style("pointer-events", "all")
.on('mouseover', function () {
d3.select(this).style('opacity', 1.0);
d3.select(group).select('text').style("fill", "#FFFFFF");
})
.on('mouseout', function () {
d3.select(this).style('opacity', 0.0);
d3.select(group).select('text').style("fill", "#000000");
})
//TODO: cubes have rects and on the north side of the building wall, paths.
d3.select(group).select("path").style("fill", "#30445d").style("opacity", 0.0)
.style("pointer-events", "all")
.on('mouseover', function () {
d3.select(this).style('opacity', 1.0);
d3.select(group).select('text').style("fill", "#FFFFFF");
})
.on('mouseout', function () {
d3.select(this).style('opacity', 0.0);
d3.select(group).select('text').style("fill", "#000000");
})
}
//occupied office
else {
//d3.select(group).select("path").style("stroke", "#ffffff").style("opacity", 0.8);
d3.select(group).select("path").style("fill", "#5A8CC9").style("opacity", 1.0)
.style("pointer-events", "all")
.on('mouseover', function () {
//alert("office");
d3.select(this).style("fill", "#2d4768").style('opacity', 1.0);
d3.select(group).selectAll('text').style("fill", "#FFFFFF");
})
.on('mouseout', function () {
d3.select(this).style("fill", "#5A8CC9").style('opacity', 1.0);
d3.select(group).selectAll('text').style("fill", "#000000");
})
}
}//end occupied else
}
}
});
//UPDATE 8-MAY-2017->Implementation Question
scope.onDataUpdateInController = function (person, moreData) { };
var datasetBinding = "dataset['" + groupId + "']";
group.setAttribute('svg-floorplan-popover', datasetBinding);
//UPDATE 8-MAY-2017
//on-data-update corresponds to onDataUpdate item on svgFloorplanPopover's scope.
group.setAttribute('on-data-update', onDataUpdateInController);
$compile(group)(scope);
}
});
}
}
}
}]);
Vacancy Service (check before update):
angular.module('FFPA').service('vacancyService', function ($http) {
...
}
The main question is:
How can we have our application refresh our page with the updated data without reloading the page?
We used to be able to do this in UpdatePanels in ASP.Net webforms back in the day. I think they were partial postbacks/AJAX calls..
EDITED 2-AUG-2017
+++++++++++++++++++++++++++++++++++
Even though the bounty was automatically awarded, we still don't have an answer to this question. Without any implementation context the answers given are not useful.
Can anyone expand on the answers given to give us an idea on how this problem can be solved?
Thanks
Just add your data on $scope object and use it in your view, whenever you update or modify the data just
eg: consider you have a function to get the data where you are making rest call to your db
$scope.getdata=function(){
$http.get(url).success(function(data)
{ $scope.data=data;
});
Whenever you modify your data just call this function in your case on click of close of directive/popup
To refresh your view (not bind the received data) use the answers for the following questions:
Using ngRoute Module
How to reload or re-render the entire page using AngularJS
Using ui-router Module
Reloading current state - refresh data
With that I would recommend you to assign the received data to your bounded $scope property.
I'll add a full example after you'll provide an updated plnkr :)
Please try the following steps:
1. Create a method in svgFloorplanPopover directive and call it by passing in the data
In your svgFloorplanPopover directive, add onDataUpdate item in the scope
declaration:
...
scope: {
'person': '=svgFloorplanPopover',
onDataUpdate: '&'
}
...
and where you are trying to reload state, instead of reloading the state or page, call the below code. This is to create an event system which is fired from within the directive to let the controller or parent directive know that data has changed and view can now be updated.
$scope.onDataUpdate({person: $scope.person, moreData: $scope.moreData});
2. Create a method in svgFloorplan to accept the passed data
Since you are using nested directive approach, you'll need to use the below code in svgFloorplan directive.
group.setAttribute('svg-floorplan-popover', datasetBinding);
group.setAttribute('on-data-update', onDataUpdateInController);
on-data-update corresponds to onDataUpdate item on svgFloorplanPopover's scope.
Declare onDataUpdateInController method on the scope of svgFloorplan directive.
scope.onDataUpdateInController = function(person, moreData) {};
The object properties that you pass from within the directive are laid out flat to the number of parameters.
If you need to pass this data further up to your controller where svgFloorplan is declared. Repeat the above two steps for svgFloorplan directive.
I hope this approach is clear. It is no different than what is explained in Angular Directives, section Creating a Directive that Wraps Other Elements and code where a close button is added. Here is the direct link to the code in plunkr.
Just a question: Are you going to use these directives separately from each other? If no, you may try to create one directive instead of making them two. This will reduce complexity.

ionic show-hide not working on android

This was suppose to be simple, I've used show/hide plenty of times...
2 hours later nothing... works on brower... it doesn't work on the mobile andriod device I'm testing on.
<li class="item" style="text-align:center" ng-if="showBlist==0">
No bouncr's available
</li>
<li class="item" ng-repeat="data in bouncrList" ng-if="showBlist==1">
<a class="item item-avatar" href="#">
<img src="{{avatar}}">
<h2>{{data.name}}</h2>
<p>{{data.venue}}, {{data.address}}</p>
</a>
</li>
$ionicPlatform.ready(function() {
$scope.initMap = function() {
$scope.positions = [];
$ionicLoading.show({
template: 'Loading...'
});
navigator.geolocation.getCurrentPosition(function(position) {
var pos = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
map = new google.maps.Map(document.getElementById('map'), {
center: pos,
zoom: 12
});
infowindow = new google.maps.InfoWindow();
var service = new google.maps.places.PlacesService(map);
service.nearbySearch({
location: pos,
radius: 5000,
type: ['night_club'],
}, callback);
function callback(results, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
createMarker(results[i]);
}
}
var locale = JSON.stringify(results[0].vicinity);
bouncrFactory.bouncrs(locale).then(function(data){
$scope.bouncrList = data.data.bouncrs
$rootScope.showBlist = data.data.showBlist
})
$rootScope.$apply()
}
function createMarker(place) {
var placeLoc = place.geometry.location;
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(place.name);
infowindow.open(map, this);
console.log(place.name)
});
}
$ionicLoading.hide();
})
}
$scope.initMap()
});
$ionicPlatform.ready was added from another solution
$scope.apply was added from another solution
i've used
$timeout(function(){
...
},1000)
and every other solution i can find

$digest already in progress when i use ionicplatform.ready with camera functionality

This is my controller, i am trying to capture image with a button in page 1 and store it locally, and display image1 in page 1, then if i click the button again to take the pic of image2. Image2 should be displayed in page1 and image1 should be viewed in page2
.controller('LeadDetailController', [
'$scope',
'$cordovaDevice',
'$cordovaFile',
'$ionicPlatform',
'ImageService', 'FileService',
function( $scope,
$cordovaDevice,
$cordovaFile,
$ionicPlatform,
ImageService, FileService) {
// image capture code
$ionicPlatform.ready(function() {
console.log('ionic is ready');
$scope.images = FileService.images();
$scope.$apply();
});
$scope.urlForImage = function(imageName) {
var trueOrigin = cordova.file.dataDirectory + imageName;
return trueOrigin;
}
$scope.addImage = function(type) {
ImageService.handleMediaDialog(type).then(function() {
$scope.$apply();
});
}
at the initial stage itself i am getting this error
Error: [$rootScope:inprog] $digest already in progress
page1 with buttons
// here camera function is called to open the camera and take pic
<ion-option-button ng-click="addImage()"class="icon ion-android-camera"></ion-option-button>
//here the pic taken in camera should be displayed
<ion-option-button>
<img src="">
</ion-option-button>
//here moveing to the next page2
<ion-option-button ng-click="Page2()" class="icon ion-ios-grid-view"></ion-option-button>
page2 html
<ion-view>
<ion-nav-bar class="bar-positive">
<ion-nav-title class="title">Grid View</ion-nav-title>
</ion-nav-bar>
<ion-content class="has-header">
<img ng-repeat="image in images" ng-src="{{image.src}}" ng-click="showImages($index)" style="height:50%; width:50%; padding:2px ">
</ion-content>
</ion-view>
page2 controller
.controller('gridController', function($scope, $ionicBackdrop, $ionicModal, $ionicSlideBoxDelegate, $ionicScrollDelegate) {
//here the images are stored inside the array
$scope.images = [{ }];
services
.factory('FileService', function() {
var images;
var IMAGE_STORAGE_KEY = 'images';
function getImages() {
var img = window.localStorage.getItem(IMAGE_STORAGE_KEY);
if (img) {
images = JSON.parse(img);
} else {
images = [];
}
return images;
};
function addImage(img) {
images.push(img);
window.localStorage.setItem(IMAGE_STORAGE_KEY, JSON.stringify(images));
};
return {
storeImage: addImage,
images: getImages
}
})
.factory('ImageService', function($cordovaCamera, FileService, $q, $cordovaFile) {
function makeid() {
var text = '';
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i = 0; i < 5; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
};
function optionsForType(type) {
var source;
/* switch (type) {
case 0:
source = Camera.PictureSourceType.CAMERA;
break;
case 1:
source = Camera.PictureSourceType.PHOTOLIBRARY;
break;
}*/
return {
destinationType: Camera.DestinationType.FILE_URI,
sourceType: source,
allowEdit: false,
encodingType: Camera.EncodingType.JPEG,
popoverOptions: CameraPopoverOptions,
saveToPhotoAlbum: false
};
}
function saveMedia(type) {
return $q(function(resolve, reject) {
var options = optionsForType(type);
$cordovaCamera.getPicture(options).then(function(imageUrl) {
var name = imageUrl.substr(imageUrl.lastIndexOf('/') + 1);
var namePath = imageUrl.substr(0, imageUrl.lastIndexOf('/') + 1);
var newName = makeid() + name;
$cordovaFile.copyFile(namePath, name, cordova.file.dataDirectory, newName)
.then(function(info) {
FileService.storeImage(newName);
resolve();
}, function(e) {
reject();
});
});
})
}
return {
handleMediaDialog: saveMedia
}
});
could someone help me to fix this issue and to help me with page2 to imageviewing
As stated by #Ila the problem is likely due to $scope.$apply().
So if you can't predict if it has to be used then insert in an if statement as follows:
if(!$scope.$$phase) {
// no digest in progress...
$scope.$apply();
}
However this is not a good practice: prefer to use $scope.$apply() only when really needed (). See Angular docs
I agree with vb-platform. But what you can also do is wrapping your code into a $timeout so angularjs would handle the $apply for you ($timeout):
$ionicPlatform.ready(function() {
console.log('ionic is ready');
$timeout(function setImages() {
$scope.images = FileService.images();
});
});

AngularJS ng-click not firing using angular-google-maps' windows

I wanted to automatically center the map to the user's location once loaded so I used $scope.$apply() once geolocation is loaded as seen in my TestCtrl in controller.js here:
$scope.drawMap = function(position) {
$scope.$apply(function() {
$scope.myLocation.lng = position.coords.longitude;
$scope.myLocation.lat = position.coords.latitude;
$scope.map = {
center: {
latitude: $scope.myLocation.lat,
longitude: $scope.myLocation.lng
},
zoom: 14,
events: {
click: $scope.clickCallback
}
};
});
};
navigator.geolocation.getCurrentPosition($scope.drawMap);
$scope.test = function(){
alert("hola");
};
The $scope.clickCallback is used to push new markers to the map on click event.
// inside TestCtrl
var markers = [], counter = 1;
$scope.clickCallback = function(map, eventName, event){
var lat = event[0].latLng.lat();
var lng = event[0].latLng.lng();
markers.push(createNewMarker(counter, lat, lng));
$scope.$apply(function(){
$scope.newMarker = markers;
});
counter++;
};
As you can see, there's another $scope.$apply there to apply the new marker/s.
The createNewMarker() is where the markers (ui-gmap-markers) models is defined.
// still inside TestCtrl
var createNewMarker = function(i, lat, lng, idKey) {
if (idKey == null) {
idKey = "id";
}
var foo = "<h4>New Marker</h4><form><input type='text' placeholder='Event name' name='name'></input> <input type='button' value='submit'></input><input type='button' ng-click='test()' value='Delete marker'></input></form>";
var bar = $compile(foo)($scope);
var ret = {
latitude: lat,
longitude: lng,
show: true,
options: {
draggable: true,
animation: google.maps.Animation.DROP,
},
windows: {
title: "New Marker",
},
windowsOptions: {
content: foo,
}
};
ret[idKey] = i;
return ret;
};
Now the marker is showing fine when I click on the map including the window, but when I click on the Delete marker button, my $scope.test() function isn't firing up. I tried using $compile but it returns a bunch of error about $scope.
Here's my template:
<ion-content scroll="false">
<ui-gmap-google-map center='map.center' zoom='map.zoom' bounds="map.bounds" events="map.events">
<ui-gmap-markers models="newMarker" coords="'self'" icon="'icon'" options="'options'">
<ui-gmap-windows show="show" options="'windowsOptions'">
</ui-gmap-windows>
</ui-gmap-markers>
</ui-gmap-google-map>
</ion-content>
Anyone familiar with this scenario? I'm using Ionic Framework btw.
It does not have to be this complex.
As a creator of ngMap, I would recommend this,
http://ngmap.github.io/drawings.html#/marker-remove#marker-remove
To set the current location, just use current-location
<map center="current-location" zoom="12" on-click="addMarker()">
<marker ng-repeat="pos in positions" position="{{pos.lat}}, {{pos.lng}}"></marker>
</map>
http://plnkr.co/edit/e1SioHQ6NTSYCp0EbR0x?p=preview

angularjs googlemap not loading when trying to load in a modal

I am using AngularJS google maps to display map with markers.
The scenario is :
Initially Contact Details like Door no, Street, Area etc fields page will be displayed along with a static map. Once an edit button is clicked a pop-up with all the fields and map is displayed.
ex:
CODE:
html
<div class="row" ng-controller="userProfileController">
<ui-gmap-google-map center="center1" zoom="zoom1" pan="true" events="events">
<ui-gmap-markers models="models1" coords="'self'" options="'options'"></ui-gmap-markers>
</ui-gmap-google-map>
</div>
controller
$scope.center1 = {
latitude: lat,
longitude: lng
};
$scope.zoom1 = 8;
$scope.models1 = [{
id: 11445522,
latitude: lat,
longitude: lng,
options: {
title: "Current Location"
}
}];
Well everything works fine so far.
When edit is clicked i am trying to load another html in the modal that contains fields and a map. This time the map isn't loading. if I press 'F12' then map can be seen.
Code for popup:
html
<div class="col-sm-12">
<ui-gmap-google-map center="center3" zoom="zoom3" pan="true" events="events3" refresh="true">
<ui-gmap-markers doRebuildAll="true" doCluster="true" models="models3" coords="'self'" options="'options'"></ui-gmap-markers>
</ui-gmap-google-map>
controller
$scope.center3 = {latitude: 19.20742852680121,
longitude: 73.553466796875
};
$scope.zoom3 = 7;
$scope.models3 = [{
id: 5421222,
latitude: 19.20742852680121,
longitude: 73.553466796875,
options: {
title: "User Location"
}
}];
What might be the issue.? Can someone help me?
It displays like this:
I had a similar problem, but in my case, the user input an address and return the location. I found on the Internet the solution, and with some adjustments, I decided this way...
First, I create myController in app.js
app.controller('myController'), function ($scope) {
// my variable that's control my modal
$scope.showModal = false;
// my click event, like your 'Edit' button
$scope.createModal = function () {
$scope.showModal = true;
};
}
HTML index.html
<my-modal visible="showModal"></my-modal>
HTML modal.html
<div class="form-group">
<input type="text" class="form-control" ng-model="chosenPlace" details="chosenPlaceDetails" googleplace placeholder="Address"/>
<div class="map_container">
<div id="map_canvas" class="map_canvas"></div>
</div>
</div>
Then, in my modal.js, I created two Directive's
// Directive of Google Maps
angular.module('modal', [])
.directive('googleplace', function () {
return {
require: 'ngModel',
scope: {
ngModel: '=',
details: '=?'
},
controller: function ($scope) {
$scope.gPlace;
$scope.map;
$scope.marker;
$scope.initMap = function () {
// Set the initial lat and lng
var latlng = new google.maps.LatLng(-20.00, -47.00);
var options = {
zoom: 5,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
$scope.map = new google.maps.Map($("#map_canvas")[0], options);
$scope.marker = new google.maps.Marker({
map: $scope.map,
draggable: true,
});
$scope.marker.setPosition(latlng);
};
$scope.initMap();
},
link: function(scope, element, attrs, model) {
var options = {
types: ['geocode'],
componentRestrictions: { country: 'us' }
};
scope.gPlace = new google.maps.places.Autocomplete(element[0], options);
google.maps.event.addListener(scope.gPlace, 'place_changed', function() {
scope.$apply(function() {
google.maps.event.trigger(scope.map, 'resize');
var location = new google.maps.LatLng(scope.gPlace.getPlace().geometry.location.A, scope.gPlace.getPlace().geometry.location.F);
scope.marker.setPosition(location);
scope.map.setCenter(location);
scope.map.setZoom(16);
});
});
}
};
});
.directive('myModal', function () {
return {
templateUrl: 'modal.html',
restrict: 'E',
replace: true,
scope: true,
controller: function ($scope) {
},
link: function postLink(scope, element, attrs) {
scope.$watch(attrs.visible, function(value) {
if(value == true) {
$(element).modal('show');
}
else {
$(element).modal('hide');
}
});
$(element).on('shown.bs.modal', function(){
scope.$apply(function(){
scope.$parent[attrs.visible] = true;
});
});
$(element).on('hidden.bs.modal', function(event){
scope.$apply(function(){
scope.$parent[attrs.visible] = false;
});
});
}
};
});
When the user write his address, and hit Enter, the listener on the map, find the address and marker on the map.
I did like that because it was the best solution I found for my project.
I hope that helps.
PS: Sorry my english :/

Resources