JavaScriptフレームワークのデファクトスタンダード「AngularJS」
アプリにおけるJavaScriptの守備範囲が広くなると、おのずと、アプリの共通的な基盤を提供するフレームワークの存在は、欠かせないものです。実際、JavaScriptでは、近年、Backbone.js、Knockout.js、Ember.jsなど、あまたのフレームワークがしのぎを削っていますが、Visual Studio 2015では、その中でも特によく利用されているAngularJS/Reactを標準でサポートしており、より効率よく開発を進められるようになりました。
本稿でも、AngularJSを利用して、あらかじめ用意しておいたWeb API経由で記事情報を編集/参照してみましょう。なお、AngularJSの基本的な構文については、別稿『AngularJSではじめるJavaScriptフレームワーク開発スタイル』などを参照してください。
[1]テンプレートを作成する
ASP.NET 5では、エンドユーザーに対して開示すべきリソースは/wwwrootフォルダーに配置するのでした。[新しい項目の追加]ダイアログから「HTMLページ」を選択し、ファイル名は「index.html」としておきます。
ページの骨組みが生成されますので、以下のように編集しておきます。マークアップを編集する際に、ng-~ではじまるAngularJSに対しても、インテリセンスが働き、適切なディレクティブを候補表示する点に注目してください。
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="utf-8" />
<title></title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular-messages.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular-resource.min.js"></script>
<script src="scripts/app.js"></script>
</head>
<body ng-controller="MyController">
<table class="table">
<tr>
<th>タイトル</th><th>公開日</th><th>PV</th><th>編集/削除</th>
</tr>
<!--取得した記事情報articlesを一覧表示-->
<tr ng-repeat="article in articles">
<td><a ng-href="{{article.Url}}">{{article.Title}}</a></td>
<td>{{article.Published | date}}</td>
<td>{{article.PageView}}</td>
<td>
<button ng-click="onedit(article.Id)">編集</button>
<button ng-click="ondelete(article.Id)">削除</button>
</td>
</tr>
</table>
<hr />
<form name="myForm" novalidate ...>
<div>
<label for="url">URL:</label><br />
<!--必須/URLフォーマット検証-->
<input id="url" name="url" type="url" size="50"
required ng-model="article.Url" />
<span ng-messages="myForm.url.$error">
<span ng-message="required">入力は必須です。</span>
<span ng-message="url">正しいURLを入力してください。</span>
</span>
</div>
<div>
<label for="title">タイトル:</label><br />
<!--必須/文字列長検証(5~150文字)-->
<input id="title" name="title" type="text" size="50"
ng-model="article.Title"
required ng-minlength="5" ng-maxlength="150" />
<span ng-messages="myForm.title.$error">
<span ng-message="required">入力は必須です。</span>
<span ng-message="minlength, maxlength">
5~150文字の範囲で入力してください。</span>
</span>
</div>
<div>
<label for="published">公開日:</label><br />
<!--必須/日付型検証-->
<input id="published" name="published" type="date"
required ng-model="article.Published" />
<span ng-messages="myForm.published.$error">
<span ng-message="required">入力は必須です。</span>
<span ng-message="date">正しい日付形式で入力してください。</span>
</span>
</div>
<div>
<label for="pageview">ページビュー:</label><br />
<!--必須/最小値検証(0以上)-->
<input id="pageview" name="pageview" type="number"
required min="0" ng-model="article.PageView" />
<span ng-messages="myForm.pageview.$error">
<span ng-message="required">入力は必須です。</span>
<span ng-message="number, min">正数で入力してください。</span>
</span>
</div>
<div>
<button ng-click="oninsert()">登録</button>
<button ng-click="onupdate()">更新</button>
</div>
</form>
</body>
</html>
テンプレートの後半は記事情報を編集するためのフォームです。HTML5でおなじみのrequired/min/max属性はもちろん、AngularJSのng-minlength/ng-maxlength/ng-patterなどの属性(ディレクティブ)を利用することで、検証機能を備えたリッチな入力フォームを、ごくシンプルなコードで実装できます。
Contents Delivery Network
前項では、説明の便宜上、Bowerを使ってAngularJSをインストールしてみました。しかし、AngularJSのようにCDN(Contents Delivery Network)で提供されているならば、サンプルのように、まずはそちらを優先して利用すべきです。というのも、CDNを利用することで、複数のサイトで同じライブラリを利用している場合、ブラウザキャッシュが働きますので、トラフィックそのものを抑えられる可能性があるからです。
[2]コントローラーを作成する
テンプレートで利用している記事情報、記事取得/更新のためのロジックは、コントローラーで準備します(注2)。
JavaScriptのソースコードは、先ほどGruntのuglifyタスクで設定した/Scriptsフォルダーの配下に配置します。[新しい項目の追加]ダイアログから「$scope を使用する AngularJS Controller」を選択し、ファイル名はここでは「controller.js」としておきます。
AngularJSを利用したコントローラーの骨組みが生成されますので、以下のように編集しておきましょう。
注2
本来であれば、ビジネスロジックの記述はサービスに委ねるべきですが、本稿では簡単化のためにコントローラーでまとめて記述しています。
(function () {
'use strict';
angular.module('myApp', ['ngResource', 'ngMessages'])
.controller('MyController', ['$scope', '$resource', function ($scope, $resource) {
// (2)すべての記事情報をバインド
var databind = function () {
$scope.articles = Article.query();
};
// (1)指定されたエンドポイントをもとにResourceオブジェクトを生成
var Article = $resource(
'/api/Articles/:id',
{ id: '@Id' },
{ ...中略...
update: { method: 'PUT' }
}
);
databind();
// (3)[登録]ボタンでフォームの内容を保存
$scope.oninsert = function () {
delete $scope.article.Id;
Article.save(
$scope.article,
function() {
databind();
});
};
// [編集]ボタンで該当する行の記事情報をフォームに表示
$scope.onedit = function (id) {
$scope.article = Article.get({ id: id },
function () {
console.log($scope.article);
});
};
// (4)[更新]ボタンでフォームの内容に従って記事情報を更新
$scope.onupdate = function() {
Article.update(
$scope.article,
function() {
databind();
});
};
// [削除]ボタンで該当する行の記事情報を削除
$scope.ondelete = function(id) {
Article.delete(
{ id: id },
function() {
databind();
});
};
}]);
})();
$resourceサービスは、いわゆるRESTサービスへのアクセスを担当するサービス。それ単体でも高機能なサービスですが、ASP.NET Web APIとの相性の良さは特筆すべきものがあります。というのも、(1)のようにWeb APIのエンドポイントを渡すだけで、ASP.NET Web APIにアクセスするためのResourceオブジェクトが生成できます。Resourceオブジェクトは、デフォルトで以下のようなメソッドを提供しますので、$resourceサービスを利用することで、非同期通信を一切意識することなく(単なるメソッド呼び出しで)、ASP.NET Web APIにアクセスできるというわけです。
| メソッド | HTTPメソッド | アクセス先URI | 概要 |
|---|---|---|---|
| query | GET | /api/articles | 複数のデータを取得(戻り値は配列) |
| get | GET | /api/articles/:id | 単一のデータを取得(戻り値は単一のオブジェクト) |
| save | POST | /api/articles | 新規にデータを登録 |
| update | PUT | /api/articles/:id | 既存のデータを更新 |
| delete | DELETE | /api/articles/:id | 既存のデータを削除 |
注3
正しくはHTTP PUTを利用したupdateメソッドだけは、明示的に追加しなければなりません。しかし、わずかにメソッド名と対応するHTTPメソッドを宣言するだけなので、手間はほぼゼロと言って良いでしょう。
あとは、例えば(2)のようにqueryメソッドを呼び出すことで、記事情報の一覧を取得できます。この際、非同期処理特有のコールバック関数すら意識しなくて良い点にも注目です。AngularJSが$scope変数の変化を受けて、その結果をビューに動的にバインドしてくれるからです。
データの登録/更新の手順もシンプルです。先ほどテンプレートで「article.プロパティ名」の形式で入力値をバインドしていましたので、$scope.articleには
{
"Url":"http://codezine.jp/article/detail/8765",
"Title":"Web開発ライブラリを自動的に入手できるパッケージ管理ツールBower",
"Published": "2015-08-07T00:00:00.000Z",
"PageView":5700
}
のようなハッシュができているはずです。このハッシュをそのままpost/updateメソッド((3)(4))に渡すことで、記事情報をまるっとサーバー側のデータモデル(ここではArticleエンティティ)にもバインドできるのです。これは便利ですね。
[3]サンプルを実行する
以上で、クライアントサイドの準備は完了です。
ボタンからサンプルを実行して、以下のようなアプリが起動し、記事情報を編集/参照できることを確認してください。
まとめ
以上、駆け足でしたが、Visual Studio 2015環境でシングルページアプリケーションを開発する流れを追ってみました。Visual Studioというと、マイクロソフト発の技術に特化しているというイメージが、まだまだ強い人もいるかもしれません。
しかし、すでに5~6年以上前から、その傾向は明らかに変化してきています。ASP.NET領域だけを見ても、jQuery/Bootstrapの標準サポートにはじまり、AngularJS/React、Grunt/Gulp、Bowerなどなど、さまざまな優れた技術に対して門戸を開き、より優れた環境を貪欲に追及しているように見えます。今後もその流れは加速していくと思われ、ますます進化していくであろうASP.NET+Visual Studioの未来に、著者自身もワクワクしながら注目しています。

