How to use $q service in angular js for login?

2019-08-13 19:08发布

问题:

I am new in angular js. i have making ionic app useing angular js and ionic framework, This is my service.js file.

In this i have create LoginService for Login control. but its not working.

angular.module('starter.services', ['ngCookies'])

.service('LoginService', function ($q, $http, $cookies, $rootScope) {
    return {
        loginUser: function (name, pw) {
            var deferred = $q.defer();
            var promise = deferred.promise;
            var user_data = $http.get("http://vanhalterenwatersport.nl/van/webservice/appc/login.php");
            user_data.then(function (result) {
                var user = result.data;
                log(user);
                console.log($rootScope.session);
            })
            function log(user) {
                var i;
                var isloggedin = false;
                for (i = 0; i < user.length; i++) {
                    if (name == user[i].user_email && pw == user[i].password) {
                        isloggedin = true;
                        id = user[i].iduser;
                        $rootScope.session = id;
                        break;
                    } 
                }
                if (isloggedin) {
                    deferred.resolve('Welcome ' + name + '!');
                } else {
                    deferred.reject('Wrong credentials.');
                }
            }
            promise.success = function (fn) {
                promise.then(fn);
                return promise;
            }
            promise.error = function (fn) {
                promise.then(null, fn);
                return promise;
            }
            return promise;
        }
    }
})

This is my controllers.js file

 angular.module('starter.controllers', ['ngRoute','ngCookies'])

    .controller('AppCtrl', function($scope, $ionicModal, $timeout) {

      // With the new view caching in Ionic, Controllers are only called
      // when they are recreated or on app start, instead of every page change.
      // To listen for when this page is active (for example, to refresh data),
      // listen for the $ionicView.enter event:
      //$scope.$on('$ionicView.enter', function(e) {
      //});

    })

    .controller('LoginCtrl', function($scope, LoginService, $ionicPopup, $state, $cookies, $rootScope) {
        $scope.data = {};

        $scope.create = function () {
            $state.go('signup');
        }

        $scope.forgot = function () {
            $state.go('forgotpassword');
        }

        $scope.login = function () {
            console.log($scope.data.user_email);
            LoginService.loginUser($scope.data.user_email, $scope.data.password).success(function (data) {
                var wat = $rootScope.session;
                console.log(wat);
                $state.go('app.dashboard');
            }).error(function (data) {
                var alertPopup = $ionicPopup.alert({
                    title: 'Login failed!',
                    template: 'Please check your credentials!'
                });
            });
        }

    })

This is my login.html

<ion-view view-title="Login" hide-nav-bar="true" name="login-view">

  <ion-content ng-controller="LoginCtrl">
  <div class="bar-header padding">
  <h1 class="title vanimage"><img src='img/logo.png'></h1>
</div>


      <div class="list">
        <label class="item item-input">
          <span class="input-label">Username</span>
          <input type="text" name="username" ng-model="data.user_email">
        </label>
        <label class="item item-input">
          <span class="input-label">Password</span>
          <input type="password" name="password" ng-model="data.password">
        </label>
        <label class="item">
           <button class="button button-block button-positive"  ng-click="login()">Log in</button>
        </label>
      </div>



    <div class="padding">

    <button class="button button-block  button-positive" ng-click="create()">Registeer hier</button>

     <button class="button button-block button-positive" ng-click="forgot()">Password Vergeten?</button>
     </div>



  </ion-content>
</ion-view>

回答1:

You should put the auth logic in the backend, more secure and efficent.

This is the code I use for login in a service of a Ionic app:

login: function( loginEmail, loginPassword ) {
    var deferred = $q.defer();
    $http({
        method: 'POST',
        url: backend_url + '/auth',
        // --- change content-type if needed (default = application/json)
        // headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        data: { email: loginEmail, password: loginPassword }
    }).then( function( result ) {
        if( typeof result.data.token !== 'undefined' ) deferred.resolve( { token: result.data.token } );
        else deferred.reject( { error: 'invalid_response' } );
    }, function( result ) {
        if( typeof result.data.error !== 'undefined' ) deferred.reject( { error: result.data.error, status: result.status } );
        else deferred.reject( { error: 'invalid_login' } );
    });
    return deferred.promise;
},


回答2:

$http always return a promice, so if you want to do it correctly in your service, using $q try smth like this:

var fn = function (method, url) {
    var deferred = $q.defer();
     $http(method, url)
       .success(function (data) {
            deferred.resolve(data);
         }
         .error(function (data, status) {
              deferred.reject({
                   data: data,
                   status: status
                 });
           });
            return deferred.promise;
}

And if you want to call this function you should do

fn(method, url)
 .then(
    function(result){
    ... do if ok (resolve)
    },
    function( error) {
    ... do if error (reject) 
     }
) 


回答3:

You forgot to return the deferred object in your service.. This probably results in the following error:

Cannot read property then of undefined

I've made a basic example to demonstrate the $q service:

Controller - Login function

$scope.login = function login() {

LoginService.loginuser($scope.data.user_email, $scope.data.password)
    .then(function onLoginSuccess(response) {
        // response should contain 'success' data
        $state.go('app.dashboard');
    }, function onLoginFailed(error) {
        var alertPopup = $ionicPopup.aler({
            title: 'Login failed!',
            template: 'Please check your credentials!'
        });
    });
}

Service

var API = {};

function loginUser(email, password) {

    var deferred = $q.defer();

    $http.get("http://vanhalterenwatersport.nl/van/webservice/appc/login.php")
        .then(function onUserLoggedIn(response) {
            deferred.resolve(response);
        }, function onLoginFailed(error) {
            deffered.reject(error);
        });

        // Make sure to return your promise!
        return deferred.promise;
}

API.loginUser = loginUser;

Sidenote: You're also using GET in your login function. For this type of operations, you would typically POST a data-object to your back-end which on his turn will return you a result.