「5 MIN QUICKSTART」の勢いでTodos。このエントリーは「AngularJS Advent Calendar 2015」12月21日の記事です。
作業ディレクトリの作成
適当な名前でディレクトリを作る
mkdir angular2todos && cd $_
モジュールのインストール
npm init -y npm install angular2 --save npm install systemjs --save npm install typescript --save npm install todomvc-common --save npm install todomvc-app-css --save npm install store.js --save npm install -g live-server
CSSに関してはtodomvc*
があるのでとても便利、この辺りあまり関係ないので。store.js
はWeb Storageを利用するためのパッケージ。
必要なファイルを作る
今回はサービスも作る
touch index.html touch app.ts mkdir services touch services/store.ts
型定義ファイル
型定義ファイル管理ツールをインストール
npm install -g tsd
必要な型定義ファイルをインストール
tsd init tsd install angular2 --save tsd install node-uuid --save tsd install storejs --save
index.html
ざっとこんな感じ
<html> <head> <title>Angular 2 QuickStart</title> <link rel="stylesheet" href="node_modules/todomvc-common/base.css"> <link rel="stylesheet" href="node_modules/todomvc-app-css/index.css"> <script src="node_modules/systemjs/dist/system.js"></script> <script src="node_modules/typescript/lib/typescript.js"></script> <script src="node_modules/store.js/store.js"></script> <script src="node_modules/angular2/bundles/angular2.dev.js"></script> <script> </script> </head> <body> <todo-app></todo-app> <footer class="info"> <p>Double-click to edit a todo</p> <p> Created by <a href="http://github.com/samccone">Sam Saccone</a> using <a href="http://angular.io">Angular2</a> </p> <p>Part of <a href="http://todomvc.com">TodoMVC</a></p> </footer> <script> System.paths['node-uuid'] = 'node_modules/node-uuid/uuid.js'; System.paths['services/store'] = 'services/store.ts'; System.config({ transpiler: 'typescript', typescriptOptions: { emitDecoratorMetadata: true } }); System.import('./app.ts'); </script> </body> </html>
app.ts
こちらも
/// <reference path="typings/tsd.d.ts" /> import {Component, View, bootstrap, NgIf, NgFor} from 'angular2/angular2'; import {TodoStore, Todo} from 'services/store'; const ESC_KEY = 27; const ENTER_KEY = 13; @Component({ selector: 'todo-app', }) @View({ directives: [NgIf, NgFor], template: ` <section class="todoapp"> <header class="header"> <h1>todos</h1> <input class="new-todo" placeholder="What needs to be done?" autofocus="" #newtodo (keyup)="addTodo($event, newtodo)"> </header> <section class="main" *ng-if="todoStore.todos.length > 0"> <input class="toggle-all" type="checkbox" *ng-if="todoStore.todos.length" #toggleall [checked]="todoStore.allCompleted()" (click)="todoStore.setAllTo(toggleall)"> <ul class="todo-list"> <li *ng-for="#todo of todoStore.todos" [class.completed]="todo.completed" [class.editing]="todo.editing"> <div class="view"> <input class="toggle" type="checkbox" (click)="toggleCompletion(todo.uid)" [checked]="todo.completed"> <label (dblclick)="editTodo(todo)">{{todo.title}}</label> <button class="destroy" (click)="remove(todo.uid)"></button> </div> <input class="edit" *ng-if="todo.editing" [value]="todo.title" #editedtodo (blur)="stopEditing(todo, editedtodo)" (keyup.enter)="updateEditingTodo(editedtodo, todo)" (keyup.escape)="cancelEditingTodo(todo)"> </li> </ul> </section> <footer class="footer" *ng-if="todoStore.todos.length > 0"> <span class="todo-count"><strong>{{todoStore.getRemaining().length}}</strong> {{todoStore.getRemaining().length == 1 ? 'item' : 'items'}} left</span> <button class="clear-completed" *ng-if="todoStore.getCompleted().length > 0" (click)="removeCompleted()">Clear completed</button> </footer> </section>` }) class TodoApp { todoStore: TodoStore; constructor() { this.todoStore = new TodoStore(); } stopEditing(todo: Todo, editedTitle) { todo.setTitle(editedTitle.value); todo.editing = false; } cancelEditingTodo(todo: Todo) { todo.editing = false; } updateEditingTodo(editedTitle, todo: Todo) { editedTitle = editedTitle.value.trim(); todo.editing = false; if (editedTitle.length === 0) { return this.todoStore.remove(todo.uid); } todo.setTitle(editedTitle); } editTodo(todo: Todo) { todo.editing = true; } removeCompleted() { this.todoStore.removeCompleted(); } toggleCompletion(uid: String) { this.todoStore.toggleCompletion(uid); } remove(uid: String){ this.todoStore.remove(uid); } addTodo($event, newtodo) { if ($event.which === ENTER_KEY && newtodo.value.trim().length) { this.todoStore.add(newtodo.value); newtodo.value = ''; } } } bootstrap(TodoApp);
services/store.ts
/// <reference path="../typings/node-uuid/node-uuid.d.ts" /> /// <reference path="../typings/storejs/storejs.d.ts" /> /// <reference path="../typings/angular2/angular2.d.ts" /> import {Injectable} from 'angular2/angular2'; import * as uuid from 'node-uuid'; export class Todo { completed: Boolean; editing: Boolean; title: String; uid: String; setTitle(title: String) { this.title = title.trim(); } constructor(title: String) { this.uid = uuid.v4(); this.completed = false; this.editing = false; this.title = title.trim(); } } @Injectable() export class TodoStore { todos: Array<Todo>; constructor() { let persistedTodos = store.get('angular2-todos') || []; // Normalize back into classes this.todos = persistedTodos.map( (todo: {title: String, completed: Boolean, uid: String}) => { let ret = new Todo(todo.title); ret.completed = todo.completed; ret.uid = todo.uid; return ret; }); } _updateStore() { store.set('angular2-todos', this.todos); } get(state: {completed: Boolean}) { return this.todos.filter((todo: Todo) => todo.completed === state.completed); } allCompleted() { return this.todos.length === this.getCompleted().length; } setAllTo(toggler) { this.todos.forEach((t: Todo) => t.completed = toggler.checked); this._updateStore(); } removeCompleted() { this.todos = this.get({completed: false}); } getRemaining() { return this.get({completed: false}); } getCompleted() { return this.get({completed: true}); } toggleCompletion(uid: String) { for (let todo of this.todos) { if (todo.uid === uid) { todo.completed = !todo.completed; break; } }; this._updateStore(); } remove(uid: String) { for (let todo of this.todos) { if (todo.uid === uid) { this.todos.splice(this.todos.indexOf(todo), 1); break; } } this._updateStore(); } add(title: String) { this.todos.push(new Todo(title)); this._updateStore(); } }
実行
実行は
live-server
最後に
ほぼこれ
作ったソースはこれ。タブとスペースが。。。