2015年11月19日

Ionic Framework 教學 - 9. 簡易聊天室設定

第八章

我們來做一個設定頁面,讓我們在聊天室講話的時候可以有一個暱稱。

請大家建立一個設定頁面 www/templates/settings.html

<ion-view view-title="設定">
  <ion-content>
    <ion-list>

      <ion-item class="item item-input-inset">
        <label class="item-input-wrapper">
          <input type="text" placeholder="Nickname" ng-model="currentUser.displayName">
        </label>
        <button class="button button-small" ng-click="saveName()">
          Save
        </button>
      </ion-item>

      <label class="item item-input item-select">
        <div class="input-label">
          Color
        </div>
        <select class="" 
          ng-model="settings.color" 
          ng-options="c.value as c.name for c in colors" 
          ng-change="showColor()">
      </label>

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

這裡使用了 currentUser.displayName 來當做顯示名稱,saveName()函式來儲存名稱,使用 select 來選擇顏色,當顏色被選擇之後會觸發 ng-change ,就可以用 showColor()來看看顏色變數被改變了嗎。
然後我們來定義這些功能,請增加一個 SettingsCtrl

.controller('SettingsCtrl', function($scope, $rootScope) {

  //gloabl variable, local storage
  $scope.currentUser = JSON.parse(window.localStorage.currentUser) || {};

  //global variable, temporary
  $rootScope.settings = $rootScope.settings || {};

  //https://en.wikipedia.org/wiki/Web_colors
  $scope.colors = [
    {
      name: 'Navy',
      value: '#000080',
    },
    {
      name: 'Crimson',
      value: '#DC143C'
    },
    {
      name: 'DimGray',
      value: '#696969'
    }
  ];

  $scope.showColor = function() {
    console.log($rootScope.settings);
  };

  $scope.saveName = function() {
    alert($scope.currentUser.displayName + ' saved!');
    window.localStorage.currentUser = JSON.stringify($scope.currentUser);
  };

})

這裡我們有兩種全域變數的寫法,一種是存在 local storage 一種是存在 $rootScope 裡面,等下我們來看看這兩種用法的差別。
注意這裡,在 window.localStorage 中必須要用字串的形式儲存,所以我們用 JSON.stringify 來把物件轉換成字串。讀取的時候則用 JSON.parse 來把字串轉換成物件。
然後我們在 www/js/app.js 增加一個 route state 來處理 settings

.state('app.settings', {
  url: '/settings',
  views: {
    'menuContent': {
      templateUrl: 'templates/settings.html',
      controller: 'SettingsCtrl'
    }
  }
})
然後我們在 www/templates/messages.html 增加一個按鈕可以連到設定頁面,把這個按鈕增加到 ion-view 的裡面,ion-content的上面。

  <ion-nav-buttons side="secondary">
    <button ui-sref="app.settings"
      class="button button-icon icon ion-gear-a">
    </button>
  </ion-nav-buttons>

這是一個 header button , secondary 代表他在次要位置。
然後我們修改 www/templates/messages.html 的內容,增加了顯示名稱和顏色,完成後大概成為這樣。
<ion-view view-title="{{chatroom.name}}">
  <ion-nav-buttons side="secondary">
    <button ui-sref="app.settings"
      class="button button-icon icon ion-gear-a">
    </button>
  </ion-nav-buttons>
  <ion-content>
    <ion-list>
      <ion-item class="item-input-inset">
        <label class="item-input-wrapper">
          <input type="text" placeholder="New Message" ng-model="newMessage.content">
        </label>
        <button class="button button-small" ng-click="sendMessage()">
          Send
        </button>
      </ion-item>
      <ion-item class="item-text-wrap" ng-repeat="message in messages.slice().reverse()">
        <strong class="" ng-show="message.displayName">{{message.displayName}}:</strong>
        <span style="color:{{message.color || '#000'}}">
          {{message.content}}
        </span>
      </ion-item>
    </ion-list>
  </ion-content>
</ion-view>

然後我們回頭修改 MessagesCtrl 來讓送出的 message 夾帶 displayName 和 color 的資訊。
.controller('MessagesCtrl', function($scope, $state, $rootScope, ChatroomService, MessageService) {

  console.log('Chatroom Id: ', $state.params.roomId);

  //get current chatroom from roomId
  $scope.chatroom = ChatroomService.get($state.params.roomId) || {};
  console.log('This is chatroom: ', $scope.chatroom.name);

  //get messages in this chatroom
  $scope.messages = MessageService.all($state.params.roomId);

  //global variable, localStorage
  var currentUser = JSON.parse(window.localStorage.currentUser) || {};
  $rootScope.settings = $rootScope.settings || {};
  console.log($rootScope.settings);

  $scope.newMessage = {};

  $scope.sendMessage = function () {
    $scope.newMessage.color = $rootScope.settings.color || '#000';
    $scope.newMessage.displayName = currentUser.displayName;
    console.log('New message: ', $scope.newMessage);

    //send message
    MessageService.send($scope.newMessage).then(function() {
      $scope.newMessage.content = '';
    });
  };

})

如果你重新載入程式,你會發現 color 的設定不見了,但是你的暱稱還保留著。

藉由這個練習,我們可以知道 localStorage 和 $rootScope 的身為全域變數的方便強大和危險,強大是在任何地方修改這個變數都有效,危險也是因為你無法確定這個變數會被什麼函式在任何什麼地方修改了,造成不是你預期的效果。

練習題:使用者設定顏色之後,要去聊天室打字才能知道是什麼顏色,這不是一個好的使用者體驗,如何在選擇完顏色的時候讓使用者知道是什麼顏色呢?