I have (finally) noticed one of the biggest problems I have. The GAPI client is often not initialised, but hangs just after loading. This is my setup, I'll mark where it hangs:
window.gapi.load('client:auth2', _ => {
console.log('loaded GAPI')
// hangs here
window.gapi.client.init(gapiConfig)
.then(_ => {
console.log('initialised GAPI')
window.GAPIiniOK = true
gapi.auth2.getAuthInstance().isSignedIn
.listen(store.dispatch('gapiAuthListener'))
// Not required anymore if global auth listener does its job!
store.dispatch('user/updateAuthStatus')
.then(_ => {
resolve()
})
}).catch(error => {
dispatch('authenticationError', {error, note: 'error during gapi initialisation'})
reject()
})
})
It hangs right where I wrote the comment. But the load worked, but the client.init is not launched.
I even added a catch statement, but it doesn't get launched.
Does anyone have any idea why?
@mesqueeb we observed this issue when injecting the api.js script asynchronously, in some browsers. We're not sure yet what the root cause of the bug is, but in the meantime you can use a setTimeout before the gapi.client.init call or not injecting dynamically the api.js script.
@TMSCH
I found out what the problem is. Right before window.gapi.client.init(gapiConfig) I logged window.gapi.client and it seems it's still undefined at that point.
Is there a better way that you know of to load the script in a Single Page application besides:
window.gapi.load('client:auth2', _ => {
window.gapi.client.init(gapiConfig)
})
I need to be sure the script is loaded before I do window.gapi.client.init(gapiConfig)
@mesqueeb that's the proper way to do it, as I mentioned, there's a bug in the loader currently that can create this issue sometimes. A setTimeout(init, 1) seems to workaround the bug.
@TMSCH
Thank you for the advice.
However this did not resolve the issue for me.
I'm not sure how I can use the GAPI js client with this bug. Also adding the script just to the html at the header didn't work for me.
I saw in the one-tap signin documentation they have something to check if the script properly loaded:
window.onGoogleYoloLoad = (googleyolo) => {
// The 'googleyolo' object is ready for use.
}
Maybe the GAPI js script could get something similar?
This is my updated code with setTimeout()
function loadAndInitGAPI() {
return new Promise((resolve, reject) => {
let script = document.createElement('script')
script.type = 'text/javascript'
script.src = 'https://apis.google.com/js/api.js'
script.onload = e => {
window.gapi.load('client:auth2', _ => {
console.log('loaded GAPI')
function initGAPI(){
if (!window.gapi || window.gapi.client){ return reject('no window.gapi.client') }
window.gapi.client.init(gapiConfig)
.then(_ => {
console.log('initialised GAPI')
window.GAPIiniOK = true
// Global auth listener
gapi.auth2.getAuthInstance().isSignedIn
.listen(store.dispatch('gapiAuthListener'))
// Not required anymore if global auth listener does its job!
store.dispatch('user/updateAuthStatus')
.then(_ => {
resolve()
})
}).catch(error => {
dispatch('authenticationError', {error, note: 'error during gapi initialisation'})
return reject(error)
})
}
setTimeout(initGAPI, 10)
})
}
document.getElementsByTagName('head')[0].appendChild(script)
})
}
There seems to be a typo:
if (!window.gapi || !window.gapi.client)
it lacks the ! in the test for window.gapi.client.
@TMSCH
Thanks for now this solved my problem. I leave it up to you to decide if you want to close this issue or not.
Let's keep it open. We have an internal bug opened for this too.
Did you make any progress with fixing the bug?
This is still happening, is there any way to detect library is loaded? Something like @mesqueeb suggested?
window.onGoogleScriptLoad = () => {
// Script is ready for use.
}
Since I got the update e-mail from @milenkovic, this is how I fixed it (maybe this will help you too @Neseke):
First include the script (I'm not sure this is the right script, but this will work for the one you use):
<script type="text/javascript" src="https://apis.google.com/js/api:client.js?onLoad=onGoogleScriptLoaded"></script>
Then you can use the snippet @mesqueeb and @milenkovic shared:
window.onGoogleScriptLoad = () => {
console.log('The google script has really loaded, cool!');
}
When you see "The google script has really loaded, cool!" in the console, you know the script has loaded and can safely use gapi or window.gapi.
Thanks @roelofjan-elsinga, that's exactly what I needed.
I'm still facing this issue, sometimes it does not load...
When gapi is loaded correctly we have this behavior:

When gapi does not load correctly we have this behavior:

The call to cb=gapi.loaded_1 is missing.
I'm loading the platform.js using this function:
public async loadGoogleApi(): Promise<void> {
try {
if (!this.$window.gapi) {
const libLoaded = this.$q.defer();
const node = document.createElement('script');
node.src = 'https://apis.google.com/js/platform.js';
node.type = 'text/javascript';
node.onload = libLoaded.resolve;
node.onerror = libLoaded.reject;
node.async = true;
node.charset = 'utf-8';
document.getElementsByTagName('head')[0].appendChild(node);
await libLoaded.promise;
}
if (!this.$window.gapi) throw new Error('Failed to load google api');
if (!this.$window.gapi.signin2) {
const signin2Loaded = this.$q.defer();
this.$window.gapi.load('signin2', {
callback: function () { signin2Loaded.resolve(true) },
onerror: function () { signin2Loaded.reject('gapi.signin2 failed to load') },
timeout: 5000, // 5 seconds.
ontimeout: function () { signin2Loaded.reject('gapi.signin2 load timeout reached') }
});
await signin2Loaded.promise;
}
if (!this.$window.gapi.auth2) {
const auth2Loaded = this.$q.defer();
this.$window.gapi.load('auth2', {
callback: function () { auth2Loaded.resolve(true) },
onerror: function () { auth2Loaded.reject('gapi.auth2 failed to load') },
timeout: 5000, // 5 seconds.
ontimeout: function () { auth2Loaded.reject('gapi.auth2 load timeout reached') }
});
await auth2Loaded.promise;
}
} catch (ex) {
HandleError.exception(ex);
}
}
Even using the onLoad=onGoogleScriptLoaded like the example above, I face the same issue.
I've tried loading the script sync/async, same issue for both.
After some debugging, the gapi is always loaded inside the window object, the problem is the google button that sometimes is not rendered.
The work around is to manually render the button like that:
public renderGoogleLoginButton(buttonID: string): void {
try {
if (!buttonID) throw new Error('Google buttonID is NULL');
this.loadGoogleApi().then(() => {
this.$window.gapi.signin2.render(buttonID,
{
'scope': 'email profile',
//width': 200,
//'height': 50,
//'longtitle': false,
'theme': 'dark',
'onsuccess': this.handleGoogleLogin.bind(this),
'onfailure': this.handleGoogleError.bind(this)
});
}).catch((ex) => {
HandleError.exception(ex);
});
} catch (ex) {
HandleError.exception(ex);
}
}
As @gustavomassa I experience fluctuating behaviour - sometimes the onLoad callback is invoked and sometimes it's not.
As a workaround I've done this which is a complete hack and not acceptable in an app where performance is somewhat a priority but for the project I'm working on here it should be alright for now.
window.gapiWasLoaded = () => {
if (!gapiWasLoaded) {
gapiWasLoaded = true;
ReactDOM.render(<App />, document.getElementById('root'));
}
};
setTimeout(() => {
// @ts-ignore
window.gapiWasLoaded();
}, 1000);
I am experiencing the same. I am trying to use gapi from React. Just out of curiosity, is any work going into fixing this?
I am experiencing the same. I am trying to use gapi from React. Just out of curiosity, is any work going into fixing this?
Have you tried my solution in this post yet? This solved the problem for me. It's not a GAPI problem, but an implementation problem.
I've tried many variations on that theme. Here's a link to the current code try and a website preview. Slowing it down with my browser dev tools makes the problem more likely to occur.
The problem appears to be that the gapi.client.init doesn't always result in running either the fulfilled or the rejected callbacks provide to the then method. Is there any way to detect that situation? FWIW, this only seems to happen when I increase he latency for my network connection with the dev tools.
So, I moved the <script> tags for gapi to the bottom of the <body>, and it seems to be working. I am not sure why that seems to be making a difference, but it does.
Here's a link to the commit: https://github.com/ymatyt/ymatyt_site/commit/f031a628e613494baba30a80e625e84e7f6ebf0f
I came up with a solution that makes use of both @mesqueeb and @roelofjan-elsinga solutions. It grantees that gapiLoaded is initialized before loading Google Api and it's safe to call gapi inside it.
window.gapiLoaded= function() {
//you can safely call gapi here
};
(function(d, s, id) {
var js,
p = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {
return;
}
js = d.createElement(s);
js.id = id;
js.src =
'https://apis.google.com/js/platform.js?onload=gapiLoaded';
p.parentNode.insertBefore(js, p);
})(document, 'script', 'google-api-js');
@mesqueeb we observed this issue when injecting the
api.jsscript asynchronously, in some browsers. We're not sure yet what the root cause of the bug is, but in the meantime you can use asetTimeoutbefore thegapi.client.initcall or not injecting dynamically theapi.jsscript.
Works. Thanks @TMSCH
If you are like me and need to dispatch an action after gapi is loaded, the snippet below did the trick:
async function loadGAPI() {
let loaded = false;
let errorMessage = null;
const gapiClientLoad = new Promise((resolve, reject) => {
setTimeout(() => {
window.gapi.load('client:auth2', async () => {
try {
await window.gapi.client.init(GAPI_CONFIG);
resolve({ errorMessage, loaded: true });
} catch (gapiErrorResponse) {
errorMessage = gapiErrorResponse.error.message;
reject({ error: errorMessage, loaded });
}
})
}, 1000);
});
return gapiClientLoad;
}
Calling loadGAPI resolves or rejects a value.
Hello everybody,
I'am facing issue with google calendar. The issue is "when user1 is connecting his google calendar with our website account and then logout his account from our website only and then user2 connect his google calendar with his account of our website and then logout. So what happening is, now if user1 is login to his account then he is not able to access his google calendar and the error image link is shown below".
(https://user-images.githubusercontent.com/38031527/88327203-730e2b00-cd44-11ea-86d2-23bea41cf789.jpeg)
.
Please help me out, what should I need to do to make this process work. I'm stuck with this issue from long time. I must be missing something.
Most helpful comment
Did you make any progress with fixing the bug?