Model,Controllerを作ったので、次はViewです。

Viewのたたき台

UI用Viewを生成するControllerを作ります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Mvc4App.Controllers
{
    public class UIController : Controller
    {
        public ActionResult Index()
        {
            return View();   //view呼ぶだけです
        }
    }
}

その後Views\UI\Index.cshtmlを作ります。

1
2
@{ViewBag.Title = "Index";}
<h2>Index</h2>

実行して http://localhost:????/ui にアクセスするとなんか表示されるはずです。

こいつをAngularJSな感じに仕上げていきたいと思います。

参考にするのはhttp://angularjs.org/

AngularJSの動作確認

AngularJSがまともに動くかチェックするべくIndex.cshtmlを以下のように書き換えます。

angularjsのThe Basicsをコピペしてスクリプトパスを絶対パスにするよう変更しただけです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<!doctype html>
<html ng-app>
  <head>
    <script src="@Url.Content("~/Scripts/angular.min.js")"></script>
  </head>
  <body>
    <div>
      <label>Name:</label><input type="text" ng-model="yourName" placeholder="Enter a name here">
      <hr>
      <h1>Hello {{yourName}}!</h1>
    </div>
  </body>
</html>

テキストボックスになんか入れるとHello以下がダイナミックに変わればOK。

どういう仕組みだか知らんけどAngularJSすげー。

AngularJSなModule

Scripts\myapp.jsを追加してmoduldeを定義します。

公式の/ Developer Guide / Modulesによるとmoduldeとはcontrollers, services, filters, directives などなどを入れとくコンテナらしいです。

この辺のものをまとめとくと値が勝手に同期するとか、色々良いことがあるらしいです。

というとで、

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
(function () {  //一応即時関数で安全性に考慮
    var my_app = angular.module('myApp', []);
    //モデルは factoryで定義するらしい
    my_app.factory('Tasks', function () {
        return [
            { Id: 1, Status: 'New', Description: 'JSでべたなデータ' },
            { Id: 2, Status: 'New', Description: 'この部分をServerで生成したいな' },
            { Id: 3, Status: 'New', Description: 'できるのかね?' }
        ];
    });

    my_app.controller('TasksController',['$scope','Tasks', function ($scope,aTasks) {
        $scope.Tasks = aTasks;
    }]);
})();

モジュールとページをリンクさせます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<!doctype html>
<html ng-app="myApp">
  <head>
    <script src="@Url.Content("~/Scripts/angular.min.js")"></script>
    <script src="@Url.Content("~/Scripts/myapp.js")"></script>
  </head>
  <body>
    <ul ng-controller="TasksController">
      <li ng-repeat="task in Tasks">{{ task.Id }} {{ task.Status }}  {{ task.Description }}</li>
    </ul>
    <hr>
    <div>
      <label>Name:</label><input type="text" ng-model="yourName" placeholder="Enter a name here">
      <h1>Hello {{yourName}}!</h1>
    </div>

  </body>
</html>

ng-app=”myApp”でmoduleと関連付けて、ng-controller=”TasksController”でコントローラを使うって感じでしょうか。

実行するとこんな感じ。

RESTfulなAPIを呼び出す

RESTfulなサービスを呼び出すにはngResourceというモジュールを使うらしいです。

名前がどうかと思いますが、便利そうです。

angular-resource.min.jsをダウンロードしてScriptsフォルダにコピーして、ページから参照しておきます。

1
<script src="@Url.Content("~/Scripts/angular-resource.min.js")"></script>

さっそくサーバを呼び出すようにしてみます。

まずは一番簡単そうな全件取得から。CRUDでいうとこのRですな。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
(function () {  //一応即時関数で安全性に考慮
    var my_app = angular.module('myApp', ['ngResource']);   //RESTfulなサービス呼出のためngResourceを使います
    //モデルは factoryで定義するらしい
    my_app.factory('Tasks', ['$resource', function ($resource) {
        return $resource('/api/tasks');
    }]);
    my_app.controller('TasksController',['$scope','Tasks', function ($scope,aTasks) {
        $scope.Tasks = aTasks.query();
    }]);
})();

factoryの定義部分をデータべたうちから、WebAPIの定義に変更して、controllerで実際にコールしています。

うまくいくと、Global.asax.csでセットしたテストデータが表示されるはずです。

追加処理追加

全件取得ができたので、次に追加をしてみます。CRUDでいうとこのC。

まず追加用フォームをページに追加します。

TasksControllerでリストとフォームの面倒も見るので、divで囲ってng-controller=”TasksController”を移動しました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!doctype html>
<html ng-app="myApp">
  <head>
    <script src="@Url.Content("~/Scripts/angular.min.js")"></script>
    <script src="@Url.Content("~/Scripts/angular-resource.min.js")"></script>
    <script src="@Url.Content("~/Scripts/myapp.js")"></script>
  </head>
  <body>
    <div ng-controller="TasksController">
        <ul >
            <li ng-repeat="task in Tasks">{{ task.Id }} {{ task.Status }}  {{ task.Description }}</li>
        </ul>
        <hr>
        <input type="text" ng-model="newDescription" placeholder="Input Description"/>
        <button ng-click="add()">追加</button>
    </div>
    <hr>
    <div>
      <label>Name:</label><input type="text" ng-model="yourName" placeholder="Enter a name here">
      <h1>Hello {{yourName}}!</h1>
    </div>
  </body>
</html>

実行するとこんな感じ。

次にコントローラーにaddメソッドを定義します。client側の肝ですな。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
(function () {  //一応即時関数で安全性に考慮

    var my_app = angular.module('myApp', ['ngResource']);   //RESTfulなサービス呼出のためngResourceを使います

    //モデルは factoryで定義するらしい
    my_app.factory('Tasks', ['$resource', function ($resource) {
        return $resource('/api/tasks');
    } ]);

    my_app.controller('TasksController', ['$scope', 'Tasks', function ($scope, aTasks) {
        $scope.Tasks = aTasks.query();
        $scope.add = function () {  //追加処理
            aTasks.save({ Description: $scope.newDescription }, function (saved_object) {
                $scope.Tasks.push(saved_object);    //成功ハンドラの第一引数にWebAPIの返り値が入るっぽい。
            });
        };
    } ]);
})();

成功ハンドラに値を返したいので、WebAPIを保存されたデータを返すように変更します。

1
2
3
4
5
6
7
8
9
// POST api/tasks
        public Models.Task Post(Models.Task value)
        {
            using (var db = new Models.TaskContext()) {
                db.Tasks.Add(value);
                db.SaveChanges();
                return value;   //保存された値を返す
            }
        }

APIのコールには、factory “Tasks”で定義された$resource(‘/api/tasks’)にディフォルトで設定されているsaveを使います。

$scope.Tasks.push(saved_object);でリストに値を追加すると表示も変わります。すばらしい。

引き続き、更新・削除も実装します。