2015年11月19日

Ionic Framework 教學 - 7. 簡易登入和登出

繼續上一章的教學,我們來做 Firebase 的使用者登入。
這篇也會提到 LocalStorage 的基本用法。
首先我們建立一個使用者資訊頁面 www/templates/profile.html

<ion-view view-title="使用者資訊">
  <ion-content>
    <div class="list">
      <div class="item">
        Name: {{currentUser.displayName}}
      </div>
    </div>
  </ion-content>
</ion-view>

定義一個 Controller ProfileCtrl

...
.controller('ProfileCtrl', function() {
})
...

然後加入 app.js route
...
.state('app.profile', {
  url: '/profile',
  views: {
    'menuContent': {
      templateUrl: 'templates/profile.html',
      controller: 'ProfileCtrl'
    }
  }
})
...

修改 menu.html 增加 Profile 項目

<ion-item menu-close href="#/app/profile">
  Profile
</ion-item>

連到 http://localhost:8100/#/app/profile 會發現這個頁面目前沒有正確的內容,因為 currentUser 還沒有定義。
現在我們來實作登入功能。
第一步我們直接修改 www/templates/login.html

<ion-modal-view>
  <ion-header-bar>
    <h1 class="title">登入</h1>
    <div class="buttons">
      <button class="button button-clear" ng-click="closeLogin()">關閉</button>
    </div>
  </ion-header-bar>
  <ion-content>
    <form ng-submit="doLogin()">
      <div class="list">
        <label class="item item-input">
          <span class="input-label">Email</span>
          <input type="text" ng-model="loginData.email">
        </label>
        <label class="item item-input">
          <span class="input-label">Password</span>
          <input type="password" ng-model="loginData.password">
        </label>
        <label class="item">
          <button class="button button-block button-positive" type="submit">登入</button>
        </label>
      </div>
    </form>
  </ion-content>
</ion-modal-view>

注意這裡我們改用了 loginData 方便使用上了解。
然後我們在 controllers.js 定義 loginData 和 doLogin()

...
.controller('AppCtrl', function($scope, $ionicModal, $timeout, $rootScope, $state, $ionicLoading, 
  FirebaseRef, Auth) {

  // 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) {
  //});

  // Form data for the login modal
  $scope.loginData = {};

  // Create the login modal that we will use later
  $ionicModal.fromTemplateUrl('templates/login.html', {
    scope: $scope
  }).then(function(modal) {
    $scope.modal = modal;
  });

  // Triggered in the login modal to close it
  $scope.closeLogin = function() {
    $scope.modal.hide();
  };

  // Open the login modal
  $scope.login = function() {
    $scope.modal.show();
  };

  $scope.loginData = {};

  // Perform the login action when the user submits the login form
  $scope.doLogin = function() {
    console.log($scope.loginData);
    var loginData = $scope.loginData;

    if (loginData && loginData.email && loginData.password) {
      $ionicLoading.show({
        template: '登入中...'
      });
      Auth.$authWithPassword({
        email: loginData.email,
        password: loginData.password
      }).then(function (authData) {
        console.log(authData);
        FirebaseRef.child("users").child(authData.uid).once('value', function (snapshot) {
          var val = snapshot.val();
          console.log(val);
          window.localStorage.currentUser = JSON.stringify(val);
          $scope.$apply(function () {
            $rootScope.currentUser = val;
          });
        }, function(err) {
          console.error(err);
        });
        $ionicLoading.hide();
        $scope.closeLogin();
        $state.go('app.profile');
      }).catch(function (error) {
        alert("登入失敗 " + error.message);
        $ionicLoading.hide();
      });
    } else {
      alert("輸入 Email 和 Password")
    }
  };
})
...

這裡可以看到使用者登入後,我們把使用者名稱儲存到 window.localStorage.currentUser 中,這個 window.localStorage 儲存內容必須要使用字串,所以我們把用 JSON.stringify 把使用者資訊從 object 轉換成字串。
window.localStorage 的內容可能被同樣機器上的其他程序看到和使用,所以不建議儲存使用者的秘密資訊,使用者資訊建議儲存在 server 。

我們修改 app.js 的起始執行內容,把 currentUser 的內容代入到 currentUser ,這樣各個 View 都可以使用了。
...
.run(function($ionicPlatform, $rootScope) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if (window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
      cordova.plugins.Keyboard.disableScroll(true);

    }
    if (window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }
    
    console.log(JSON.parse(window.localStorage.currentUser));
    $rootScope.currentUser = JSON.parse(window.localStorage.currentUser) || null;

  });
})
...

接下來實作登出功能。
修改 profile.html ,增加登出按鈕。

<ion-view view-title="使用者資訊">
  <ion-content>
    <div class="list">
      <div class="item">
        Name: {{currentUser.displayName}}
      </div>
    </div>
    <button class="button button-full button-positive" ng-click="logout()">登出</button>
  </ion-content>
</ion-view>

然後修改 ProfileCtrl
...
.controller('ProfileCtrl', function($scope, $rootScope, Auth) {
  $scope.logout = function () {
    $rootScope.currentUser = null;
    window.localStorage.currentUser = null;
    Auth.$unauth();
  };
})
...

現在可以試試看登入和登出了。

下一章,簡易聊天室