2018-03-21 20:11:08 -04:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
*/
|
|
|
|
|
2018-06-22 13:38:30 -04:00
|
|
|
import '@angular/core/test/bundling/util/src/reflect_metadata';
|
2018-05-21 11:15:19 -04:00
|
|
|
|
2018-06-18 11:05:06 -04:00
|
|
|
import {CommonModule} from '@angular/common';
|
2018-09-14 18:58:57 -04:00
|
|
|
import {Component, Injectable, NgModule, ViewEncapsulation, ɵmarkDirty as markDirty, ɵrenderComponent as renderComponent} from '@angular/core';
|
2018-04-06 13:29:22 -04:00
|
|
|
|
2018-06-20 19:02:10 -04:00
|
|
|
class Todo {
|
2018-04-06 13:29:22 -04:00
|
|
|
editing: boolean;
|
|
|
|
|
2018-06-18 19:38:33 -04:00
|
|
|
// TODO(issue/24571): remove '!'.
|
|
|
|
private _title !: string;
|
2018-04-06 13:29:22 -04:00
|
|
|
get title() { return this._title; }
|
|
|
|
set title(value: string) { this._title = value.trim(); }
|
|
|
|
|
|
|
|
constructor(title: string, public completed: boolean = false) {
|
|
|
|
this.editing = false;
|
|
|
|
this.title = title;
|
|
|
|
}
|
2018-03-21 20:11:08 -04:00
|
|
|
}
|
2018-04-06 13:29:22 -04:00
|
|
|
|
2018-04-12 19:03:05 -04:00
|
|
|
@Injectable({providedIn: 'root'})
|
2018-06-20 19:02:10 -04:00
|
|
|
class TodoStore {
|
2018-04-06 13:29:22 -04:00
|
|
|
todos: Array<Todo> = [
|
|
|
|
new Todo('Demonstrate Components'),
|
|
|
|
new Todo('Demonstrate Structural Directives', true),
|
|
|
|
new Todo('Demonstrate NgModules'),
|
|
|
|
new Todo('Demonstrate zoneless change detection'),
|
|
|
|
new Todo('Demonstrate internationalization'),
|
2018-03-21 20:11:08 -04:00
|
|
|
];
|
|
|
|
|
2018-04-06 13:29:22 -04:00
|
|
|
private getWithCompleted(completed: boolean) {
|
|
|
|
return this.todos.filter((todo: Todo) => todo.completed === completed);
|
|
|
|
}
|
2018-03-21 20:11:08 -04:00
|
|
|
|
2018-04-06 13:29:22 -04:00
|
|
|
allCompleted() { return this.todos.length === this.getCompleted().length; }
|
|
|
|
|
|
|
|
setAllTo(completed: boolean) { this.todos.forEach((t: Todo) => t.completed = completed); }
|
|
|
|
|
|
|
|
removeCompleted() { this.todos = this.getWithCompleted(false); }
|
|
|
|
|
|
|
|
getRemaining() { return this.getWithCompleted(false); }
|
2018-03-21 20:11:08 -04:00
|
|
|
|
2018-04-06 13:29:22 -04:00
|
|
|
getCompleted() { return this.getWithCompleted(true); }
|
2018-03-21 20:11:08 -04:00
|
|
|
|
2018-04-06 13:29:22 -04:00
|
|
|
toggleCompletion(todo: Todo) { todo.completed = !todo.completed; }
|
2018-03-21 20:11:08 -04:00
|
|
|
|
2018-04-06 13:29:22 -04:00
|
|
|
remove(todo: Todo) { this.todos.splice(this.todos.indexOf(todo), 1); }
|
|
|
|
|
|
|
|
add(title: string) { this.todos.push(new Todo(title)); }
|
2018-03-21 20:11:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'todo-app',
|
2018-04-06 13:29:22 -04:00
|
|
|
// TODO(misko): make this work with `[(ngModel)]`
|
2018-07-31 14:14:06 -04:00
|
|
|
encapsulation: ViewEncapsulation.None,
|
2018-03-21 20:11:08 -04:00
|
|
|
template: `
|
2018-04-06 13:29:22 -04:00
|
|
|
<section class="todoapp">
|
|
|
|
<header class="header">
|
|
|
|
<h1>todos</h1>
|
2018-06-18 11:05:06 -04:00
|
|
|
<input class="new-todo" placeholder="What needs to be done?" autofocus=""
|
|
|
|
[value]="newTodoText"
|
2018-09-14 18:58:57 -04:00
|
|
|
(keyup)="$event.code == 'Enter' ? addTodo() : updateNewTodoValue($event.target.value)">
|
2018-04-06 13:29:22 -04:00
|
|
|
</header>
|
|
|
|
<section *ngIf="todoStore.todos.length > 0" class="main">
|
2018-06-18 11:05:06 -04:00
|
|
|
<input *ngIf="todoStore.todos.length"
|
|
|
|
#toggleall class="toggle-all" type="checkbox"
|
|
|
|
[checked]="todoStore.allCompleted()"
|
2018-09-14 18:58:57 -04:00
|
|
|
(click)="toggleAllTodos(toggleall.checked)">
|
2018-04-06 13:29:22 -04:00
|
|
|
<ul class="todo-list">
|
2018-06-18 11:05:06 -04:00
|
|
|
<li *ngFor="let todo of todoStore.todos"
|
|
|
|
[class.completed]="todo.completed"
|
2018-04-10 23:57:20 -04:00
|
|
|
[class.editing]="todo.editing">
|
2018-04-06 13:29:22 -04:00
|
|
|
<div class="view">
|
2018-06-18 11:05:06 -04:00
|
|
|
<input class="toggle" type="checkbox"
|
|
|
|
(click)="toggleCompletion(todo)"
|
2018-04-10 23:57:20 -04:00
|
|
|
[checked]="todo.completed">
|
|
|
|
<label (dblclick)="editTodo(todo)">{{todo.title}}</label>
|
2018-04-06 13:29:22 -04:00
|
|
|
<button class="destroy" (click)="remove(todo)"></button>
|
|
|
|
</div>
|
2018-06-18 11:05:06 -04:00
|
|
|
<input *ngIf="todo.editing"
|
2018-04-06 13:29:22 -04:00
|
|
|
class="edit" #editedtodo
|
2018-06-18 11:05:06 -04:00
|
|
|
[value]="todo.title"
|
2019-10-12 12:38:47 -04:00
|
|
|
(blur)="updateEditedTodoValue(todo, editedtodo.value)"
|
|
|
|
(keyup)="updateEditedTodoValue(todo, $event.target.value)"
|
|
|
|
(keyup)="$event.code == 'Enter' && updateEditedTodoValue(todo, editedtodo.value)"
|
2018-04-06 13:29:22 -04:00
|
|
|
(keyup)="$event.code == 'Escape' && cancelEditingTodo(todo)">
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</section>
|
|
|
|
<footer *ngIf="todoStore.todos.length > 0" class="footer">
|
|
|
|
<span class="todo-count">
|
|
|
|
<strong>{{todoStore.getRemaining().length}}</strong>
|
|
|
|
{{todoStore.getRemaining().length == 1 ? 'item' : 'items'}} left
|
|
|
|
</span>
|
2018-06-18 11:05:06 -04:00
|
|
|
<button *ngIf="todoStore.getCompleted().length > 0"
|
|
|
|
class="clear-completed"
|
2018-04-06 13:29:22 -04:00
|
|
|
(click)="removeCompleted()">
|
|
|
|
Clear completed
|
|
|
|
</button>
|
|
|
|
</footer>
|
|
|
|
</section>
|
2018-04-04 16:12:27 -04:00
|
|
|
`,
|
2018-04-10 23:57:20 -04:00
|
|
|
// TODO(misko): switch over to OnPush
|
2018-04-06 13:29:22 -04:00
|
|
|
// changeDetection: ChangeDetectionStrategy.OnPush
|
2018-03-21 20:11:08 -04:00
|
|
|
})
|
2018-06-20 19:02:10 -04:00
|
|
|
class ToDoAppComponent {
|
2018-04-06 13:29:22 -04:00
|
|
|
newTodoText = '';
|
|
|
|
|
2018-04-12 19:03:05 -04:00
|
|
|
constructor(public todoStore: TodoStore) {}
|
2018-04-06 13:29:22 -04:00
|
|
|
|
2018-09-14 18:58:57 -04:00
|
|
|
cancelEditingTodo(todo: Todo) {
|
2018-04-06 13:29:22 -04:00
|
|
|
todo.editing = false;
|
2018-09-14 18:58:57 -04:00
|
|
|
markDirty(this);
|
2018-04-06 13:29:22 -04:00
|
|
|
}
|
|
|
|
|
2018-09-14 18:58:57 -04:00
|
|
|
finishUpdatingTodo(todo: Todo, editedTitle: string) {
|
2018-04-06 13:29:22 -04:00
|
|
|
editedTitle = editedTitle.trim();
|
|
|
|
|
|
|
|
if (editedTitle.length === 0) {
|
2018-09-14 18:58:57 -04:00
|
|
|
this.remove(todo);
|
2018-04-06 13:29:22 -04:00
|
|
|
}
|
2018-03-21 20:11:08 -04:00
|
|
|
|
2018-04-06 13:29:22 -04:00
|
|
|
todo.title = editedTitle;
|
2018-09-14 18:58:57 -04:00
|
|
|
this.cancelEditingTodo(todo);
|
2018-03-21 20:11:08 -04:00
|
|
|
}
|
|
|
|
|
2018-09-14 18:58:57 -04:00
|
|
|
editTodo(todo: Todo) {
|
|
|
|
todo.editing = true;
|
|
|
|
markDirty(this);
|
|
|
|
}
|
2018-04-06 13:29:22 -04:00
|
|
|
|
2018-09-14 18:58:57 -04:00
|
|
|
removeCompleted() {
|
|
|
|
this.todoStore.removeCompleted();
|
|
|
|
markDirty(this);
|
|
|
|
}
|
2018-04-06 13:29:22 -04:00
|
|
|
|
2018-09-14 18:58:57 -04:00
|
|
|
toggleCompletion(todo: Todo) {
|
|
|
|
this.todoStore.toggleCompletion(todo);
|
|
|
|
markDirty(this);
|
|
|
|
}
|
2018-04-06 13:29:22 -04:00
|
|
|
|
2018-09-14 18:58:57 -04:00
|
|
|
remove(todo: Todo) {
|
|
|
|
this.todoStore.remove(todo);
|
|
|
|
markDirty(this);
|
|
|
|
}
|
2018-04-06 13:29:22 -04:00
|
|
|
|
|
|
|
addTodo() {
|
|
|
|
if (this.newTodoText.trim().length) {
|
|
|
|
this.todoStore.add(this.newTodoText);
|
|
|
|
this.newTodoText = '';
|
|
|
|
}
|
2018-09-14 18:58:57 -04:00
|
|
|
markDirty(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
toggleAllTodos(checked: boolean) {
|
|
|
|
this.todoStore.setAllTo(checked);
|
|
|
|
markDirty(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
updateEditedTodoValue(todo: Todo, value: string) {
|
|
|
|
todo.title = value;
|
|
|
|
markDirty(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
updateNewTodoValue(value: string) {
|
|
|
|
this.newTodoText = value;
|
|
|
|
markDirty(this);
|
2018-03-21 20:11:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-31 18:50:02 -04:00
|
|
|
@NgModule({declarations: [ToDoAppComponent], imports: [CommonModule]})
|
2018-06-20 19:02:10 -04:00
|
|
|
class ToDoAppModule {
|
2018-03-21 20:11:08 -04:00
|
|
|
}
|
|
|
|
|
2018-12-03 10:34:25 -05:00
|
|
|
renderComponent(ToDoAppComponent);
|