4

I'm trying to use google OAuth api with Vue.js. I use and modify sample code which google supplys. But when I click "Authorize" button, console returns:

Uncaught TypeError: Cannot read property 'init' of undefined

at Vue$3.initClient (vueAuth.js:24)

at Vue$3.boundFn [as initClient] (vue.js:196)

at Vue$3.handleClientLoad (vueAuth.js:20)

at boundFn (vue.js:196)

at invoker (vue.js:2006)

at HTMLButtonElement.fn._withTask.fn._withTask (vue.js:1804)

Here is my code

index.html

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>管理画面</title>
</head>

<body>
    <p>Google Sheets API Quickstart</p>

    <!--Add buttons to initiate auth sequence and sign out-->
    <div id="app">
        <button @click="handleClientLoad">Authorize</button>
        {{ memberlist }}
    </div>

    <script async defer src="https://apis.google.com/js/api.js"></script>
    <script src="https://unpkg.com/vue"></script>
    <!-- vueAuth.js is my code -->
    <script src="vueAuth.js"></script>
</body>

</html>

vueAuth.js

// Client ID and API key from the Developer Console
const CLIENT_ID = '/*my client id */';

// Array of API discovery doc URLs for APIs used by the quickstart
const DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/sheets/v4/rest"];

// Authorization scopes required by the API; multiple scopes can be
// included, separated by spaces.
const SCOPES = "https://www.googleapis.com/auth/spreadsheets.readonly";

let vm = new Vue({
    el: '#app',

    data: {
        memberlist: ''
    },

    methods: {
        handleClientLoad: function () {
            gapi.load('client:auth2', this.initClient(this));
        },

        initClient: function (vue) {
            gapi.client.init({
                discoveryDocs: DISCOVERY_DOCS,
                clientId: CLIENT_ID,
                scope: SCOPES
            }).then(function () {
                // Listen for sign-in state changes.
                gapi.auth2.getAuthInstance().isSignedIn.listen(vue.updateSigninStatus);

                // Handle the initial sign-in state.
                vue.updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
                vue.handleAuthClick();
            });
        },

        updateSigninStatus: function (isSignedIn) {
            if (isSignedIn) {
                this.loadSheetsApi();
            } else {
                return;
            }
        },

        handleAuthClick: function (event) {
            gapi.auth2.getAuthInstance().signIn();
        },

        handleSignoutClick: function (event) {
            gapi.auth2.getAuthInstance().signOut();
        },

        loadSheetsApi: function () {
            var discoveryUrl =
                'https://sheets.googleapis.com/$discovery/rest?version=v4';
            gapi.client.load(discoveryUrl).then(this.listMajors);
        },

        listMajors: function () {
            gapi.client.sheets.spreadsheets.values.get({
                spreadsheetId: '/* my sheet id */',
                range: '/* target range */',
            }).then(function (response) {
                this.memberlist = response.result;
            })
        }
    }
})

I wonder why gapi.client.init is not available. How should I change my code to enable gapi?

3 Answers 3

2

Incase someone else is looking for this. This is how I did for my Add To Caledndar button

public/index.html add script in head

<head>
...
<script async defer src="https://apis.google.com/js/api.js"></script>
...
</head>

Template:

<ion-button @click="addToCalendar(item)">
  Add to Calendar <ion-icon :icon="calendarClearOutline"></ion-icon>
</ion-button>

Script:

// after imports
var gapi = window.gapi;
var CLIENT_ID = "_YOUR_CLIENT_ID_";
var API_KEY = "_YOUR_API_KEY_";
var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"];
var SCOPES = "https://www.googleapis.com/auth/calendar";

// in methods
    addToCalendar(event) {
      gapi.load("client:auth2", () => {
        console.log("gapi loaded", gapi.client);
    
        gapi.client.init({
          apiKey: API_KEY,
          clientId: CLIENT_ID,
          discoveryDocs: DISCOVERY_DOCS,
          scope: SCOPES
        }).then(() => {
          const gcEvent = {
            "summary": event.eventName,
            "location": event.venue,
            "start": {
              "dateTime": moment(event.start).utc().format("YYYY-MM-DDTHH:mm:ss.SSS[Z]"),
              "timeZone": "Africa/Johannesburg"
            },
            "end": {
              "dateTime": moment(event.end).utc().format("YYYY-MM-DDTHH:mm:ss.SSS[Z]"),
              "timeZone": "Africa/Johannesburg"
            },
            "reminders": {
              "useDefault": false,
              "overrides": [
                {"method": "email", "minutes": 24 * 60},
                {"method": "popup", "minutes": 10}
              ]
            }
          };
    
          var request = gapi.client.calendar.events.insert({
            'calendarId': 'primary',
            'resource': gcEvent,
          });
    
          // window object is undefined inside `execute`/
          const rootWindow = window;
    
          request.execute(gcEvent => {
            rootWindow.open(gcEvent.htmlLink);
          })
        })
      })
    }

Only use moment(event.start).utc().format("YYYY-MM-DDTHH:mm:ss.SSS[Z]") if your dates are not ISO

Grant Singleton's react tutorial helped alot.

Sign up to request clarification or add additional context in comments.

Comments

0

if your code depend on Gapi to work, you should not load it with async. the correct way to load it in your case is: <script src="https://apis.google.com/js/platform.js"></script>

Comments

-1

Try this for your script tag:

<script src="https://apis.google.com/js/client.js"></script>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.