mochalogからの転載です。
AngularJSとASP.NET MVC (Razor)を使ってビューを作成します。
AngularJSを使うとHTML要素とJavaScriptオブジェクトや関数とのバインドが簡単にできます。
Razorを使うととてもシンプルなやり方でビューの構造化ができます。
ASP.NET MVCのControllerの作成
ControllersフォルダにHomeControllerクラスを作成します。
AngularJSだけでビューを作るのであれば必要ありませんが、
Razorを使わないのはもったいないのでView()を呼ぶだけのアクションを実装します。
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
ビューの作成
Viewsフォルダ下にHomeフォルダを作成します。
作成したHomeフォルダ下にIndex.cshtmlファイルを作成します。
Scriptsフォルダ下にtodo.jsファイルを作成します。
それぞれ見比べながら見た方がわかりやすいので両方の抜粋を載せます。
Index.cshtmlのポイントはng-*
な属性と{{}}
なところ、
todo.jsのポイントは$scope
にいろいろ値や関数を設定してるところ、です。
それぞれに対応づいた値や関数名があるのがわかるかと思います。
これで、TodoCtrlで値を適当にいじると、値や関数にバインドされたところの表示が更新されます。
びっくりですね。
@* 省略 *@
<!doctype html>
<html ng-app="todoApp">
<head>
@* 省略 *@
</head>
<body>
@* 省略 *@
<div class="container">
<h1 class="page-header">Todo</h1>
<div ng-controller="TodoCtrl">
<span>{{remaining()}} of {{todos.length}} remaining</span>
[ <a href="" ng-click="archive()">archive</a> ]
<p ng-show="todos === null">データのロード中です...</p>
<ul class="list-unstyled" ng-show="todos !== null">
<li ng-repeat="todo in todos" class="checkbox">
<label>
<input type="checkbox" ng-model="todo.IsDone" ng-change="updateTodo(todo)">
<span class="done-{{todo.IsDone}}">{{todo.Text}}</span>
</label>
</li>
</ul>
<form class="form-inline" ng-submit="addTodo()">
<input class="form-control" type="text" ng-model="todoText" size="30"
placeholder="add new todo here">
<input class="btn btn-primary btn-sm" type="submit" value="add">
</form>
</div>
</div>
</body>
</html>
angular.
module("todoApp", []).
controller("TodoCtrl", ["$scope", "$http", function ($scope, $http) {
// 値
$scope.todos = null;
$scope.todoText = "";
// 関数
$scope.addTodo = function () {
// 省略
};
$scope.remaining = function () {
// 省略
};
$scope.archive = function () {
// 省略
};
$scope.updateTodo = function (todo) {
// 省略
};
// 初期化処理
// 省略
}]);
ng-app
Index.cshtml
ng-app
属性でこのページのアプリケーション名を指定します。
今回の例でもhtml要素につけているように、一般的にhtml要素やbody要素に書きます。
todo.js
angular.module("todoApp", [])
でアプリケーションを作成します。
ng-controller
Index.cshtml
ng-controller
属性でコントローラをビューに割り当てます。
AngularJSのコントローラはHTML要素とJavaScriptの関数や値を簡単にバインドできます。
コントローラという言葉がASP.NETでもAngularJSでも出てきますが、
AngularJSのコントローラはクライアントサイドの入出力値を管理して、
サーバサイドのASP.NET Web APIコントローラを呼び出すもの、という認識でいいです。
今回の例ではTodoCtrlというコントローラをdiv要素に割り当てています。
div要素内のHTML要素ではTodoCtrlが持つ関数や値をバインドして使っています。
todo.js
controller("TodoCtrl", [...
でTodoCtrlを作成しています。
引数に$scope
とか$http
とかありますが、$scope
はお決まりで書いておく、
$http
はAjax呼び出ししたいときは書かないといけないもの、と思っておいてください。
関数や値のバインド
Index.cshtml
TodoCtrlを割り当てたdiv要素内のHTML要素に{{}}
とかng-*
といった記述があります。
これでHTML要素とTodoCtrlが持つ値や関数をバインドします。
{{}}
はコントローラが持つ値を出力します。
ng-click
やng-submit
は要素がクリックされたり、サブミットされたときに呼ばれる関数をバインドできます。
ng-model
は要素にコントローラが持つ値をバインドします。
input、textarea、selectといった入力のための要素にバインドして、
ビューへのユーザ入力をバインドした値に反映したり、
逆にバインドした値が変更されたときにビューに反映したりしてくれます。
今回の例ではtype="checkbox"
やtype="text"
なinput要素に値をバインドしています。
todo.js
TodoCtrlが持つ関数や値を定義します。
コントローラが持つ値や関数は$scope
に持たせます。
CSSの作成
Contentフォルダ下にtodo.cssを作成します。
チェックされたtodoのスタイルを定義します。
.done-true {
text-decoration: line-through;
color: grey;
}
Index.cshtmlの<span class="done-{{todo.IsDone}}">{{todo.Text}}</span>
で、
todo.IsDoneがtrueのときspanのclassが"done-true"となるので、このスタイルが適用されます。
ちなみにこの記述のせいで、Visual Studioのブラウザリンクを有効にするとエラーが表示されます。。。
AngularJSのコントローラの実装
todo.jsにAngularJSのコントローラを実装します。
前述したtodo.jsの全ソースは以下のとおり。
$scope.todosにtodoの配列、$scope.todoTextにテキスト入力値を持たせています。
各関数では$http
のメソッドを使って、Web APIのアクションを呼んだりしています。
remaining()はサーバに問い合わせる必要がないので、TodoCtrlだけで処理が完結しています。
初期化ではWeb APIからデータを取得して$scope.todosに格納しています。
angular.
module("todoApp", []).
controller("TodoCtrl", ["$scope", "$http", function ($scope, $http) {
// 値
$scope.todos = null;
$scope.todoText = "";
// 関数
$scope.addTodo = function () {
var todo = {
IsDone: false,
Text: $scope.todoText
};
$scope.todos.push(todo);
$scope.todoText = "";
$http.post("/api/todos", todo).success(function (data) {
todo.Id = JSON.parse(data);
});
};
$scope.remaining = function () {
var count = 0;
angular.forEach($scope.todos, function (todo) {
count += todo.IsDone ? 0 : 1;
});
return count;
};
$scope.archive = function () {
var oldTodos = $scope.todos;
$scope.todos = [];
angular.forEach(oldTodos, function (todo) {
if (!todo.IsDone) $scope.todos.push(todo);
});
$http.delete("/api/todos/archive");
};
$scope.updateTodo = function (todo) {
$http.put("/api/todos", todo);
};
// 初期化
$http.get("/api/todos").success(function (data) {
$scope.todos = data;
});
}]);
Razorと組み合わせる
Razorのヘルパーや部分ビューももちろん使えます。
AngularJSにも構造化するためのメカニズムはあるのですが、
C#とかRazorに慣れてるとこっちの方が楽ですね。
分割したIndex.cshtmlの全ソースを以下に載せます。
Index.cshtmlは以下のとおり。
@{
var title = "Hello, ASP.NET & AngularJS!";
var message = "ASP.NETとAngularJSで作るWebアプリのサンプルです。";
}
<!doctype html>
<html ng-app="todoApp">
<head>
<meta charset="utf-8" />
<title>@title</title>
<script src="@Url.Content("~/Scripts/angular.js")"></script>
<script src="@Url.Content("~/Scripts/jquery-2.1.0.js")"></script>
<script src="@Url.Content("~/Scripts/bootstrap.js")"></script>
<script src="@Url.Content("~/Scripts/todo.js")"></script>
<link rel="stylesheet" href="@Url.Content("~/Content/bootstrap.css")">
<link rel="stylesheet" href="@Url.Content("~/Content/todo.css")">
</head>
<body>
@Jumbotron(title, message)
<div class="container">
<h1 class="page-header">Todo</h1>
<div ng-controller="TodoCtrl">
<span>{{remaining()}} of {{todos.length}} remaining</span>
[ <a href="" ng-click="archive()">archive</a> ]
@Html.Partial("_TodoList")
@Html.Partial("_AddTodoForm")
</div>
</div>
</body>
</html>
@helper Jumbotron(string title, string message)
{
<div class="jumbotron">
<h1>@title</h1>
<p>@message</p>
</div>
}
_TodoList.cshtmlは以下のとおり。
<p ng-show="todos === null">データのロード中です...</p>
<ul class="list-unstyled" ng-show="todos !== null">
<li ng-repeat="todo in todos" class="checkbox">
<label>
<input type="checkbox" ng-model="todo.IsDone" ng-change="updateTodo(todo)">
<span class="done-{{todo.IsDone}}">{{todo.Text}}</span>
</label>
</li>
</ul>
_AddTodoFormは以下のとおり。
<form class="form-inline" ng-submit="addTodo()">
<input class="form-control" type="text" ng-model="todoText" size="30"
placeholder="add new todo here">
<input class="btn btn-primary btn-sm" type="submit" value="add">
</form>
作成したTodoアプリのダウンロード
完成したTodoアプリが必要な方は、
http://blog.mochaware.jp/?attachment_id=661
よりダウンロードしてください。
まとめ
以上、駆け足ですがASP.NETとAngularJSでTodoアプリを作ってみました。
- ASP.NET Web APIを使うとC#、CoCで快適にHTTPなサービスのAPIを作れます。JSONでもらったり返したり余裕です
- AngularJSを使うとHTML要素とJavaScriptオブジェクトや関数とのバインドが簡単にできます。JSONで呼び出したり受け取ったりも余裕です
- ASP.NET MVC (Razor)を使うとビューの構造化とか楽です。説明してませんがバンドルとか使うとミニファイとかも楽です。SPAじゃなくてちょっと画面遷移があるときもC#、CoCで快適です
こんな感じが伝わればと思います。
あと、実際にASP.NET + AngularJSで作った、参考になるリンクをまとめて共有するサービス、
Refsもよろしくおねがいします。