How to load google's api.js file in to my vue project

I am trying to integrate google calendar in to my vue project. I am following How to integrate Google Calendar? this and there I found this example https://jsfiddle.net/andrisv/nqwdymee/.

my vue file is like this,

<template>
  <div id="app">
    <div class='authentification'>
      <h2>VueJS + Google Calendar Example</h2>
      Authentification
      <button v-if='!authorized' @click="handleAuthClick">Sign In</button>
      <button v-if='authorized' @click="handleSignoutClick">Sign Out</button>
    </div>
    <hr>
    <button v-if='authorized' @click="getData">Get Data</button>
    <div class="item-container" v-if="authorized && items">
      <pre v-html="items"></pre>
    </div>
  </div>
</template>



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

<script>

  const CLIENT_ID = '';
  const API_KEY = '';
  const DISCOVERY_DOCS = ['https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest'];
  const SCOPES = 'https://www.googleapis.com/auth/calendar.readonly';
  export default {
    data() {
      return {
        items: undefined,
        api: undefined,
        authorized: false
      }
    },
    created() {
      this.api = gapi;
      this.handleClientLoad();
    },
    methods: {
      /**
       *  On load, called to load the auth2 library and API client library.
       */
      handleClientLoad() {
        this.api.load('client:auth2', this.initClient);
      },

      /**
       *  Initializes the API client library and sets up sign-in state
       *  listeners.
       */
      initClient() {
        let vm = this;
        vm.api.client.init({
          apiKey: API_KEY,
          clientId: CLIENT_ID,
          discoveryDocs: DISCOVERY_DOCS,
          scope: SCOPES
        }).then(_ => {
          // Listen for sign-in state changes.
          vm.api.auth2.getAuthInstance().isSignedIn.listen(vm.authorized);
        });
      },

      /**
       *  Sign in the user upon button click.
       */
      handleAuthClick(event) {
        Promise.resolve(this.api.auth2.getAuthInstance().signIn())
          .then(_ => {
            this.authorized = true;
          });
      },

      /**
       *  Sign out the user upon button click.
       */
      handleSignoutClick(event) {
        Promise.resolve(this.api.auth2.getAuthInstance().signOut())
          .then(_ => {
            this.authorized = false;
          });
      },

      /**
       * Print the summary and start datetime/date of the next ten events in
       * the authorized user's calendar. If no events are found an
       * appropriate message is printed.
       */
      getData() {
        let vm = this;

        vm.api.client.calendar.events.list({
          'calendarId': 'primary',
          'timeMin': (new Date()).toISOString(),
          'showDeleted': false,
          'singleEvents': true,
          'maxResults': 10,
          'orderBy': 'startTime'
        }).then(response => {
          vm.items = this.syntaxHighlight(response.result.items);
          console.log(vm.items);
        });
      },
      syntaxHighlight(json) {
        if (typeof json != 'string') {
          json = JSON.stringify(json, undefined, 2);
        }
        json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
        return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, match => {
          var cls = 'number';
          if (/^"/.test(match)) {
            if (/:$/.test(match)) {
              cls = 'key';
            } else {
              cls = 'string';
            }
          } else if (/true|false/.test(match)) {
            cls = 'boolean';
          } else if (/null/.test(match)) {
            cls = 'null';
          }
          return '<span class="' + cls + '">' + match + '</span>';
        });
      }
    }

  }
</script>

I am getting gapi is not defined error, so I loaded the https://apis.google.com/js/api.js as a script. But I am still getting the error.

You are assigning gapi while it’s not defined yet, most probably you are running into a race condition since you are loading the javascript asynchronously. Have you tried removing the async defer or assigning it on the mounted hook and/or using window.gapi instead?

this.api = window.gapi;
1 Like

You can’t use multiple <script> tags in a SFC. Either include the api within your index or inject it dynamically.

e.g.

const existingScript = document.getElementById('googleMaps');

if (!existingScript) return;

const script = document.createElement('script');
script.src = 'url';
script.id = 'libraryName';

document.body.appendChild(script);
2 Likes

Would you put this code in created hook?

Either created or mounted. It can be circumstantial, but yes, usually created is the ideal hook for something like this.

That said, if you do use it in a lifecycle hook, use a function to run the logic so it doesn’t return early if the script already exists.

1 Like