Loading Google visualization API before/during page load - javascript

I am in a scenario where I need to display a google chart that is presentable and ready to display "before" the entire page loads. I've tried loading modules using the "ignoreWindowOnLoad" property, messing with different async call methodologies, and different versions of the API. I've also tried loading the scripts the following ways:
<script type="text/javascript" src='https://www.google.com/jsapi?autoload={"modules":[{"name":"visualization","version":"current","packages":["gauge"],"ignoreWindowOnLoad":true}]}'></script>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
google.load("visualization", "current", { packages: ["corechart"], ignoreWindowOnLoad: true});
The issue is that by the time the page loads and I try to draw the chart immediately after load, I get an exception:
Uncaught TypeError: Cannot read properties of undefined (reading 'arrayToDataTable')
at drawChart
I am using ASP.NET (not Core) as the backend, and using an SSR technology such as node.js isn't a viable option in my scenario, but if I can achieve SSR without a framework (if it's not an overkill solution) that may be acceptable. The chart loads fine if I call drawChart after the page fully loads.
Basically I'm looking for a way to ensure all visualization-related APIs are fully loaded before the page presents itself, so a single web request can pull the entire page and its contents, charts included. Any advice on how to achieve this would be greatly appreciated.

Related

How do I get gtag to send events automatically?

I am trying to add Google Analytics to our website using the gtag API.
Most of the events I am interested in happen in our PHP code, so I collect them in the session and inject them into the next page that renders. This allows me to handle eg. a login followed by a redirect to the home page.
However, when I try and load the page, none of the injected events are triggered.
I know the system works as I can bind a 'gtag' call to a button's onClick event and it works when I click it, but the automatic ones don't.
Here is an example file: test.php:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test Analytics</title>
</head>
<body>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script type="text/javascript">
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
// First attempt: Added to the datalayer with the rest of the config.
gtag('event', 'test-event-1');
// Second attempt: Added once everything has finished loading.
window.addEventListener('load', function () {
gtag('event', 'test-event-2');
})
</script>
<div class="container">
<h1>This is a test</h1>
<p>Click to trigger another event.</p>
<!-- Successful attempt: Event is triggered when run from a button event handler. -->
<button type="button"
onclick="gtag('event', 'test-event-3')">
Send Event
</button>
</div>
</body>
</html>
When I open this page with Firefox's Network tab running and click the button, I can see the following URLs sent:
GET "http://testapp.localhost:9009/analytics-test.html",
GET "https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX",
GET "http://testapp.localhost:9009/favicon.ico",
POST "https://region1.google-analytics.com/g/collect?v=2&tid=G-XXXXXXXXXX&gtm=2oeav0&_p=22328352&cid=1447481123.1666024506&ul=en-us&sr=1920x1080&_s=2&sid=1667482491&sct=17&seg=1&dl=http%3A%2F%2Ftestapp.localhost%2Fanalytics-test.html&dt=Test%20Analytics&en=user_engagement&_et=4840",
POST "https://region1.google-analytics.com/g/collect?v=2&tid=G-XXXXXXXXXX&gtm=2oeb20&_p=1344830813&cid=1447481123.1666024506&ul=en-us&sr=1920x1080&sid=1667482491&sct=17&seg=1&dl=http%3A%2F%2Ftestapp.localhost%2Fanalytics-test.html&dt=Test%20Analytics&_s=1",
POST "https://region1.google-analytics.com/g/collect?v=2&tid=G-XXXXXXXXXX&gtm=2oeb20&_p=1344830813&cid=1447481123.1666024506&ul=en-us&sr=1920x1080&_s=2&sid=1667482491&sct=17&seg=1&dl=http%3A%2F%2Ftestapp.localhost%2Fanalytics-test.html&dt=Test%20Analytics&en=test-event-3&_ee=1&_et=14263",
The 'en' is the event name, so you can see that only 'test-event-3' is sent to Google.
Please can you let me know how to change the code so that 'test-event-1' and 'test-event-2' are sent to Google as well?
Ok, many issues, but the most likely issue here is that your config happens before the library is loaded. Move your gtag config to the window load. Gtag may not be smart enough to retroactively inspect the dataLayer.
Another issue here is that you seem to be looking at the network tab. There's a way easier way to debug analytics. I suggest trying the Adswerve debugger extension. It shows your events in a much easier to look at presentation right in the console:
Good. Another issue here is that you're editing a php file. This kind of implementation is being frowned upon by the industry. There are many problems around implementing tracking in backend files. Implementing it in the template files would be a bit better, but still quite a poor design.
The proper implementation would be using GTM. GTM would handle retroactive datalayer pushes better, but you would also likely not need them with GTM. GTM is basically a script that is able to intelligently load other scripts whenever is required and translate business-like logic set via its UI to code. So with GTM, you just load it on every page and the rest of the tracking is done in its interface.
While doing gtag calls manually is a way to implement tracking, it's like making a site with no web-server, just quickly deploying your own backend network listeners that would spew html in response. A very odd and niche choice not making sense in vast majority of cases. Don't expect this kind of tracking to live long, to be appreciated, to be scalable or manageable or even to be very useful. Not a great legacy either.

Google Maps Places API: TypeError: autocomplete is undefined

Whenever I am trying to use the Google Maps API places library it gives me this error in the console of my browser:
TypeError: autocomplete is undefined
If I'm not mistaken, that means the places library couldn't load. As for the code, I had my own code but I also copypasted the code from the Places API tutorial(https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-addressform).
In my header I have these two lines included:
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=MY_KEY_HERE"></script>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?libraries=places&sensor=false"></script>
I also made sure Placis API, Google Maps JavaScript API v3 and Google Maps Geolocation API are all switched on in my Google APIs console.
I am not really sure what the problem is, besides the places library not loading. I should note I am working on a hidden subdomain, could that be the problem?
Thanks in Advance.
Please make sure you only load the maps file once (and you should always load the api via https, or with the active protocl):
<script type="text/javascript" src="//maps.googleapis.com/maps/api/js?key=MY_KEY_HERE&libraries=places&sensor=false"></script>
The subdomain should not be a problem, so you can work with it.

Lazyloading Google API not working

Here's the deal. I've tried a number of methods of lazy loading the Google Maps API JavaScript, and every time in do it, with any Lazy Loader I use, FireFox "blocks." It lazy loads just fine in Chrome.
What I mean by "blocks" is that the elements in the HTML don't display, and instead, the browsers spin trying to make a connection to download the Maps JavaScript.
The code follows. Put it in an HTML file and open it in your browser:
<html>
<head>
<script type="text/javascript" src="http://github.com/rgrove/lazyload/raw/master/lazyload.js"></script>
</head>
<body>
Open your console. Wait for "entering debugger..." message.<br />
You can't see me in FireFox, can you?
<script type="text/javascript">
// If I remove the `sensor` from the query string key and value,
// Google rejects the request and alert() does occur
LazyLoad.js("http://maps.google.com/maps/api/js?sensor=false", function() {
console.log("entering debugger...");
});
</script>
</body>
</html>
In Chrome, I see the "Open your console..." contents of the page, and the JavaScript is requested and downloaded, async, in the background.
In FireFox, the "Open your console..." contents never appear, and it hangs (status bar says "Read" from a Google DNS), never finishing or displaying the page contents.
Are you sure you need to write your own loader? What about using a previously tested implementation: Lazy Load
Are you trying to load Google Maps on demand? To load the API dynamically, pass a callback parameter, as shown on the Example
I think you'll need to rename your LazyLoad script, because it already exists. :) Speaking of which, it already exists, so why write it again?
If you just want to see how it's done, the source code is available.
Yeah, why reinvent the wheel. You seem to be using jQuery.
try this plugin:
Load image only when it is viewable?
Found a solution:
Check the URL:'http://maps.google.com/maps/api/js?sensor=true'
You would find main.js is being imported by it . A simple getScript for sensor=true will not give whole google object so next import also required.
var t=setTimeout(function(){
jQuery.getScript('http://maps.google.com/maps/api/js?sensor=true');
jQuery.getScript('http://maps.gstatic.com/intl/en_us/mapfiles/api-3/10/20/main.js');
},1000);
PS: Similar issue thread Lazy loading google map api

Can I inject google AJAX API autoload anywhere else than globally?

There is this issue I am struggling with. I know that the autoload for the google visualization geomap must be in the part of your document.
The thing is every time I reload some other pages in my application the google reloads everything and this I want to take out. So I tried taking the :
<script type="text/javascript" src="http://www.google.com/jsapi?autoload=%7B%22modules%22%3A%5B%7B%22name%22%3A%22visualization%22%2C%22version%22%3A%221%22%2C%22packages%22%3A%5B%22geomap%22%2C%22table%22%5D%7D%5D%7D"></script>
out of my global template and inject it when the page call happens. So to only load the google API when I need it so to keep loading times to an absolute low. I want to know if this is do-able and if the google autoload MUST exist in the global at all times.
I am using Prototype Javascript framework and here is my code to inject the autoload :
var element = new Element('script', {
src: "http://www.google.com/jsapi?autoload=%7B%22modules%22%3A%5B%7B%22name%22%3A%22visualization%22%2C%22version%22%3A%221%22%2C%22packages%22%3A%5B%22geomap%22%2C%22table%22%5D%7D%5D%7D",
type: 'text/javascript'
});
$$('head')[0].appendChild(element);
This keeps it out of the rest of the site but doesn't work at all. Am I thinking about this wrong or is there some possibility of me only loading the API in one place and not everywhere.
Thank you
It seems like if you do it in the template of the view you are using it works fine. Every time the template gets rendered it refreshes the page resulting in the Google API code loading.

How to correctly load dependent JavaScript files

I am trying to extent a website page that displays google maps with the LabeledMarker. Google Maps API defines a class called GMarker which is extended by the LabeledMarker.
The problem is, I cant seem to load the LabeledMarker script properly, i.e. after the Google API loads and I get the 'GMarker not defined' error.
What is the correct way to specify the scripts in such cases?
I am using ASP.NET's ClientScript.RegisterClientScriptInclude() first for the google API url and then immediately after with the LabeledMarker script file.
The initial google API loader writes further script links that load the actual GMarker class. Shouldnt all those scripts be executed before the next script block(LabeledMarker script) is processed.
I have checked the generated HTML and the script blocks are emitted in the right order.
<script src="google api url" type="text/javascript"></script>
...
(the above scripts uses document.write() etc to append further script blocks/sources)
...
<script src="Scripts/LabeledMarker.js" type="text/javascript"></script>
Once again, the LabeledMarker.js seems to get executed before the google API finishes loading.
I think that is the problem. I was calling google.load() in the body.onload which happened after loading the scripts. Resolved by emitting script tag for the LabeledMarker from within the onload handler.

Categories