3

I'm trying to build a mobile application on NativeScript where I've created a class for authorization which has a login() function which has following codes:

export default class NitsEditorAuth {
    //Finding logged-in user.
    isLoggedIn() {
        return store.getters.access_token ? true : false;
    }
    //For Login user
    login(user) {
        const postData = {
            grant_type: 'password',
            username: user.email,
            password: user.password,
            client_id: clientId,
            client_secret: clientSecret,
            scope: '',
            provider: provider
        }
        const authUser = {}
        axios.post(authUrl, postData).then(response => {
            if(response.status === 200)
            {
                authUser.access_token = response.data.access_token;
                authUser.refresh_token = response.data.refresh_token;
                axios.get(apiUrl + 'user/log', {headers: getHeader()}).then(response => {
                    if(response.status === 200){
                        authUser.email = response.data.email;
                        authUser.first_name = response.data.first_name;
                        authUser.last_name = response.data.last_name;
                        authUser.userRole = response.data.role;
                        store.commit('save', authUser);
                        return new Promise(function (resolve, reject) {
                            resolve('Login successful')
                        });
                    }
                })
            }
        })
        .catch((err) => {
            if(err.response.status === 401){
//                this.error = err.response.data.message
                return new Promise(function (resolve, reject) {
                    reject('Validation error')
                });
            }
            else
                return new Promise(function (resolve, reject) {
                    reject('Something went wrong')
                });
        })
    }

}

I included this very class in my main.js file as:

const nitsEditorAuth = new NitsEditorAuth();
Vue.prototype.$nitsEditorAuth = nitsEditorAuth;

And I'm calling this function inside my Vue-methods like:

login() {
    this.$nitsEditorAuth
        .login(this.user)
        .then(() => {
           this.processing = false;
           this.$navigateTo(Home, { clearHistory: true });
        })
        .catch(() => {
           this.processing = false;
           this.alert(
              "Unfortunately we could not find your account."                   
           );
        });
},

But I'm getting error stating that:

TypeError: Cannot read property 'then' of undefined. Frame: function:'login'

Help me out with this. Thanks.

Nitish Kumar
  • 6,054
  • 21
  • 82
  • 148
  • 3
    `login` method is returning **nothing** in `NitsEditorAuth`. – briosheje Mar 15 '19 at 11:31
  • @briosheje you mean `login` method in `NitsEditorAuth` class? – Nitish Kumar Mar 15 '19 at 11:32
  • Yes, the error is being thrown here in my opinion: `this.$nitsEditorAuth .login(this.user)` <--- here, .login returns `undefined` because your `axios` call is not returned, nothing more than that, really, you were very close to the solution. Just add `return` before `axios` and it should work as expected, despite I would still return a `Promise` instead (custom promise) for design purposes. – briosheje Mar 15 '19 at 11:33

5 Answers5

4

Easy fix would be just wrap a promise out side the function. And remove the rest. For example.

javascript node.js vue.js nativescript nativescript-vue
I'm trying to build a mobile application on NativeScript where I've created a class for authorization which has a login() function which has following codes:

export default class NitsEditorAuth {
    //Finding logged-in user.
    isLoggedIn() {
        return store.getters.access_token ? true : false;
    }
    //For Login user
    login(user) {
        const postData = {
            grant_type: 'password',
            username: user.email,
            password: user.password,
            client_id: clientId,
            client_secret: clientSecret,
            scope: '',
            provider: provider
        }
return new Promise(function (resolve, reject) {
        const authUser = {}
        axios.post(authUrl, postData).then(response => {
            if(response.status === 200)
            {
                authUser.access_token = response.data.access_token;
                authUser.refresh_token = response.data.refresh_token;
                axios.get(apiUrl + 'user/log', {headers: getHeader()}).then(response => {
                    if(response.status === 200){
                        authUser.email = response.data.email;
                        authUser.first_name = response.data.first_name;
                        authUser.last_name = response.data.last_name;
                        authUser.userRole = response.data.role;
                        store.commit('save', authUser);

                            resolve('Login successful')

                    }
                })
            }
        })
        .catch((err) => {
            if(err.response.status === 401){
//                this.error = err.response.data.message

                    reject('Validation error')

            }
            else

                    reject('Something went wrong')
        })
})
    }

Subhendu Kundu
  • 3,618
  • 6
  • 26
  • 57
  • For design purposes, to me, this is the cleanest solution. – briosheje Mar 15 '19 at 11:38
  • Yup, by doing this you are making sure where ever this function is called, tell it to wait, it's returned a promise. Once it resolved it will call the then method or catch if rejected. – Subhendu Kundu Mar 15 '19 at 11:41
2

You broke the promise chain by not returning the promise that is returned by axios in your login method (and the inner call to axios.get(apiUrl + 'user/log',

return axios.post(authUrl...

Return values from then handlers of Promises are chained, see this example:

// a here points to a promise that will resolve to "Just the 2 of us"
const a = Promise.resolve(1)
  .then(val => val + val)
  .then(val => `Just the ${val} of us`);

a.then(val => console.log(val))
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
  • But I have one more axios call after the authUrl is called. Is it fine to call on first one? – Nitish Kumar Mar 15 '19 at 11:34
  • @NitishKumar add return there as well. Otherwise, wrap everything inside a `Promise` block and call resolve on the master Promise only. – briosheje Mar 15 '19 at 11:35
  • They are nested thens, what will be returned is what you return from the innermost then, you have to make sure all the returns get chained – Ruan Mendes Mar 15 '19 at 11:35
1

In your login function, you have returned a promise within axios post call which is async in nature. Your function which should return a promise is not returning anything. So you can refer the code below.

login() {
  let promise = new Promise(function(resolve, reject) {

  // your post call (dummy data) 
  axios.post(authUrl, postData).then(response => {
        if(response.status === 200) {
           resolve('foo');
        } else {
           reject('Login successful');
        }
  });

  return promise;
}

Hope this helps.

Rohini
  • 244
  • 1
  • 8
1

You can use async/await pattern.

async login(user) {
  const postData = {
    grant_type: 'password',
    username: user.email,
    password: user.password,
    client_id: clientId,
    client_secret: clientSecret,
    scope: '',
    provider: provider
  };

  const authUser = {};
  try {
    const postResponse = await axios.post(authUrl, postData);
    if (postResponse.status === 200) {
      authUser.access_token = response.data.access_token;
      authUser.refresh_token = response.data.refresh_token;
      const response = await axios.get(apiUrl + 'user/log', {headers: getHeader()});
      if (response.status === 200) {
        authUser.email = response.data.email;
        authUser.first_name = response.data.first_name;
        authUser.last_name = response.data.last_name;
        authUser.userRole = response.data.role;
        store.commit('save', authUser);
        return 'Login successful';
      }
    }

    return 'Validation error';
  }  
  catch(err) {
    if (err.response.status === 401){
      return 'Validation error';
    }
    return 'Something went wrong';
  }
}
Alex
  • 1,373
  • 8
  • 15
0
yourMethodName() {
    return new Promise((resolve, reject) => {
        this.authorizationService.yourAuthorizationMethod().subscribe({
            next: response => resolve(response),
            error: error => reject(error)
        });
    })
}
this.yourMethodName().then((response:any) => {
    //Your logic
}).catch(error => {
    this.errorMessage = error;
})

In yourMethodName we will call the service and this method returns a promise. Hence while calling youMethodName function we use then and catch for response and error.

PaperinFlames
  • 642
  • 5
  • 6