1

I am trying to make login with google in vue by following google document and everything worked but i cant access method inside attachClickHandler.

new Vue({
    el: '#loginModal',
    data: { ...
    },
    methods: {
        gInit: function() {
            gapi.load('auth2', function() {
                auth2 = gapi.auth2.init({
                    client_id: 'MY-Client-id.apps.googleusercontent.com',
                    cookiepolicy: 'single_host_origin',
                    //scope: 'additional_scope'
                });
                auth2.attachClickHandler(document.getElementById('googleBtn'), {},
                    function(googleUser) {
                        const profile = googleUser.getBasicProfile();
                        const gplusObj = {
                            name: profile.getName(),
                            email: profile.getEmail(),
                            provider: 'google',
                            image: profile.getImageUrl(),
                            provider_user_id: profile.getId()
                        };

                        this.socialLogin(gplusObj);
                    },
                    function(error) {
                        alert(JSON.stringify(error, undefined, 2));
                    });
            });
        },
        socialLogin: function(data) {
            axios.post(`${this.api}/api/sociallogin`, data)
                .then(res => {
                    console.log(res);
                }).catch(err => {
                    console.log(err);
                });
        },
    },
    mounted: function() {
        this.gInit();
    }

})

Here calling a function socialLogin() inside attachClickHandler() is giving error this.socialLogin is not a function is not defined. Why this is not working?

4
  • 2
    Please fix the indentation. Commented Apr 30, 2018 at 8:32
  • 1
    Can you use ES6 features? Commented Apr 30, 2018 at 8:33
  • yes i can @sandrooco. Commented Apr 30, 2018 at 8:34
  • Ok check my edited answer - I left out the config stuff to have a good overview.. Commented Apr 30, 2018 at 8:38

2 Answers 2

2

It's because the this.socialLogin call is located in a callback function. This function creates a new context so this changes and won't be your component anymore. Use arrow functions. They won't change this.

Edit: Change your code like this:

gInit() {
    gapi.load('auth2', () => {
        ...
        auth2.attachClickHandler(document.getElementById('googleBtn'), {}, (googleUser) => {
            ...
            this.socialLogin(gplusObj);
        }, (error) => {
            alert(JSON.stringify(error, undefined, 2));
        });
    });
},

More on that topic: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions, see "No separate this".

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

Comments

0

Because you didn't save this,try :

new Vue({
  el: '#loginModal',
  data: { ...
  },
  methods: {
    gInit: function() {
      let self = this // new added
      gapi.load('auth2', function() {
        auth2 = gapi.auth2.init({
          client_id: 'MY-Client-id.apps.googleusercontent.com',
          cookiepolicy: 'single_host_origin',
          //scope: 'additional_scope'
        });
        auth2.attachClickHandler(document.getElementById('googleBtn'), {},
          function(googleUser) {
            const profile = googleUser.getBasicProfile();
            const gplusObj = {
              name: profile.getName(),
              email: profile.getEmail(),
              provider: 'google',
              image: profile.getImageUrl(),
              provider_user_id: profile.getId()
            };
            console.log(e);
            self.socialLogin(gplusObj); //updated
          },
          function(error) {
            alert(JSON.stringify(error, undefined, 2));
          });
      });
    },
    socialLogin: function(data) {
      axios.post(`${this.api}/api/sociallogin`, data)
        .then(res => {
          console.log(res);
        }).catch(err => {
          console.log(err);
        });
    },
  },
  mounted: function() {
    this.gInit();
  }

})

this wouldn't be passed automatically and you should already know this before learning vue.

Also,you can use arrow function to avoid this being changed:

new Vue({
  el: '#loginModal',
  data: { ...
  },
  methods: {
    gInit: function() {
      gapi.load('auth2', function() {
        auth2 = gapi.auth2.init({
          client_id: 'MY-Client-id.apps.googleusercontent.com',
          cookiepolicy: 'single_host_origin',
          //scope: 'additional_scope'
        });
        auth2.attachClickHandler(document.getElementById('googleBtn'), {},
          (googleUser) => { //updated
            const profile = googleUser.getBasicProfile();
            const gplusObj = {
              name: profile.getName(),
              email: profile.getEmail(),
              provider: 'google',
              image: profile.getImageUrl(),
              provider_user_id: profile.getId()
            };
            console.log(e);
            this.socialLogin(gplusObj);
          },
          function(error) {
            alert(JSON.stringify(error, undefined, 2));
          });
      });
    },
    socialLogin: function(data) {
      axios.post(`${this.api}/api/sociallogin`, data)
        .then(res => {
          console.log(res);
        }).catch(err => {
          console.log(err);
        });
    },
  },
  mounted: function() {
    this.gInit();
  }

})

2 Comments

This is an old-school workaround and bad practice since we can use arrow functions.
@sandrooco,You are partial right,i just added,please check.I didn't think it is a bad practice though it is not convenient enough

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.