Office UI FabricとAngularJSでToDoアプリを作る

[Office Fabric UI](https://github.com/OfficeDev/Office-UI-Fabric)の基本的なUI部品の使い方を調べていますが、ある程度実用的なアプリを作るとどんな感じになるのか試してみたくなりました。

そこで今回は[Office Fabric UI](https://github.com/OfficeDev/Office-UI-Fabric)と[AngularJS](https://angularjs.org/)を使ってToDoアプリを作ってみました。以下のURLからアプリを試すことができます。

 * ToDoアプリ(Office UI Fabric+AngularJS)
   * http://furandon_pig.bitbucket.org/sample/officeui/todo_app.html

![img00.png](https://qiita-image-store.s3.amazonaws.com/0/61137/51520726-f8db-aeaa-0348-f52e2595e473.png)

# ToDoアプリの簡単な使い方

まずはToDoアプリの簡単な使い方。と言ってもToDoアプリの最低限の機能を実装してみただけです。

ToDoの追加・編集、優先度の変更が行えます。

![img04.png](https://qiita-image-store.s3.amazonaws.com/0/61137/0c20c949-4f66-fc47-9944-b4355213d2ad.png)

ToDoデータはlocal storageに保存しています。不要になったら「設定」ダイアログからlocal storageのToDoデータのみ削除できます。

![img02.png](https://qiita-image-store.s3.amazonaws.com/0/61137/6e7769e2-d985-ed88-9af0-d9223d76c95d.png)

# Office UI FabricとAngularJSの組み合わせ

Twitter BootstrapとAngularJSを組み合わせるのは良くあるパターンだと思いますが、ここでは
Office UI FabricとAngularJSを組み合わせる例を解説してみます。

## ToDoデータの一覧表示

Office UI Fabricには、ListとListItemというUI部品が用意されています。以下のような表示のUIになります(OfficeUIをビルドした際のサンプルアプリの画面です)。

![img005.png](https://qiita-image-store.s3.amazonaws.com/0/61137/2e942f16-b93c-4372-e7cc-279700067c07.png)

これを使ってToDoデータを表示すると見栄えが良さそうです。

## ListItemへの独自スタイルの適用

が、このListItemは「選択(チェックボックスをON)したアイテムに対して何らかの操作をする」というUIで、ListItemの領域をクリックするとチェックボックスがONになってしまいます。ToDoでは「チェックボックスのみをON/OFFにしたい」ので、このままでは用途に合いません。

そのため、ListItemに独自のスタイルを適用します。"is-selectable"というスタイルでListItemのチェックボックスが描画されているので、今回のToDoアプリ用に"is-x-selectable"という独自スタイルを定義します。これでマウスオーバ時にはListItem項目の背景色が薄い灰色になり、別途用意したチェックボックスのON/OFFでToDoの完了/未完了が管理できるようになります。

```css
.ms-ListItem.is-x-selectable:hover {
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
  display: inline-block;
  background-color: #eaeaea; /* 薄い灰色 */
};
```

ToDoの項目表示は以下のような感じです。

![img006.png](https://qiita-image-store.s3.amazonaws.com/0/61137/49ea3546-2ad0-81a9-d528-7f757bccb1f9.png)

## グリッドレイアウトとListItemの表示

ListItemを用いて以下のようなToDoデータを表示します。このJSONデータを配列の形で管理することでToDoデータとしています。

```js
{
  id   : id++,
  task : "悲しい時こそ涙の声を聞く",
  prio : 0,
  memo : "HAPPYぱLUCKY",
  done : false,
  showToDo : true,
  sample : true,
}
```

今回のToDoアプリはAngularJSを使用しているので、ng-repeatディレクティブで上記のToDoデータを表示します。単にUIフレームワークが異なるだけで、(あたり前ですが)Twitter BootstrapとAngularJSを組み合わせて使うケースと変わらないですね。

```html
<div class="ms-Grid">
  <div class="ms-Grid-row">
    <div class="ms-Grid-col ms-u-sm6 ms-u-md4 ms-u-lg12">
      <div class="sample-wrapper">
        <ul class="ms-List ms-List--grid">
          <div ng-repeat="todo in todos | filter: { 'showToDo': true }">
            <!-- ListItemには独自スタイル(is-x-selectable)を適用する -->
            <div class="ms-ListItem is-unread is-x-selectable">
              <!-- ここからToDoの1項目 -->
              <div class="ms-ChoiceField">
                <!--- XXX ラベルの無いチェックボックスを作成している -->
                <input id="data{{todo.id}}" class="ms-ChoiceField-input" type="checkbox" ng-checked="{{isChecked(todo.id)}}" ng-click="check(todo.id)">
                <label for="data{{todo.id}}" class="ms-ChoiceField-field">
                </label>
                <!-- ToDoの概要はlabelタグで表示 -->
                <label class="ms-Label {{getPriorityColor(todo.id)}}" style="{{getTaskDecoration(todo.id)}}">
                  {{todo.task}}
                </label>
              </div>
              ...
              <!-- ToDoの1項目ここまで -->
            </div>
          </div> <!-- ng-repeatに対応するタグ -->
        </ul>
      </div>
    </div>
  </div>
</div>
```

ListItemの表示は以下のようなグリッドレイアウト上で行っています。ToDoデータの個数が多くなるとグリッドの幅を超えてしまいそうな気がしますが、List,ListItem側でケアしてくれるので表示がおかしくなることはありません。

```html
<div class="ms-Grid">
  <div class="ms-Grid-row">
    <div class="ms-Grid-col ms-u-sm6 ms-u-md4 ms-u-lg12">
      ...
    </div>
  </div>
</div>
```

こんな感じで、複数行に渡ってToDoデータを表示してくれます。

![img03.png](https://qiita-image-store.s3.amazonaws.com/0/61137/f4f0892a-7976-4e89-dfaa-c67768fd1b9b.png)

# まとめ

Office UI FabricとAngularJSでToDoアプリを作成してみました。やはり少し手の込んだアプリを作ろうとすると、AngularJSなどのMVCフレームワークが便利に思えてきます(AngularJSのお作法から外れると、途端に噴き出す謎のエラー！的な現象にはまだ馴染めませんが...)。

UIフレームワークでは、用意されている機能から外れるようなことをすると途端に面倒くさい感じになったりするのですが、今回のListItemをToDoデータの表示に使うケースのように、独自にスタイルを定義することで上手いこと対応できそうです。独自にUI部品を追加するような試みも面白そうです。