Google calendar export application error - javascript

I am writing a short application for exporting events to Google calendar. (Events are obtained from code processing information from my website.) However, when I click the button, the script I wrote is giving me a strange error. The error I get the first time I click the button is: Uncaught TypeError: Cannot call method 'setApiKey' of undefined. However, the second time I click the button without refreshing the page, the error disappears and the code runs perfectly.
Here is my code, as you can see I defined the api key before setting it:
var exportCalendarToGoogle = function() {
var clientId = '38247913478902437.google#user...';
var scope = 'https://www.googleapis.com/auth/calendar';
var apiKey = 'JDKLSFDIOP109321403AJSL';
var withGApi = function() {
gapi.client.setApiKey(apiKey);
gapi.auth.init(checkAuth);
}
var checkAuth = function() {
gapi.auth.authorize({client_id: clientId, scope: scope, immediate: false}, handleAuthResult);
}
var handleAuthResult = function(authResult) {
if(authResult) {
gapi.client.load("calendar", "v3", exportCalendar);
} else {
alert("Authentication failed: please enter correct login information.");
}
}
//functions to format the calendar json input to Google calendar...

Sounds like gapi has not been fully loaded
http://code.google.com/p/google-api-javascript-client/wiki/GettingStarted
There are two callbacks:
1) In the URL to load the gapi code:
<script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
2) You can also supply a callback function that will let you know when a specific API has loaded:
gapi.client.load('plus', 'v1', function() { console.log('loaded.'); });
I think your problem is 1)

Related

How to unattach gapi- auth2.attachClickHandler on a condtion

I am using the google auth for client (gapi) in my code and I have this onLoad event:
<script>
function onLoad() {
gapi.load('auth2', function () {
auth2 = gapi.auth2.init();
var additionalParams = {};
auth2.attachClickHandler('signinButton', additionalParams, onSignIn, onSignInFailure);
//auth2.attachClickHandler('btnGoRegister', additionalParams, onRegisterIn, onSignInFailure);
});
}
</script>
As you can see above, I am attaching a click handler for my Signin button which works fine. The other part is that for the Register button, I have to enable/disable the button and associated events on a condition which works fine for other auth (like FB).
The problem here is that once the attachClickHandler is invoked, then I am unable to in unattach it so that if my condition is not true, then the Google popup screen should not be invoked (currently if it is invoked once then it will always be shown irrespective of my condition).
Does anyone have any idea on how to achieve this?
Thanks
It looks like Google Sign-In API does not support a method for un-attaching the click handler. On the other hand they have a disconnect() & signOut() function, but I don't think it achieves what you want.
One solution is to add an additional button which handles the decision of loading the Google Auth API and preforms the click on signinButton. The signinButton can be hidden using css.
I don't have the api up & running but the code should look something like:
const GoogleSignInButton = 'signinButton';
const GoogleDecisionGateSignInButton = 'googleDecisionGateButton';
function onLoad() {
document.getElementById(GoogleDecisionGateSignInButton).addEventListener("click", GoogleDecisionGateButton);
}
function GoogleDecisionGateButton() {
if (ShouldUseGoogleSigninButton()) {
LoadGoogleAuthApi();
ClickGoogleAuthButton();
}
}
function ShouldUseGoogleSigninButton() {
return true; // Replace this with logic to decided if user should use Google API Auth button or not.
}
function LoadGoogleAuthApi() {
gapi.load('auth2', function () {
auth2 = gapi.auth2.init();
var additionalParams = {};
auth2.attachClickHandler(GoogleSignInButton, additionalParams, onSignIn, onSignInFailure);
//auth2.attachClickHandler('btnGoRegister', additionalParams, onRegisterIn, onSignInFailure);
});
}
function ClickGoogleAuthButton() {
document.getElementById(GoogleSignInButton).click()
}
HTML:
<button id="signinButton" type="button"></button>
<button id="googleDecisionGateButton" type="button"></button>
CSS:
#signinButton { display: none !important }

GoogleAuth.signOut() does not work

I have a google sign-in button on my page, using gapi.signin2.render to render the button (https://developers.google.com/identity/sign-in/web/reference#gapisignin2renderid-options).
However it ALWAYS renders as signed-in, despite calling GoogleAuth.signOut(). In fact I can actually call GoogleAuth.signOut() and immediatly check GoogleAuth.isSignedIn.get() to check the state and returns as true.
Does anyone know how to fix this? My sign-out code is as follows:
var GoogleAuth = gapi.auth2.getAuthInstance();
GoogleAuth.signOut().then(() => {
var status = GoogleAuth.isSignedIn.get(); //ALWAYS TRUE!!!!
alert('IP.common.oAuth.signOut: signin status: ' + status);
});
This should be work fine. Delete then(this.props.onLogoutSuccess)) if you don't need it.
signOut() {
if (window.gapi) {
const auth2 = window.gapi.auth2.getAuthInstance()
if (auth2 != null) {
auth2.signOut().then(auth2.disconnect().then(this.props.onLogoutSuccess))
}
}
}
Very nice lib, if you wanna learn how to work with Google API https://github.com/anthonyjgrove/react-google-login. Yes it's react, but methods should be similar, I think.

LinkedIn Javascript SDK Fail To Return Positions

I am trying to use LinkedIn Javascript SDK to retrieve some information including positions fields. I copied the code from the internet but it seems something is not working quite right because the code i copied doesn't return positions fields as supposed to be. I tried on ApiGee it worked fine and it returned the list of positions as i am expected. If you look at the code below , do you think i missed something or the javascript SDK itself has some buggy problems ?
<script type="text/javascript" src="//platform.linkedin.com/in.js">
api_key: yourapikey
authorize: true
onLoad: onLoad
</script>
<script type="text/javascript">
function onLoad() {
IN.Event.on(IN, "auth", getProfileData);
}
// Handle the successful return from the API call
function onSuccess(data) {
alert(JSON.stringify(data));
}
// Handle an error response from the API call
function onError(error) {
console.log(error);
}
// Use the API call wrapper to share content on LinkedIn
function getProfileData() {
//alert(IN.ENV.auth.oauth_token);
IN.API.Raw("/people/~:(id,positions)?format=json").result(onSuccess).error(onError);
}
</script>
Return result is showing this :
{"id":"wQplQQjzLa","positions":{"_total":0}}
Hello there #John Hadikusumo,
Well, I do understand that this reply would be happening only a year later but, I too was facing some problems with the linkedin api integration especially when it came to the "positions" object values.
Apparently when I got an error, what it meant was that the user who is using his linkedin profile to authorize, that particular user has not initiated his experience details and thus has no value;
To circumvent this particular problem here is what I had done which had helped me:
function onLinkedInLoad() {
IN.Event.on(IN, "auth", getProfileData);
}
function onSuccess(data) {
console.log(data);
}
function onError(error) {
console.log(error);
}
function getProfileData(){
IN.API.Profile("me").fields(["firstName","lastName", "email-address", "positions"]).result(function(data) {
var profileData = data.values[0];
var profileFName = profileData.firstName;
var profileLName = profileData.lastName;
//this is the piece of code that helped me out;
//might work for you as well;
if(data.values[0].positions._total == "0" || data.values[0].positions._total == 0 || data.values[0].positions._total == undefined) {
console.log("Error on position details");
var profileCName = "Details Are Undefined";
}
else {
var profileCName = profileData.positions.values["0"].company.name;
}
var profileEName = profileData.emailAddress;
//and other logic/code continues...
});
}
So I do hope this helps you out. Do let me know if you had faced any other errors, I could use some help in case I would need to improve my existing code.
Cheers and Have a nice day.

Detect closing the "Request for Permission" window (Google Account login)

I'm implementing a Google Account login on my website and I've reached the following problem: when the user chooses to login using his/her Google Account, Google's Request for Permission popup window opens and, if the user closes it, I have no way of detecting this in any way.
Here's the relevant code, using GoogleAuth.attachClickHandler method:
gapi.load('auth2', function() {
var auth2 = gapi.auth2.init({
client_id: 'my-client-id.apps.googleusercontent.com',
cookiepolicy: 'single_host_origin',
});
auth2.attachClickHandler(button, {},
function(googleUser) {
successHandler(googleUser);
}, function(error) {
failureHandler(error);
});
});
If the user presses Accept, successHandler is called and if the user presses Cancel, failureHanlder is called. However, if the user simply closes this window, nothing happens and my website keeps waiting for some callback.
Is there any way to detect this, other than adding a timeout?
So, I guess I came up with a (very ugly) solution. Answers are still welcome, if someone knows of a better way.
Basically, I replace the default window.open function with my own and monitor if a Google window opens and then periodically check if it closed:
Function.prototype.isNative = function() {
return this.toString().indexOf('[native code]') > -1;
}
function registerGoogleTimeoutCallback() {
if (window.open.isNative()) {
var originalOpen = window.open;
window.open = function(URL, name, specs, replace) {
var newWindow = originalOpen(URL, name, specs, replace);
if (URL.indexOf('https://accounts.google.com/') === 0) {
var interval = setInterval(function() {
if (newWindow.closed) {
clearInterval(interval);
setTimeout(function() {
$(window).trigger('googleWindowClosed');
}, 2000);
}
}, 1000);
}
return newWindow;
}
} else {
throw 'window.open already replaced'
}
}
This way, I use $(window).on('googleWindowClosed', callback) to register a failure callback and also $(window).off('googleWindowClosed') to unregister it, in case of success.

Refresh Vs. Reload (Cannot call method 'authorize' of undefined) GAPI

I have a simple gapi (Google Drive) app that I want to connect to. There something strange that happening. I have the sample from the demo. https://developers.google.com/drive/web/quickstart/quickstart-js
//Nothing happens
<script src="static/javascript/libs/client.js?onload=Drive._handleClientLoad"></script>
//Works on reload but not refresh
// (reload) "successfully authorization"
// (refresh) "Uncaught TypeError: Cannot call method 'authorize' of undefined"
<script src="static/javascript/libs/client.js" onload="Drive._handleClientLoad"></script>
Javascript:
var Drive = {
_CLIENT_ID: '61183508825.apps.googleusercontent.com',
_SCOPES: 'https://www.googleapis.com/auth/drive.file',
_rootid: null,
authorised: false,
_auth: function() {
gapi.auth.authorize({
'client_id': Drive._CLIENT_ID, 'scope': Drive._SCOPES, 'immediate': true
},Drive._handleAuthResult);
},
_handleClientLoad: function() {
window.setTimeout(Drive._auth, 1);
},
_handleAuthResult: function(authResult) {
if (authResult && !authResult.error) {
// Access token has been successfully retrieved, requests can be sent to the API.
Drive._validAuth();
} else {
// No access token could be retrieved, show the button to start the authorization flow.
Drive._invalidAuth();
}
},
_invalidAuth: function(){
Drive.authorised = false;
console.log("invalid authorization");
},
_validAuth: function(){
Drive.authorised = true;
console.log("successfully authorization");
},
}
Why is this happening?
The html should be as per your first snippet. You need to figure out why "nothing happens". It might be some limitation in the Google lib that prevents it from calling into a module. Try replacing Drive._handleClientLoad with a global function that in turn calls your module. Perhaps sprinkle a few console.log's or debugger's in to see what is being executed and what isn't.
Not sure why but I can't call Drive._handleClientLoad from the ..client.js?onload= function, so creating a public one like bellow and it works.
function handleClientLoad() {
window.setTimeout(Drive._checkAuth, 1);
}
// ..client.js?onload=handleClientLoad

Categories