Bootstrapはやってますね。使ったことありませんが、お手軽にきれいなサイトができるらしいっす。
てことで、AngularJSの練習で作ったプロジェクトにBootstrapを組み込んでみたいと思います。
AngularJS と Bootstrapを合わせ技で使う場合、UI Bootstrapがよさそうです。
こーゆーのやるときって上級者の間ではyeomanとかでさくっとscaffolding的な事をするんでしょうけど、お勉強目的なので地道にダウンロード→プロジェクトに組み込みでやっていきます。
ダウンロード
UI Bootstrap
Angularな人たちが作っているnative AngularJS directivesなライブラリ(?)です。
UI Bootstrapの”Download”から Build=Minified ,Include Templates=Yesでダウンロードします。
バージョンは0.10.0でした。
ダウンロードされたファイル”ui-bootstrap-tpls-0.10.0.min.js”をプロジェクトのScriptsにコピー。
Bootstrap
twitterな人たちが作ってる、さくっとかっこいいサイトができるらしいフレームワークです。
BootstrapのサイトからDownloadします。
バージョンは3.1.1でした。
“bootstrap-3.1.1-dist.zip”を展開したフォルダをプロジェクトのContentにコピー。
フォルダ名を”bootstrap3.1.1″にしました。
こんな構成になっております。
追加フォームをbootstrap風にしてみる
手始めに新規追加フォームをbootstrapで装飾してみます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
<!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/jquery-1.11.0.min.js")"></script>
<script src="@Url.Content("~/Scripts/ui-bootstrap-tpls-0.10.0.min.js")"></script>
<script src="@Url.Content("~/Scripts/myapp.js")"></script>
<link href="@Url.Content("~/Content/bootstrap3.1.1/css/bootstrap.min.css")" rel="stylesheet"/>
</head>
<body>
<div ng-controller="TasksController">
・・・中略・・・
<hr>
<form class="form-horizontal" role="form">
<div class="form-group">
<label for="newDescription" class="col-sm-2 control-label">詳細</label>
<div class="col-sm-10">
<input type="text" ng-model="newDescription" placeholder="Input Description" id="newDescription" class="form-control"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button ng-click="add()" class="btn btn-default">追加</button>
</div>
</div>
</form>
</div>
<hr>
・・・中略・・・
</body>
</html>
|
bootstrapって結構冗長な書き方になるのですね。
実行してみると… ChromeだとちゃんとするけどIE8だとダメですね。
horizontalとかoffsetとか効いてないっす。
IE8対応
Supported browsersによるとRespond.js とやらを組み込めとのこと。さらに、Basic templateを良く見るとIE用の記述がありますね。”if lt IE 9″ってやつ。
html5shivとRespond.jsをダウンロードして、Scriptsにコピーして参照します。修正後は
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<!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/jquery-1.11.0.min.js")"></script>
<script src="@Url.Content("~/Scripts/ui-bootstrap-tpls-0.10.0.min.js")"></script>
<script src="@Url.Content("~/Scripts/myapp.js")"></script>
<link href="@Url.Content("~/Content/bootstrap3.1.1/css/bootstrap.min.css")" rel="stylesheet"/>
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="@Url.Content("~/Scripts/html5shiv.min.js")"></script>
<script src="@Url.Content("~/Scripts/respond.min.js")"></script>
<![endif]-->
</head>
<body>
・・・中略・・・
</body>
</html>
|
IE8、Widnows7標準のブラウザなんで対応しないわけにはいきませんよね~。IE滅びないかな♪
UI Bootstrapなdirectiveを使ってみる
動作確認もかねて見た目が派手そうなDatepickerを使ってみます。
Entityの変更
日付っぽいプロパティを持たせたいので、TaskにDueDateというプロパティを持たせてみました。
1
2
3
4
5
6
7
8
|
[Table("Tasks")]
public class Task
{
public int Id { get; set; }
public TaskStatus Status{ get; set;}
public string Description { get; set; }
public DateTime? DueDate { get; set; }
}
|
テスト用データにも日付を入れるようにします。
1
2
3
4
5
6
7
8
|
using (var db = new Models.TaskContext()) {
var task = new Models.Task();
task.Status = Models.TaskStatus.New;
task.Description = "てすとっす";
task.DueDate = DateTime.Parse("2014/4/1");
db.Tasks.Add(task);
db.SaveChanges();
}
|
AngularJSコントローラ変更
AngularJS用のスクリプトにui.bootstrapを組み込み、カレンダー用のコントローラを追加します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
(function () { //一応即時関数で安全性に考慮
var my_app = angular.module('myApp', ['ngResource' //RESTfulなサービス呼出のためngResourceを使います
, 'ui.bootstrap' //モダンなページデザインのためUI Bootstrapを使用します
]);
・・・中略・・・
my_app.controller('TasksController', ['$scope', 'Tasks', function ($scope, aTasks) {
$scope.Tasks = aTasks.query();
$scope.newTask = {}; //入れ子のコントローラから参照されるので、空のオブジェクトをセットしておく
$scope.add = function (task) { //追加処理
aTasks.save({ Description: task.Description, DueDate: task.DueDate }, function (saved_object) {
$scope.Tasks.push(saved_object); //成功ハンドラの第一引数にWebAPIの返り値が入るっぽい。
});
};
・・・中略・・・
my_app.controller('DatepickerCtrl', ['$scope', function ($scope) {
// Disable weekend selection
$scope.disabled = function (date, mode) {
//return (mode === 'day' && (date.getDay() === 0 || date.getDay() === 6)); //disable weekend
return false; //enable all days
};
$scope.open = function ($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened = true;
};
$scope.dateOptions = {'year-format': "'yy'",'starting-day': 1 }; //コントローラ側からオプション設定
} ]);
})();
|
4行目でUI Bootstrapへの参照を追加しています。
11行目付近で新規追加用のモデルを明示的に作成しています。
コントローラを入れ子にした際の親のスコープオブジェクトを明確にするためです。
addハンドラも追加対象を明示的にセットするようにしました。あ、DueDateにも対応してます。
19行目からがカレンダー用のコントローラですサンプルを参考に要らない部分を削ってみました。
Datepickerのコントローラ名に”DatepickerController”を使ったらカレンダーが表示されなくなりました。ほかの名前なら大丈夫。なんか内部的に使ってたりするみたいです。半日はまりました。
新規フォームView変更
新規追加用フォームを変更していきます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
・・・中略・・・
<div ng-controller="TasksController">
・・・中略・・・
<hr>
<form class="form-horizontal" role="form" ng-model='newTask'>
<div class="form-group">
<div ng-controller="DatepickerCtrl">
<label for="newDueDate" class="col-sm-2 control-label">締切日</label>
<div class="col-sm-6">
<p class="input-group">
<input type="text" class="form-control"
ng-model="newTask.DueDate"
datepicker-popup="yyyy-MM-dd"
is-open="opened"
datepicker-options="dateOptions"
date-disabled="disabled(date, mode)"
ng-required="true" />
<span class="input-group-btn">
<button class="btn btn-default" ng-click="open($event)">
<i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
</div>
</div>
<div class="form-group">
<label for="newDescription" class="col-sm-2 control-label">詳細</label>
<div class="col-sm-10">
<input type="text" ng-model="newTask.Description" placeholder="Input Description" id="newDescription" class="form-control"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button ng-click="add(newTask)" class="btn btn-default">追加</button>
</div>
</div>
{{newTask}}
</form>
</div>
・・・中略・・・
|
5行目:フォームにモデルを明示的にセットしています。
7行目:DatepickerCtrlを入れ子にして、
12行目:で親コントローラのモデルを参照しています。
13行目:からのdatepicker-??とかのdirectiveがUI Bootstrap用の記述になります。これだけでPopupなカレンダーが出るようになります。
30,35行目:モデルを明示的にセットしています。
実行
IE8でも動きます。
おそろしいです。
続くかも。