Adding location to Google Map on page load with Angular UI - angularjs

Thanks to #AJoslin I now have a working google map using only AngularUI and AngularJS.
Unfortunately there are two things I can't figure out how to do which may have to do with Google Map API and my lack of understanding of.
When the map initially loads, I already have a location so I wish to load it with a marker already on it. How do I do that?
I also wish to set the ng-click="myMap.panTo(marker.getPosition()) not to a new marker but to the initial location, which is the only marker I would have since I'm removing the add marker functionality out, once I can figure this one out.
Here is the working jsfiddle
http://jsfiddle.net/jorgecas99/xMw6U/

i think it should be achievable by setting the tilesloaded event, but didnt manage that way, so i ended up using a simple "trick", watching for myMap to appear.
$scope.$watch('myMap', function(){
$scope.setHome();
});
$scope.setHome = function() {
$scope.homeMarker = new google.maps.Marker({
map: $scope.myMap,
position: $scope.mapOptions.center
});
}

Related

angular-google-maps - listen for infowindow domready event

Listening for the domready event in normal js Google maps is relatively easy
as outlined here :
infoWindow = new google.maps.InfoWindow();
google.maps.event.addListener(infoWindow, 'domready', function() {
// whatever you want to do once the DOM is ready
});
However it doesn't seem obvious how to do it in angular-google-maps.
Is there a solution ?
The solution when using Angular Google Maps involves using the infowindow control object - see docs.
As noted in this issue - where I first posted this solution - you can create an empty infowindow control object within the main controller :
$scope.infowindowControl = {};
Then you scope bind your new object in the ui-gmap-window directive definition like :
<ui-gmap-window
options="windowOptions"
closeClick="closeClick()"
control="infowindowControl"
>
On infowindow open (actually unsure at what point) - it will pass five functions to the empty object you created within $scope. Some of these functions are noted in the documentation but in a rather haphazard and non-defined way :
getChildWindows()
getGWindows()
getPlurals()
hideWindow()
showWindow()
The one that you need is getGWindows() - which you put inside your marker click event.
This will get you an array of the open infowindows and you can now attach an event listener in the standard google maps fashion, like :
var windows = $scope.infowindowControl.getGWindows();
console.log('inside click after getGWindows ', windows);
google.maps.event.addListener(windows[0], 'domready', function() {
console.log('infowindow domready just fired !!');
});
While it's not an ideal, well documented or easy solution (and took me a number of hours to figure out) - and passing functions to an empty object is frankly counter-intuitive - it does seem to work.
Plunker here.

How can I reinitialize ngMaps when changing routes in Angular, using ui-router?

I'm using ngMap and here's my relevant code:
<div map-lazy-load="https://maps.google.com/maps/api/js" map-lazy-load-params="{{googleMapsUrl}}" ng-style="{'height': feedActualHeight + 'px'}">
<ng-map id="iPadFeedMap" zoom="14" center="Times Square, New York, NY">
</ng-map>
</div>
This works great and loads the map perfectly. But when I navigate away and then come back to the page, the map is grayed out:
Is there a way to re-initialize the map when this page loads?
I experienced the exact same issue regardless of how center was being set (it failed both with lat/lng and a physical address), but the accepted answer wasn't quite working for me.
My solution was to use NgMap's lazy-init property to re-initialize the map each time I returned to it.
<ng-map id="dashboard-map"
center="Boston, MA"
lazy-init="true"
zoom="9"
map-type-id="TERRAIN">
</ng-map>
In my ctrl I used the following code to 1) find the uninitialized map in the DOM and 2) initialize it
// dashboardCtrl.js
NgMap.getMap({ id: "dashboard-map" }).
then(function(map) {
NgMap.initMap(map.id);
});
This way every time I hit my dashboard, the ctrl would run and re-init the map. It now shows properly every time.
This was a helpful thread to read through: https://github.com/allenhwkim/angularjs-google-maps/issues/387
It seems it only occurs in case when value for center attribute is provided as address value (e.g. Times Square, New York, NY). In that case the way the map center is determined consist of the following steps:
since ng-map leverages Google Maps Geocoding API, the corresponding method is invoked to resolve actual location (lat,lng)
Map object center property is getting updated
Since this issue never occurred for me when center attribute is provided as location value (e.g. [40.759011, -73.98447220000003]) i propose to change the way how map is initialized:
remove setting of center attribute center="Times Square, New
York,NY"
instead set map center as demonstrated below:
Example: set map center by address
NgMap.getMap("iPadFeedMap").then(function (map) {
NgMap.getGeoLocation($scope.address)
.then(function (latlng) {
map.setCenter(latlng);
});
});
$scope.address = "Times Square, New York, NY";
Demo

Angularjs - Charts.js: Same chart element doesn't redraw on other view

I am new to angularjs, trying to create my first directive. I am creating a directive to load Charts.js2.0(beta) into my application.
I have 2 views managed by angular-route, both html view has ng-included a html page that contains only charts-element.
The problem is the first page properly draws the chart, when i go to other view the charts div is loaded but charts is not re-drawn. And now if i go back to first view its blank.
Link to Plunker
What i am doing wrong? Is there any issue with my directive?
Thanks in advance.
There appears to be an issue with the Charts library modifying the existing object on the root scope, and thereby ignoring it forever afterward. I can't really trace down what is doing it, but here's a fix for you: http://plnkr.co/edit/jDQFV62FSeXAQJ6o7jE8
Here is what you had
scope.$watch('config', function(newVal) {
if(angular.isDefined(newVal)) {
if(charts) {
charts.destroy();
}
var ctx = element[0].getContext("2d");
charts = new Chart(ctx, scope.config);
//scope.$emit('create', charts);
}
});
Above, you can see that you're passing scope.config directly into the charts method. That appears to be modifying the data somehow, and since that's passed by reference, you're actually modifying $rootScope.sales.charts. If you copy that object and use it locally like below, you don't have that problem.
Here's how I fixed it.
scope.$watch('config', function(newVal) {
var config = angular.copy(scope.config);
if(angular.isDefined(newVal)) {
if(charts) {
charts.destroy();
}
var ctx = element[0].getContext("2d");
charts = new Chart(ctx, config);
//scope.$emit('create', charts);
}
});
You can see that instead of passing that object directly in, we use angular to make a copy (angular.copy()), and that's the object we pass in.
I think it has relation with the id of the canvas where you are drawing. I've had this problem too amd it was because i was using the same id for the canvas of two graphs in different views. Be sure that those ids are different and that the javasrcipt of each graph is in the controller of each view or in each view itself.
Taking a look at your pluker I see that you are using the same html for the graph and I guess that when angular moves from one of your views to the other thinks that the graph is already drawn. Differentiating two graphs will solve the problem. I don't know of there is any other approach that allows using the same html for the canvas of the graph.
Hope it helps you solve it

Angular.js view rendering (with a bit more than just showing the retrieved values)

I'm working on a view that allows user to type in the postcode and then it will give the location info about the postcode (lat, long, city name, etc), as well as marking the location on a map (using google map api).
For the postcod part, it is rather straight forward, I placed a few {{}} directives in the view and assign the corresponding values to the $scope in the controller. But when it comes to marking that location on the google map view, it gets a bit confusing. here is the sample code to mark a place in google map:
var containerID = 'map-container'; // id of a DIV
var lat = 50.2;
var lng = -3.6;
var container = document.getElementById(containerID);
var options = {
zoom: 15,
center: new google.maps.LatLng(lat, lng),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(container, options);
var marker = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),
map: map,
title: markerTitle
});
As you can see, the code itself only involves rendering the map, and to me it should sit inside the view because a view is supposed to take the returned result from the controller and do whatever magic it wants to present that result. And since the code involves manipulating the DOM, which is another reason I don't think it should be in the controller.
But am I correct to make this assumption?
And even if i'm correct, how could I implement this?
You are right, DOM Manipulation should not be in the controller, but it shouldn't be in the view neither.
The Angular way would be to create a directive that handle all DOM Manipulation. This directive is independent and work alone, and is here to do the dirty job. Once you've created it, you add it in the view, and pass it the parameters from the controllers.
So the view display the element, the controllers set the model and values, and the directive handle DOM manipulation/graphic change,value processing ...etc.
Good news for you, I think that in your case the directive has already been made, you may want to take a look at : AngularUI GoogleMap Directive
Try writing your asynchronous codes inside.
$scope.$apply(function{
})

Google maps not always fully rendering in Ionic

Having trouble with always rendering google maps in my Ionic app. When I first land on a view from a list of items on the previous view, the map always renders in its complete state. However, if I go back to the previous view and tap a different business, or even the same one, it appears as if the map is only rendering 25% of the complete map. I'm having this issue on both the emulator and on my iPhone.
Example
Code
getData.getBusinesses()
.then(function(data) {
// get businesses data from getData factory
})
.then(function(data) {
// get businesses photo from getData factory
})
.then(function(data) {
// get some other business stuff
})
.then(function() {
// get reviews for current business from separate async call in reviews factory
})
.then(function() {
// instantiate our map
var map = new GoogleMap($scope.business.name, $scope.business.addr1, $scope.business.city, $scope.business.state, $scope.business.zip, $scope.business.lat, $scope.business.long);
map.initialize();
})
.then(function() {
// okay, hide loading icon and show view now
},
function(err) {
// log an error if something goes wrong
});
What doesn't make sense to me is that I'm using this exact code for a website equivalent of the app, yet the maps fully load in the browser every time. The maps also fully load when I do an ionic serve and test the app in Chrome. I did also try returning the map and initializing it in a following promise, but to no avail.
I've also tried using angular google maps, but the same issue is occurring. I think I might want to refactor my gmaps.js (where I'm creating the Google Maps function) into a directive, but I don't know if that will actually fix anything (seeing as angular google maps had the same rendering issue).
I don't think the full code is necessary, but if you need to see more let me know.
EDIT
It seems that wrapping my map call in a setTimeout for 100ms always renders the map now. So I guess the new question is, what's the angular way of doing this?
I'm seeing similar issues with ng-map in Ionic. I have a map inside of a tab view and upon switching tabs away from the map view and back again, I would often see the poorly rendered and greyed out map as you describe above. Two things that I did that may help fix your issue:
Try using $state.go('yourStateHere', {}, {reload: true}); to get back to your view. The reload: true seemed to help re-render the map properly when the map was within the tab's template.
After wrapping the map in my own directive, I found the same thing happening again and wasn't able to fix it with the first suggestion. To fix it this time, I started with #Fernando's suggestion and added his suggested $ionicView.enter event to my directive's controller. When that didn't work, I instead added a simple ng-if="vm.displayMap" directive to the <ng-map> directive and added the following code to add it to the DOM on controller activation and remove it from the DOM right before leaving the view.
function controller($scope) {
vm.displayMap = true;
$scope.$on('$ionicView.beforeLeave', function(){
vm.displayMap = false;
});
}
Hope that helps.
don't use setTimeout on this!
You need to understand that the map is conflicting with the container size or something (example: map is loading while ionic animation is running, like swiping).
Once you understand this, you need to set map after view is completely rendered.
Try this on your controller:
$scope.$on('$ionicView.enter', function(){
var map = new GoogleMap($scope.business.name,
$scope.business.addr1, $scope.business.city,
$scope.business.state, $scope.business.zip,
$scope.business.lat, $scope.business.long);
map.initialize();
});

Resources