Angularでさくっと何か作ってみます。"5 min quickstart"のようなものです。このエントリーは「AngularJS Advent Calendar 2015」12月12日の記事です。
Step0: 作成するファイルの構成
Step1: 環境の作成
作業ディレクトリを作りindex.html
を用意する
$ mkdir TodoApp && cd $_ $ touch index.html
index.html
の中身はHTML5の基本構成で。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <base href="/"> <title>Angular1</title> <meta name="viewport" content="width=device-width"> </head> <body> </body> </html>
Step2: 必要なパッケージを登録
AngularはCSSなUIはもってないのでBootstrapを利用します。みんな大好きnpm
でインストール。せっかくのAngularなのでSPAで、使うルータはngRoute
やui Router
、New Router
がありますがngRoute
で。
まずはpackage.json
の生成、色々利かれるから良いように応える。
$ npm init
パッケージの登録
$ npm install jquery bootstrap angular@1.5.0-beta.2 angular-resource@1.5.0-beta.2 angular-route@1.5.0-beta.2 --save
Step1で作ったindex.html
にパッケージを読み込ませる。bodyタグにng-app="TodoApp"を忘れずに。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <base href="/"> <title>Angular1</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css"> </head> <body ng-app="TodoApp"> <!-- package --> <script src="node_modules/jquery/dist/jquery.min.js"></script> <script src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script> <script src="node_modules/angular/angular.min.js"></script> <script src="node_modules/angular-route/angular-route.min.js"></script> <script src="node_modules/angular-resource/angular-resource.min.js"></script> </body> </html>
Step3: メニューを作る
これはAngularというよりBootstrap。新しくheader.html
を作りng-include
でファイルを読み込む。
(index.html) <body ng-app="TodoApp"> <!-- contents --> <div ng-include="'header.html'"></div> <!-- package -->
メニューに関しては色んなパターンで作れるのでBootstrapのサイトを見る
(header.html) <div class="navbar navbar-default navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#app-nav"> <span class="sr-only">Toggle</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="">TodoApp</a> </div> <div class="collapse navbar-collapse" id="app-nav"> <ul class="nav navbar-nav"> <li><a>Home</a></li> <li><a>Todo</a></li> </ul> </div> </div> </div>
固定メニューを設定するとコンテンツを表示させたときにメニューに隠れるのでカスケードスタイルシートに若干手をいれる。
(main.css) body { padding-top: 70px; padding-bottom: 20px; }
Step4: ルーティングの設定とコンポーネントの作成
ng-href
でリンク先のコンポーネントを指定。
(header.html) <li><a ng-href="#/home">Home</a></li> <li><a ng-href="#/todo">Todo</a></li>
JavaScriptを読みこませるのとコンポーネントを表示させるための定義ng-view
を記述。
(index.html) <!-- contents --> <div ng-include="'header.html'"></div> <div class="container"> <div ng-view></div> </div> … <!-- module --> <script src="scripts/main.js"></script> <script src="components/home/home.js"></script> <script src="components/todo/todo.js"></script>
main.js
はルーティングの設定を定義。ここでコンポーネントを構成するJavaScriptとHTMLを定義する。
(main.js) (function () { 'use strict'; angular .module('TodoApp', [ 'ngRoute', 'TodoApp.components.home', 'TodoApp.components.todo' ]) .config(AppConfig); AppConfig.$inject = ['$routeProvider']; function AppConfig($routeProvider) { $routeProvider .when('/', { templateUrl: 'components/home/home.html', controller: 'HomeController as home' }) .when('/todo', { templateUrl: 'components/todo/todo.html', controller: 'TodoController as todo' }) .otherwise({ redirectTo: '/' }); } })();
homeがクリックされたときのコンポーネントを定義
(home.html) <p>home</p>
対応するJavaScriptは
(home.js) (function () { 'use strict'; angular .module('TodoApp.components.home', []) .controller('HomeController', HomeController); HomeController.$inject = []; function HomeController() { console.log('HomeController Constructor'); } })();
続いてtodoがクリックされたときのコンポーネントを定義
(todo.html) <p>todo</p>
対応するJavaScriptは
(todo.js) (function () { 'use strict'; angular .module('TodoApp.components.todo', []) .controller('TodoController', TodoController); TodoController.$inject = []; function TodoController() { console.log('TodoController Constructor'); } })();
Step5: Todoの作成
todo.htmlを変更、8割はBootstrapで2割がAngularのディレクティブ。見るとわかるがng-*
がディレクティブ。ng-repeatで繰り返しを表現しng-click, ng-submitでボタンが押されたときのイベントを処理。
(todo.html) <h2>Todo</h2> <!-- Todos input --> <form role="form" ng-submit="todo.addTodo()"> <div class="input-group"> <input type="text" ng-model="todo.item" placeholder="What needs to be done?" class="form-control"> <span class="input-group-btn"> <input type="submit" class="btn btn-primary" value="Add" name="add"> </span> </div> </form> <hr> <!-- Todos list --> <div> <p class="input-group" ng-repeat="data in todo.todoList track by $index"> <input type="text" ng-model="data" class="form-control"> <span class="input-group-btn"> <button class="btn btn-danger" ng-click="todo.removeTodo($index)" aria-label="Remove">X</button> </span> </p> </div>
対応するイベントを定義。todoの追加と削除のみで、データはリストで保存している。
(todo.js) var vm; function TodoController() { vm = this; vm.todoList = []; } TodoController.prototype.addTodo = function () { vm.todoList.push(vm.item); vm.item = ''; }; TodoController.prototype.removeTodo = function (index) { vm.todoList.splice(index, 1); };
めちゃくちゃ簡単にTodoが完成。AngularというよりBootstrapなコーティングボリューム。
Step6: $resourceを利用
有無も言わさずサービスを作成
(lists.js) (function () { 'use strict'; angular .module('TodoApp.service.lists', [ 'ngResource' ]) .factory('ListsService', ListsService); ListsService.$inject = ['$resource']; function ListsService($resource) { return $resource('/api/lists.json', { 'query': {} }); } })();
表示するリストを定義
(lists.json) [ { "name": "Angular", "note": "HTML is great for declaring static documents, but it falters when we try to use it for declaring dynamic views in web-applications. AngularJS lets you extend HTML vocabulary for your application. The resulting environment is extraordinarily expressive, readable, and quick to develop." }, { "name": "Bootstrap", "note": "Sleek, intuitive, and powerful mobile first front-end framework for faster and easier web development." } ]
homeで表示。ほとんどBootstrap。
(home.html) <div class="col-lg-6" ng-repeat="data in home.list"> <div class="card card-block"> <h4 class="card-title">{{data.name}}</h4> <p class="card-text">{{data.note}}</p> </div> </div>
対応するJavaScriptを定義。自分で作ったサービスをインジェクトしサービスから取得されるプロミスを処理する。
(home.js) (function () { 'use strict'; angular .module('TodoApp.components.home', [ 'TodoApp.service.lists' ]) .controller('HomeController', HomeController); HomeController.$inject = ['ListsService']; var vm; function HomeController(ListsService) { console.log('HomeController Constructor'); vm = this; ListsService.query().$promise .then(function (list) { vm.list = list; }) .catch(function (e) { console.log(e); }); } })();
終わり
こんな画面ができる
コードはGithub
ここに書いたことだけを覚えれば管理画面くらいはサクッといける。学習コスト超低い(と思う)