Enabling Google maps after data has been switched on - javascript

I have a Cordova app with an angular bootstrap kicking in on 'deviceready'.
I have Google maps linked like so:
<script src="https://maps.googleapis.com/maps/api/js"></script>
If the app starts with data set to off then obviously the script will be missing.
If the user turns on data how can i initialise Google maps? Must i restart the app? I've tried injecting the script via 'document' but the error message said that's not allowed.
Any help or tips would be very much welcomed.
Cheers
Dale

Basically this code will check if google maps api libraries are loaded when building a map within your angular controller and try get it if not.
//already loaded build the map
if ($window.google && $window.google.maps) {
prepareMap();
} else { //not loaded
//create a promise object
var mapScriptPromise = getMapScript();
mapScriptPromise.then(function(){
prepareMap(); //now you can build the map
});
}
//create the hook for the file and return the deferred promise
function getMapScript() {
var deferred = $q.defer();
var script = document.createElement('script');
//script callback
$window.initMap = function() {
deferred.resolve();
}
script.src = "https://maps.googleapis.com/maps/api/js?sensor=true&callback=initMap";
document.body.appendChild(script);
return deferred.promise;
}
//add your map settings here i.e.
function prepareMap() {
var map = new google.maps.Map(mapCanvas, mapOptions);
...
}

Related

How do you return a javascript object? it keeps throwing a "Converting circular structure to JSON"

I am working on an Ionic app, and I need to use firebase's phone authentication, to use that, I have to use google's recaptcha, which doesn't work in Ionic apps, so...
I made a web page that held the code for rendering the reCaptcha, and used cordova's inAppBrowser to navigate to it from inside my app.
after hours, I got everything working, and finally got the "recaptchaVerifier" object, that you need to pass to firebase.auth().signInWithPhoneNumber(phoneNumber,recaptchaVerifier)
.
I just need to pass the "recaptchaVerifier" object from the inAppBrowser, to my ionic app, I tried everything, and got stuck on a simple javascript function that would "return recaptchaVerifier" and I would grab it in Ionic, but it kept giving me Uncaught TypeError: Converting circular structure to JSON
What do I do? I just need to pass that object so I can send the verification sms from my app and continue registration/signing in.
the code for the static site that renders the recaptcha from inside the inAppBrowser:
<script>
var recaptchaVerifier;
function lol() {
alert("done");
};
$(document).ready(function() {
recaptchaVerifier = new firebase.auth.RecaptchaVerifier('gre', {
'size': 'invisible',
'callback': lol
});
recaptchaVerifier.render();
});
function getIt() {
console.log(recaptchaVerifier);
return recaptchaVerifier;
};
</script>
The code for opening the inAppBrowser and grabbing the recaptchaVerifier Object:
var myInterval;
var myValue : firebase.auth.ApplicationVerifier ;
const browser = this.inAppBrowser.create("https://demo.firebaseapp.com","_blank",
{"location":"no",clearcache:"yes",clearsessioncache:"yes"});
browser.on("loadstop").subscribe(x=>{
myInterval = setInterval(function(){
browser.executeScript({code:"getIt()"}).then(data=>{myValue = JSON.parse(data)});
},200);
});
browser.on("exit").subscribe(x=>{
clearInterval(myInterval);
this.presentAlert("Test Alert",myValue,"OK");
console.log("Adnan12 is error "+ myValue);
firebase.auth().signInWithPhoneNumber("+123456789",myValue)
.then(function (confirmationResult) {
this.presentAlert("alert title","sms sent","ok");
}).catch(function (error) {
this.presentAlert("alert title","sms NOT sent","ok");
});
});

Map always returns undefined

I've been trying to display Bing Map whenever a user clicks on a certain HTML element, but Microsoft.Maps.Map always returns undefined even after setting a timeInterval, I have also tried inserting a new scripts with onscriptload onclick event.
Below are my sample code.
$(document).ready(function(){
var script = document.createElement("script");
script.type = 'text/javascript';
script.src = 'https://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0&onscriptload=getMap';
document.head.appendChild(script);
})
$("#showMap").click(function(){
getMap();
})
function getMap(){
console.info(Microsoft.Maps.Map);
var time = "";
var map
var mapControl = Microsoft.Maps.Map;
if(mapControl == undefined){
time = setInterval(function(){ getMap() }, 8000);
}
else{
map = new Microsoft.Maps.Map(document.getElementById('address1_composite'), {credentials: 'Cred'});
clearInterval(time);
}
}
Sorry I know this question is already asked here in this link, Bing map is undefined after loading Javascript file
We have the same scenario but mine is not working as expected though i have tried the suggested answer.
What you should do instead of creating the map when an element is clicked is load the map once and then hide/show it when the button is clicked. This will significantly reduce the number of map loads which means less transactions are generated and thus lower costs.
Also, instead of loading the map script on demand like you are, use the Bing Maps V8 control and load it asynchronously: https://msdn.microsoft.com/en-us/library/mt712557.aspx

How to conditionally include assets in the <head> with Angular

I am building a one-page Angular app. One of the views has content which depends on an external javascript library.
I don't want to include this external JS resource on every view of the site, just the single view which depends on it.
What is the best way to conditionally include blocks of code based on the current view?
If it's possible I'm hoping I can place in the something like this:
<script ng-if="view == 'view1'" type='text/javascript' src='http://webplayer.unity3d.com/download_webplayer-3.x/3.0/uo/UnityObject2.js'></script>
So you should include the library script in page.
Then within directive bound to elements it needs to act on do the initialization.
app.directive('unity', function () {
return {
link: function (scope, element, attrs) {
// element is jQuery object when jQuery.js is included in page
// before angular - or it is a jQLite object similar to a jQuery object
// config code
u.initPlugin(element[0], "web_ovar_beta.unity3d");
}
}
});
Usage in view:
<div unity></div>
This can easily be expanded to pass in attributes to the directive from controller
It is
<script ng-if="view == 'view1'" type='text/javascript' ng-src='http://webplayer.unity3d.com/download_webplayer-3.x/3.0/uo/UnityObject2.js'></script>
And it is something that you don't want to do. It doesn't guarantee that the script won't be loaded twice. Since the script is being used for particular view, make it one-time resolving service
app.factory('unityResolver', function ($document, $rootScope, $q, $timeout) {
var deferred = $q.defer();
var script = angular.element('<script>')[0];
script.src = '...';
script.async = true;
script.onload = script.onreadystatechange = function () {
if (['loaded', 'complete', undefined].indexOf(script.readyState) < 0)
return;
script.onload = script.onreadystatechange = null;
deferred.resolve();
$rootScope.$apply();
}
script.onerror = function onerror() {
script.onerror = null;
deferred.reject();
$rootScope.$apply();
};
$timeout(onerror, 20000);
$document.find('head').append(script);
return deferred.promise;
});
and use it in view/route resolve.
What your wanting to in turn is impossible.
You can get Javascript to include a javascript file if you want however if your using AJAX to load the content that is needed leave it in there it would be the same amount of time to load anyway. but once a file has been loaded into JavaScript it finished with you can remove the file from your HTML but the JavaScript engine still has the content of that file loaded in to it.
Try it in your browsers(chrome or FF with Firebug) inspector now:
open a new tab and go to about:blank then put the code below into the console
var include = (function(){
// the reference to the script
var theScript;
return function (filename, status){
if(status == 'on'){
// adding a script tag
var head = document.getElementsByTagName('head')[0];
theScript= document.createElement('script');
theScript.src = filename;
theScript.type = "text/javascript";
head.appendChild( theScript )
}else{
// removing it again
theScript.parentNode.removeChild( theScript );
}
}
})();
taken from Remove specific <script> tag in <head> tag by onclick event
then in your inspector's console
include("https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js", 'on')
now check Elements and you will see jQuery loaded in the pages head tag.
and type jQueryinto console and you will see function (a,b){return new n.fn.init(a,b)}
And then use this into your console
include("https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js", 'off')
and check your elements tab again the script tag will have gone.
however go back to console and type jQuery again and you will see function (a,b){return new n.fn.init(a,b)} as even though you have unloaded the file you can't remove the executed code from memory.
You have 2 options another framework page gets loaded into an iFrame or if you want to use Anagular to load the View in then just include the file in your head there is no point not having and then removing it as once it is loaded it's loaded

Embed a Google Map into a dynamically created div

I'm trying to dynamically generate a Google map when the user submits a form, but the map does not appear in its div when the form is submitted.
I tested to see if the map populates on merely on pageload and it does, but when trying to use a div that displays onclick the map does not show.
<form onsubmit="return false" action="">
<input type="text" id="addLocation"/>
<button onclick="findLocation()" id="btnLocation">Find Location</button>
</form>
<div id="mapContainer"></div>
This is the JavaScript:
function findLocation(){
var inputString = $('#addLocation').val();
$('#mapContainer').html('<div id="mapCanvas"></div>');
var apiRequest = $.ajax({
url: 'http://xxxxx.net/json/'+ inputString,
dataType: 'json',
type: 'get',
});
apiRequest.done(function(data){
var lat = data['latitude'];
var lng = data['longitude'];
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(lat, lng),
zoom: 8
};
map = new google.maps.Map(document.getElementById('mapCanvas'), mapOptions);
}
// from GMaps API docs
function loadScript() {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp' + '&callback=initialize';
document.body.appendChild(script);
}
window.onload = loadScript;
}); // ends .done statement
} // ends findLocation
It should be that when you click the Find Location button it will generate a map in the mapCanvas div but it does not.
I found out from the Google Maps API documentation that if you want to asynchronously load a map you have to use that loadScript function.
And yes, the map divs have widths and heights in the CSS, so that's not the problem. I think the problem is with the Javascript scopes. I'm doing something wrong with the order or placement of the calls, just not sure what.
First, it is not true that you have to load the Maps API asynchronously when you want to create a map dynamically. You can load the API either using the asynchronous method or with a conventional <script> tag. Loading the API does not create a map; it merely loads the code. A map is not created until you call new google.maps.Map().
So one easy solution would be to go back to a <script> tag to load the API, and simply call your initialize() function directly inside your ajax callback. (Or pull the code out of the initialize() function and just run it inline inside the callback.)
In fact, in your current code you are already loading the Maps API at page load time, with this line:
window.onload = loadScript;
That causes the loadScript() function to be called at page load time.
So you may as well just use a <script> tag to load the API, it's more or less the same thing you're doing now but simpler.
If you do want to load the Maps API dynamically, #sirfriday's comment is correct: your initialize function is not visible in the global scope, and it needs to be so the asynchronous API load can call it when ready.
You mentioned that "calling initialize didn't do it." - but you shouldn't be calling initialize() in this case, you should set window.initialize to be a reference to the function, e.g.:
window.initialize = initialize; // note no () so it doesn't call it here
Or change the function like this:
window.initialize = function() {
...
};
And also if you want to load the API dynamically, don't do it at onload time. Instead, call your loadScript() function inside your ajax callback. That will give you the right sequence of operations:
Page loads
User interacts with it and the ajax request starts
Ajax request completes
Maps API loads
Your initialize() function gets called

How can I know if Google Visualization is loaded

I'm showing Google's charts in some web pages. But I can't assure my clients will have network access to Google: a client computer will be in the same LAN as my web server (which can access Google), but I'm not guaranteed all the clients will have access outside the LAN.
I'd like to show data using Google Charts to those clients who can access it, and a plain HTML table to those who don't.
I tried setting a variable to false, and changing it to true in a method called when the Google Visualization API is loaded:
var canAccessGoogleVisualizationVar = false;
google.load('visualization', '1', {packages: ['corechart'], callback: canAccessGoogleVisualization});
function canAccessGoogleVisualization()
{
canAccessGoogleVisualizationVar = true;
}
But it doesn't seem to work.
How can I know from the client side if the Google Visualization is accesible or not?
Update: The code above didn't work because of the following code (which I didn't post before as I thought wasn't meaningful):
google.setOnLoadCallback(drawVisualization);
function drawVisualization()
{
// Check if Google Visualization is loaded
if (!canAccessGoogleVisualizationVar) {
alert('Can't access Google Visualization');
}
// The following code can be any of the samples from Google (see http://code.google.com/apis/ajax/playground/?type=visualization#pie_chart).
var data = new google.visualization.DataTable();
// Add columns and values to data
...
// Call new google.visualization.AnyChartBuilderFromTheAPI(<element>).draw(data);
}
I noticed my code didn't work because, if canAccessGoogleVisualizationVar == true, the if branch isn't taken, and if its false, the function drawVisualization() wouldn't have been executed.
So I took the if-test outside the function:
google.setOnLoadCallback(drawVisualization);
function drawVisualization()
{
// Any drawVisualization unchanged from the samples from Google (see http://code.google.com/apis/ajax/playground/?type=visualization#pie_chart).
}
// Check if Google Visualization is loaded at the end of this <script> </script>
if (!canAccessGoogleVisualizationVar) {
alert('Can't access Google Visualization');
}
</script>
But now it's not working because the evaluation if (!canAccessGoogleVisualizationVar) is being executed before the line google.load(?, ?, canAccessGoogleVisualization); calls the method canAccessGoogleVisualization().
How can I be sure I'm reading the value of canAccessGoogleVisualizationVar after having tried to execute the call to google.load(...);?
You can try
function canAccessGoogleVisualization()
{
if ((typeof google === 'undefined') || (typeof google.visualization === 'undefined')) {
return false;
}
else{
return true;
}
}

Categories

Resources