顯示具有 Firebase 標籤的文章。 顯示所有文章
顯示具有 Firebase 標籤的文章。 顯示所有文章

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();
  };
})
...

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

下一章,簡易聊天室


Ionic Framework 教學 - 6. 簡易註冊

承續上一章的應用,我們想來試做一個簡易聊天室,在做聊天室之前我們要先做使用者登入,對於使用者註冊和登入沒興趣的朋友可以跳至第八章。
要做 instant messaging 的話,我們必須要有一個即時同步訊息的後台,因為我們這個教學主要是做手機端的開發,所以我們就選用一些現有的即時通訊後台服務吧,比如說:

1. Layer: https://layer.com/
2. Quickblox: http://quickblox.com/
3. Firebase: https://www.firebase.com/
...

就決定是你了,Firebase,因為我印象中有 Angular-Fire 這種已經成熟的轉接器,可以讓 Firebase 跟 Ionic 中的 AngularJS 做良好的溝通,比較方便我們這次的教學。

Firebase 提供的登入方式基本上有一種簡是易登入,就是用帳號密碼,和另一種是社群登入,像是用 Facebook 的方式來登入, 由於 Firebase 官網已經有一篇 Ionic + Facebook 登入的教學,所以這個部分就留給同學朋友們自己練習,我們來實作一個簡易的帳號密碼登入。

首先,我們要安裝 bower ,這是目前 Ionic 還在用的 web package management tool 。

$ npm install -g bower

然後安裝 firebase & angular-fire

$ bower install firebase angularfire

我們要在 www/index.html 中引用 app.js 之前的地方引入這個兩個 javascript library

...
<!-- Firebase -->
<script src="lib/firebase/firebase.js"></script>

<!-- OR Firebase from CDN -->
<script src="https://cdn.firebase.com/js/client/2.3.0/firebase.js"></script>

<!-- AngularFire -->
<script src="lib/angularfire/dist/angularfire.min.js"></script>

<!-- OR AngularFire from CDN -->
<script src="https://cdn.firebase.com/libs/angularfire/1.1.3/angularfire.min.js"></script>

<!-- your app's js -->
<script src="js/app.js"></script>
...

接下來到 Firebase 申請一個帳號,並且建立一個 Project,下面會用到你的 Project ID。
申請完之後請到進入你的 Project 管理頁面的 Login & Auth ,並且勾選 Enable Email & Password Authentication 。



然後我們新增一個 www/js/services.js

var firebaseUrl = "https://your-project-id.firebaseio.com/";
angular.module('starter.services', [])
.factory("FirebaseRef", function($firebaseAuth) {
  return new Firebase(firebaseUrl);
})
.factory("Auth", function($firebaseAuth) {
  var usersRef = new Firebase(firebaseUrl+"users");
  return $firebaseAuth(usersRef);
});
your-project-id 請使用你申請的 Project ID
這裡我們定義了 FirebaseRef 和 Auth 兩個工廠,他們分別指向 Firebase 的資料庫和使用者工具,等下會用到。
回到 www/index.html 引用 services.js

...
<script src="js/app.js"></script>
<script src="js/services.js"></script>
...

然後修改 app.js 中 starter app 的依賴關係,增加 firebase 和 starter.services

angular.module('starter', ['ionic', 'firebase', 'starter.services', 'starter.controllers'])

接下來我們做一個註冊頁面 www/templates/signup.html

<ion-view view-title="註冊">
  <ion-content class="padding">
    <div class="list">
      <label class="item item-input">
        <span class="input-label">Email</span>
        <input ng-model="signupData.email" type="text">
      </label>
      <label class="item item-input">
        <span class="input-label">密碼</span>
        <input ng-model="signupData.password" type="password">
      </label>
      <label class="item item-input">
        <span class="input-label">顯示名稱</span>
        <input ng-model="signupData.displayName" type="text">
      </label>
      <button class="button button-full button-positive" ng-click="createUser()">建立</button>
    </div>
  </ion-content>
</ion-view>

這裡看到我們使用了 signupData 和 createUser ,接下來我們來定義這兩個東西。
我們增加一個 Controller

...
.controller('SignupCtrl', function($scope, $ionicLoading, FirebaseRef, Auth) {

  $scope.signupData = {};

  $scope.createUser = function () {
    var signupData = $scope.signupData;

    if (signupData && signupData.email && signupData.password && signupData.displayName) {
      $ionicLoading.show({
        template: '註冊中...'
      });

      Auth.$createUser({
        email: signupData.email,
        password: signupData.password
      }).then(function (userData) {
        console.log(userData);
        alert("註冊成功!");
        // add user info
        FirebaseRef.child("users").child(userData.uid).set({
          displayName: signupData.displayName
        });
        $ionicLoading.hide();
      }).catch(function (error) {
        alert("Error: " + error);
        $ionicLoading.hide();
      });
    } else {
      alert("請填寫所有資料");
    }
  }
})
...

接著定義路徑,修改 app.js

...
.state('app.signup', {
  url: '/signup',
  views: {
    'menuContent': {
      templateUrl: 'templates/signup.html',
      controller: 'SignupCtrl'
    }
  }
})
...

然後加入 menu.html

...
<ion-item menu-close href="#/app/signup">
  Signup
</ion-item>
...

完成了,然後就可以測試看看註冊功能了,在 Firebase console 也可以看到註冊的使用者資料。