Our last relevant Blaze Template is the list item - this is a little bit tricky because this template need to interact with the parent Component and get the actual Todo item, and also expose events for the parent Component - so we will use a new Angular 2 features called Input
and Output
for that.
So let's start with the Component migration this time:
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
42
43
44
45
46
47
48
49
50
51
52
53
import {Component, Input, Output, EventEmitter} from '@angular/core';
import {
setCheckedStatus,
updateText,
remove,
} from '../../../imports/api/todos/methods';
import {displayError} from '../../../imports/ui/lib/errors';
declare let _;
@Component({
selector: 'list-item',
templateUrl: '/client/imports/components/list-item.html'
})
export class ListItemComponent {
@Input("todo") todo: any;
@Input("editing") editing: boolean;
@Output("editChange") editChange = new EventEmitter();
constructor() {
}
toggleEdit(isEdit) {
if (!isEdit || (isEdit && this.editing)) {
this.editChange.emit({
editing: isEdit,
todoId: this.todo._id
});
}
}
remove() {
remove.call({
todoId: this.todo._id,
}, displayError);
}
checkedChange(event) {
setCheckedStatus.call({
todoId: this.todo._id,
newCheckedStatus: event.target.checked,
});
}
updateText(event) {
_.throttle((event) => {
updateText.call({
todoId: this.todo._id,
newText: event.target.value,
}, displayError);
}, 300)(event);
}
}
We copied the code from the old Blaze Template, and added two Input
s and one Output
in the Component declaration:
todo
which is the actual todo item.editing
which is an indication for the current item that being edited.editChange
which is an event we expose to the parent Component that triggered when starting to edit an item in the list.And add the new Component to the NgModule:
8
9
10
11
12
13
14
17
18
19
20
21
22
23
24
import {JoinComponent} from "./components/join.component";
import {SigninComponent} from "./components/signin.component";
import {FormsModule} from "@angular/forms";
import {ListItemComponent} from "./components/list-item.component";
@NgModule({
// Components, Pipes, Directive
...some lines skipped...
ListShowComponent,
ListRedirectorComponent,
JoinComponent,
SigninComponent,
ListItemComponent
],
// Entry Components
entryComponents: [
Now let's migrate the HTML Template of this Component:
1
2
3
4
5
6
7
8
9
10
11
<div class="list-item" [ngClass]="{'editing': editing, 'checked': todo.checked}">
<label class="checkbox">
<input type="checkbox" [checked]="todo.checked" (change)="checkedChange($event)" name="checked">
<span class="checkbox-custom"></span>
</label>
<input type="text" [value]="todo.text" (blur)="toggleEdit(false)" (focus)="toggleEdit(true)" (keyup)="updateText($event)" placeholder="Task name">
<a class="js-delete-item delete-item" (click)="remove()">
<span class="icon-trash"></span>
</a>
</div>
And now we need to use this new Component in the ListShowComponent
:
51
52
53
54
55
56
57
<div class="content-scrollable list-items">
<div *ngIf="todosReady">
<div *ngFor="let todo of todos | async">
<list-item [todo]="todo" [editing]="editingTodo" (editChange)="onTodoItemEditChange($event)"></list-item>
</div>
<div class="wrapper-message" *ngIf="!todos || todos.length == 0">
<div class="title-message">No tasks here</div>
And let's implement the actual event handler and use declare the usage of the new Component:
22
23
24
25
26
27
28
101
102
103
104
105
106
107
108
109
110
111
112
private editing : boolean = false;
private editModel : any;
private newItemModel : string = '';
private editingTodo : number | boolean;
constructor(private currentRoute: ActivatedRoute, private router: Router) {
this.editModel = {
...some lines skipped...
}
}
onTodoItemEditChange(event) {
if (event.editing) {
this.editingTodo = event.todoId;
}
else {
this.editingTodo = false;
}
}
}
And we are done! You can now remove all the files that related to the list item and removed it's import! (we did it in commit #9.6)