Angular Google Maps not displaying in Ionic - angularjs

I'm using Angular Google Maps to implement a map and geo-location in my Ionic app. I do everything according to the docs, but the map isn't displaying (even though there isn't any console output showing errors).
Controller:
app.controller('panicController', ['$scope', '$cordovaGeolocation',
function($scope, $cordovaGeolocation) {
$scope.map = { center: { latitude: 45, longitude: -73 }, zoom: 8 };
}
]);
View:
<ion-view hide-nav-bar="true" ng-controller="panicController" class="panic-view">
<ion-content data-tap-disabled="true" class="padding">
<ui-gmap-google-map center='map.center' zoom='map.zoom'></ui-gmap-google-map>
</ion-content>
</ion-view>
SCSS:
.angular-google-map-container {
height: 100%;
}
When I run it, I just get a blank/empty white view. And my console output:
Any idea of what the issue could be?

maybe this example can help you._
nightly codepen
I used this example in my application too and I like the way.
Do you need to develop it this way?
Greetz,
Bernhard

Try removing the sensor parameter. But according to the docs, it should not affect the API's behavior. It looks like there's something else going on that shows you the white view.
From the Google Maps API Docs: https://developers.google.com/maps/documentation/javascript/error-messages
SensorNotRequired: The sensor parameter is no longer required for the
Google Maps JavaScript API. It won't prevent the Google Maps
JavaScript API from working correctly, but we recommend that you
remove the sensor parameter from the script element.

In my case the solution was to explicitly specify dependency to uiGmapgoogle-maps via module, so make sure uiGmapgoogle-mapsmodule is included:
var app = angular.module('ionicApp', ['ionic', 'uiGmapgoogle-maps']);
Demo

Related

Using Google Maps API on Single page application - Error using multiple times the api

I have an angular WebApp in which I use the google Map API. It is loaded in the html view. On click the states changes to another page and loads the map. It is working well for the first time. When I go back to the loading page my console says: You have included the Google Maps API multiple times on this page. This may cause unexpected errors. And when i load the map again, some unexpected errors are happening.
So my question: Is it possible to reset the google Maps API so that it refreshes everytime i go back? Or can i delete the instance or what should i do?
I'm using the angular google maps directive: https://angular-ui.github.io/ and implementing it with:
<script src="https://maps.googleapis.com/maps/api/js?key=XXXXXX" type="text/javascript">
On the page who is loading it.
The maps page is loaded with resolving the 'uiGmapgoogle-maps' directive.
I'm using the inline javascript cause i could not figure out how to pass an api key to the directive settings. And I load it before the google maps page so, the maps loads well.
State first page:
.state('apps.vermittlungDetail', {
url: '/vermittlung/detail/:taskID',
templateUrl: 'tpl/apps_vermittlung_detail.html',
controller: 'XeditableCtrl',
resolve: load( ['ui.select','toaster','js/app/globalServices/global-services.js','js/app/vermittlung/newTask-service.js','js/controllers/bootstrap.js','js/app/vermittlung/vermittlung-detail.js','js/app/annulation/annulation-service.js','js/app/smsTool/smsTool-service.js','js/app/emailMami/emailmami-service.js' ,'js/app/vermittlung/vermittlung-service.js', 'smart-table','xeditable','js/controllers/xeditable.js', 'moment'])
})
State second page (the map)
.state('apps.vermittlungGoogleMap', {
url: '/vermittlungMap',
templateUrl: 'tpl/apps_vermittlung_googlemap.html',
resolve: load( ['uiGmapgoogle-maps','toaster','js/app/vermittlung/vermittlung-detail.js', 'js/app/vermittlung/vermittlung-service.js'])
})
HTML second page
<div ng-controller="vermittlungDetailCtrl"> <!--SET CONTROLLER-->
<ui-gmap-google-map center='map.center' zoom='map.zoom'>
<ui-gmap-markers models="markers" coords="'self'" icon="'icon'" options="markers.options" click="onClickMarker">
</ui-gmap-markers>
<ui-gmap-window options="windowOptions" show="showWindow" coords="windowData.model" closeClick="closeClick()">
<div>
<div class="m-b-sm">{{currentMarkerTitle}}<br>{{currentMarkerPhone}}</div>
<button class="btn btn-info btn-xs" ng-click="$parent.sendMamiSMS($parent.tasktosend,$parent.currentMarkerPhone,$parent.currentMarkerTitle)">SMS senden</button>
</div>
</ui-gmap-window>
</ui-gmap-google-map>
</div>
First, set the controller on your state, not your template.
.state('apps.vermittlungGoogleMap', {
url: '/vermittlungMap',
controller: 'vermittlungDetailCtrl',
templateUrl: 'tpl/apps_vermittlung_googlemap.html',
resolve: load( ['uiGmapgoogle-maps','toaster','js/app/vermittlung/vermittlung-detail.js', 'js/app/vermittlung/vermittlung-service.js'])
})
Then stop importing GoogleMaps like this
<script src="https://maps.googleapis.com/maps/api/js?key=XXXXXX" type="text/javascript">
Angular Google Maps already does it.
To manipulate the map and insert your API key, take a look here.
The answer from mcrvaz solved my problem. I removed the inline javascript file. And loaded it uiGmapgogole map Instance in the controller. Like in the docs.
.controller("someController", function($scope, uiGmapGoogleMapApi) {
// Do stuff with your $scope.
// Note: Some of the directives require at least something to be defined originally!
// e.g. $scope.markers = []
// uiGmapGoogleMapApi is a promise.
// The "then" callback function provides the google.maps object.
uiGmapGoogleMapApi.then(function(maps) {
});
});
I was missing putting "uiGmapGoogleMapApi" in the controller head.

Why Google maps refuses to render fully

This problem afflicts chrome, ff and opera (all latest) on fedora 23.
Its a django app which uses angular's uiGmapGoogleMapApiProvider to initialize google maps (v3). I've seen many posts which show a possible solution involving google.maps.events.trigger(map, 'resize'). This does not work for me.
My map gets rendered in the following html snippet:
<section class="section-googlemap">
<ui-gmap-google-map center="map.center" zoom="map.zoom"
options="options"
events="map.events"
control="map.control">
</ui-gmap-google-map>
</section>
For the uiGmapGoogleMapAPIProvider, i've the following codebase:
uiGmapGoogleMapApiProvider.configure({
key: "XXXXYYYY",
v: "3.17",
libraries: "weather,geometry,visualization"
});
Then in another controller, i've the following:
uiGmapGoogleMapApi.then(function(maps) {
$scope.maps = maps;
geocoder = new maps.Geocoder();
});
I've referred to the following SO posts and tried to get this working but to no avail:
Google Map not loading completely after inital call
Google Map shows only partially
Google Map displaying just partially
Please tell me if there is anything else i can do.

Build an Ionic App with Wistia Player API not working on iOs.

So I am building an Ionic / AngularJS app using Wistia player API. I finial tried and everything work right on browser test mode. But when compile onto iOs, it just show white screen. Here is the detail:
View - HTML page:
<!-- Wistia Embed -->
<div id="{{ 'wistia_' + mediaHashId }}" class="wistia_embed" style="width:398px;height:224px;" ng-if="mediaHashId"></div>
Controller:
$timeout(function() {
var wistiaEmbed = Wistia.embed($scope.mediaHashId, {
videoFoam: true,
playerColor: "3B97D3"
});
wistiaEmbed.bind("end", function () {
alert ("Video is finished");
});
}, 100);
So it load perfectly onto Chrome.
But when I compile it onto xcode and run it on my phone. It just show a white screen (with no JS error!)
SECOND OPTION: iframe - since iframe load okay on iOs (http://wistia.com/doc/player-api#using_iframes_and_the_player_api).
The second option is attach wistiaApi onto an iframe. But the code does not work.
View - HTML page:
<div class="video-container">
<iframe id="wistia_player" ng-src="{{ mediaHashId | wistiaEmbedUrl }}" allowtransparency="true" frameborder="0" scrolling="no" class="wistia_embed" name="wistia_embed" width="640" height="360"></iframe>
</div>
Controller:
$timeout(function() {
var wistiaEmbed = document.getElementById("wistia_player").wistiaApi;
console.log (wistiaEmbed);
wistiaEmbed.bind("end", function () {
alert ("Video is finished");
});
}, 100);
The wistiaEmbed console log an undefined.
And error log:
TypeError: Cannot read property 'bind' of undefined
at lesson-detail-ctrl.js:46
at ionic.bundle.js:24922
at completeOutstandingRequest (ionic.bundle.js:13604)
at ionic.bundle.js:13984
So clearly .wistiaApi does not work...
I do include this in my index.html:
I will love a AngularJS library like this https://github.com/brandly/angular-youtube-embed with Wistia Player...but no luck...
Wow, I've found the problem. This is actually a very common problem when building ionic apps on iOs and/or Android. When you include <script> tags in your index.html, always put the full http://.... instead of using just //.
In my case, I included the Wistia API via their official documentation like:
<script src="//fast.wistia.com/assets/external/E-v1.js"></script>
It works on browsers because browsers are smart. Devices are not as smart as browsers so by including the http like so:
<script src="https://fast.wistia.com/assets/external/E-v1.js"></script>
Solves it!

Angular Google Map not rendering in Ionic view

I am experiencing some issues with implementing the angular-google-maps plugin (https://angular-ui.github.io/angular-google-maps/#!/) for the Ionic Framework software in that I cannot get the map to render at all. Crazy thing is that the GoogleMapAPI promise is being triggered (as per alerts that I am placing within there for testing purposes) but no map is rendered to the screen.
My index.html file (in my iOS directory) uses the following file calls:
_assets/_js/_plugins/lodash-2.4.1.min.js"
lib/ionic/js/ionic.bundle.js"
lib/ngCordova/ng-cordova.min.js"
cordova.js"
_assets/_js/_plugins/angular-google-maps-2.0.7.min.js"
_assets/_js/app.js"
_assets/_js/_custom/factories.js"
_assets/_js/_custom/controllers.js"
I have double checked that these files are all present in the locations I have listed in the script src attributes so no problems there.
The Google Map plugin is being loaded/initialised within my controller.js file via the following:
angular.module('sampleAppNameHere.controllers', ["google-maps".ns()])
.config(['GoogleMapApiProvider'.ns(), function (GoogleMapApi) {
GoogleMapApi.configure({
key: 'MY-KEY-HERE',
v: '3.17',
libraries: 'weather,geometry,visualization'
});
}])
Further down in the controller where I want the Google Map to be loaded from I have the following set-up:
.controller('LocationController', ['$scope', '$http', '$stateParams', '$sce', '$ionicLoading', '$ionicPopup', '$timeout', 'Logger'.ns(), 'GoogleMapApi'.ns(), 'RetrieveAppContent', function($scope, $http, $stateParams, $sce, $ionicLoading, $ionicPopup, $timeout, $log, GoogleMapApi, RetrieveAppContent)
{
function parseLocations(locationID, locationName, regionName)
{
// Retrieve factory function to return AJAX loaded data
RetrieveAppContent.retrieveRemoteContentForApp().then(function(locationObj)
{
// Loop through associative array formed from parsed AJAX data into factory method
angular.forEach(locationObj.locations, function(v, k)
{
if(locationID === v.recordID)
{
// Other content in here bonded to scope
$scope.mapLongitude = v.mapLongitude;
$scope.mapLatitude = v.mapLatitude;
$scope.mapZoom = v.mapZoom;
}
});
GoogleMapApi.then(function(maps)
{
// Alerts placed in here are triggered when the template loads
maps.visualRefresh = true;
$scope.map = { center: {latitude: $scope.mapLatitude, longitude: $scope.mapLongitude }, zoom: $scope.mapZoom };
$scope.options = { scrollwheel: false };
});
});
}
}
The parseLocations function is called shortly afterwards in the above controller and the content is all loaded into the template exactly as intended so no problems there BUT the angular map will not render.
The following segment is from the view where the content for the controller is loaded/displayed and where the map is located:
<ion-view title="{{ locationName }}">
<ion-content class="location-panel" ng-controller="LocationController">
<!-- Render Google Map -->
<div id="map-canvas">
<ui-gmap-google-map center="map.center" zoom="map.zoom"></ui-gmap-google-map>
</div>
I have set the following class within the CSS that the app uses:
.map-canvas,
.angular-google-maps-container {
height: 400px;
}
But I see NO rendering of the map only a white space fixed to the above height.
Can anyone offer any suggestions/heads-up on what might or could be causing the non-rendering of the Map and what steps I might be able to take to rectify this?
My thanks in advance for any help that folk might be able to provide.....and my apologies if the code formatting is a bit wonky! :-/
Check your CSS class
.angular-google-maps-container
should be
.angular-google-map-container.
I believe you have it as maps not map.
First of all thanks to Brad for his answer to my question (the heads up on the CSS class name WAS useful for my most recent attempt in using this package!).
I originally solved this, back in November 2014, by writing my own custom directive which provided the Google Map functionality that I needed.
Since then I've had occasion to use the latest version of the AngularJS Google Maps package (angular-google-maps 2.0.12 2015-01-29) and have implemented this without problem (noting Brad's tip on the class name).
Thanks once again.

AngularJS different views based on Desktop or Mobile

I would like to use AngularJS for a single page webapp.
I am concerned if there is an elegant way to "send" different templates based on whether the client is a mobile or desktop.
Is there any way to do it ? Is it recommended that web server "understand" what the browser is and send the view accordingly so the browser always asks for template.html OR you write javascript so the browser will tell webserver to get the mobile/template.html ?
if you wanted to use the same URL but serve two different sets of HTML (say swap out large images and inpage videos for something else) I would do something like this
'use strict';
angular.module('MyApp', []).config(function ($routeProvider) {
// Magic sauce, imediate so the value is stored and we don't need to lookup every check
var _isNotMobile = (function() {
var check = false;
(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
return !check;
})();
// Swap out different HTML because you want to say, hide a video etc.
$routeProvider
.when('/', {
templateUrl: (_isNotMobile )? 'views/MY_DESKTOP_VIEW.html':'views/m/MY_MOBILE_VIEW.html',
controller: (_isNotMobile )?'MyHomeCtrl':'MyMobileCtrl'
})
.otherwise({
redirectTo: '/'
});
});
How I would go about with this is to display one template to the user and make the template Responsive. Just because you are using AngularJS templates, I do not see a reason why you would not want to make the template responsive. I would not go for the solution that involves displaying a different template to the user based on the device browser.
That said, one way that I would do is:
To have a simple script for the home / landing page of the web application that determines the browser / device. This can be found here.
Next, depending on the browser / device, you redirect the user to a different route
Have different routes based on the browser / device type - display a different template based on the route and thus identify if it s a mobile device or not based on the route.
The last step would be something like:
angular.module('myApp', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
//Display desktop version
when('/desktop/homePage', {
//Template for Desktop based browsers
templateUrl: 'partials/desktop/home-page.html'
}).
//Display mobile version
when('/mobile/homePage', {
//Template for Mobile based browsers
templateUrl: 'partials/mobile/home-page.html'
}).
otherwise({redirectTo: '/desktop/homePage'});
}]);
Responsive design will work well for smaller apps but gets rather messy when you move to bigger applications.
I'd personally suggest detecting the user agent on page load, and redirecting him to a separate mobile app if needed. You can still use most of your code base for both apps (simply import individual modules).
If your interested in detecting the user agent using javascript I suggest this solution (simply select javascript): http://detectmobilebrowsers.com/ the most extensive solution I've found so far
use boostrap. and it could be easily done.
<!-- Display Only Screen > Big -->
<div class="hidden-xs">
<div ng-view class="section" ng-class="animate"></div>
</div>
<!-- Display Only Screen < Small -->
<div class="visible-xs">
<div ng-swipe-right="openSlide()">
<div ng-view class="section" ng-class="animate"></div>
</div>
</div>
and in landing.html
<div class="visible-xs" ng-include="'{{template path}}/desktop.html'" ></div>
<div class="hidden-xs" ng-include="'{{template path}}/mobile.html'" ></div>
ANd in config
$routeProvider
.when(/,{
templateUrl : "landing.html"
controller : "landingCtrl"
});
it works floawlessley for me. Its not of the way. maybe there could be another using pure JS. This just happened pout of the box since i am using boostrap and leverage it to my advantage.
A bit late, but in something like your header, or nav controller, you could set the initial width:
angular
.module('myApp')
.controller('navCtrl', ['$rootScope', '$window',
function($rootScope, $window) {
$rootScope.is_mobile = ($window.innerWidth < 480);
And if you want checking on resize, go ahead and bind it:
angular.element($window).bind('resize', function() {
$scope.$apply();
});
Then watch it:
$scope.$watch(function () {
return $window.innerWidth;
}, function (innerWidth) {
$rootScope.safeApply(function () {
$rootScope.is_mobile = innerWidth < 480 // went with max device width
});
});
Then in your HTML:
<div ng-if="$root.is_mobile">Show me only in mobile</div>
BOOSTRAP + ANGULARJS solution to this problem:
You can check out the angular-match-media library. It is extremely small in size but very helpful and elegant.
https://github.com/jacopotarantino/angular-match-media
**Watch out: This is installed with bower install angular-media-queries; however, the path to the js file is /path/to/library/angular-media-queries/match-media

Resources