Skip to content

Commit e4f8475

Browse files
author
maksym.koretskyi
committed
Solution: Moving a view between containers inside child components
1 parent 1e64ed9 commit e4f8475

File tree

7 files changed

+75
-57
lines changed

7 files changed

+75
-57
lines changed

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@
2020
<body>
2121
<my-app>Loading AppComponent content here ...</my-app>
2222
</body>
23+
2324
</html>

src/app/app.component.ts

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,54 @@
1-
import { Component } from '@angular/core';
1+
import {
2+
AfterViewInit,
3+
Component,
4+
EmbeddedViewRef,
5+
OnInit,
6+
QueryList,
7+
TemplateRef,
8+
ViewChild,
9+
ViewChildren
10+
} from '@angular/core';
11+
import { TodoListComponent } from './todo-list.component';
212

313
@Component({
414
selector: 'my-app',
515
template: `
6-
<h1>{{name}}</h1>
7-
<to-do-list></to-do-list>
8-
`
16+
<div class="top">
17+
<div>All tasks</div>
18+
<to-do-list></to-do-list>
19+
</div>
20+
<div class="bottom">
21+
<div>Completed tasks</div>
22+
<to-do-list></to-do-list>
23+
</div>
24+
<ng-template #tpl>
25+
<span>I am a task</span>
26+
</ng-template>
27+
<button (click)="move()">move</button>
28+
`,
29+
styles: ['.top, .bottom {border: 1px solid black; padding: 10px; margin: 10px 0; height: 30px; width: 500px; }']
930
})
10-
export class AppComponent {
11-
name = 'Angular Flow Homework';
31+
export class AppComponent implements AfterViewInit {
32+
@ViewChildren(TodoListComponent) comps: QueryList<TodoListComponent>;
33+
@ViewChild('tpl') tpl: TemplateRef<null>;
34+
embeddedView: EmbeddedViewRef<null>;
35+
isTop: boolean = true;
36+
37+
ngAfterViewInit() {
38+
this.embeddedView = this.tpl.createEmbeddedView(null);
39+
this.comps.first.addItem(this.embeddedView);
40+
this.isTop = true;
41+
}
42+
43+
move() {
44+
if (!this.isTop) {
45+
this.comps.last.removeItem(0);
46+
this.comps.first.addItem(this.embeddedView);
47+
this.isTop = true;
48+
} else {
49+
this.comps.first.removeItem(0);
50+
this.comps.last.addItem(this.embeddedView);
51+
this.isTop = false;
52+
}
53+
}
1254
}

src/app/app.module.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import { NgModule } from '@angular/core';
22
import { BrowserModule } from '@angular/platform-browser';
33
import { AppComponent } from './app.component';
4-
import { TodoItemComponent } from './todo-item';
54
import { TodoListComponent } from './todo-list.component';
65

76
@NgModule({
87
imports: [BrowserModule],
9-
declarations: [AppComponent, TodoListComponent, TodoItemComponent],
8+
declarations: [AppComponent, TodoListComponent],
109
bootstrap: [AppComponent]
1110
})
1211
export class AppModule {

src/app/todo-item.ts

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/app/todo-list.component.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
1-
import { Component } from '@angular/core';
1+
import { Component, ViewChild, ViewContainerRef } from '@angular/core';
22

33
@Component({
44
selector: 'to-do-list',
55
template: `
6-
<h1>To-do list</h1>
7-
<todo-item [item]="todoItem" (completed)="updateCompletedStatus($event)"></todo-item>
8-
`
6+
<ng-container #vc></ng-container>
7+
`,
98
})
109
export class TodoListComponent {
10+
@ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;
11+
12+
addItem(v) {
13+
this.vc.insert(v);
14+
}
15+
16+
removeItem(index) {
17+
return this.vc.detach(index);
18+
}
1119
}

task.gif

32.6 KB
Loading

task.md

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,13 @@
1-
Components input/output communication & ExpressionChangedAfterItHasBeenCheckedError
2-
---------------------
3-
4-
Steps
5-
---------------------
6-
7-
* Implement ToDoList component that contains one child componentn ToDoItem component.
8-
Here is a template of the component:
9-
```html
10-
<h1>To-do list</h1>
11-
<todo-item [item]="todoItem" (completed)="updateCompletedStatus($event)"></todo-item>
12-
```
13-
* Implement ToDoItem component that takes a to-do item as an input. It shows
14-
title and status of the to-do item that it takes. It also contains a checkbox
15-
to switch status of the to-do item.
16-
17-
Here is a template of the component:
18-
```html
19-
<h4>Title: {{item.title}}</h4>
20-
<h4>Status: {{item.completed}}</h4>
21-
<label>
22-
Completed
23-
<input id="checkBox" type="checkbox" (change)="complete($event)">
24-
</label>
25-
```
26-
* ToDoItem component also has `completed` event that is listened to by
27-
the ToDoList component. Once it receives the notification, it udpates the status
28-
of the to-do item.
29-
30-
* Add styles with borders and padding according to the task.jpg
1+
Moving a view between two containers inside child components
2+
------------------------------------------------------------
3+
4+
* Implement the `ToDoListComponent` with one view container in the template.
5+
The component should have the `addItem` method that takes a view
6+
and adds it to a view container. And the `removeItem` method that detaches
7+
the view from a container and returns it.
8+
9+
* Implement the `AppComponent` with the template `<span>I am a task</span>` and
10+
two wrapper divs for the `to-do-list` component. The `AppComponent` should create
11+
an embedded view from the template. It also should should query
12+
two child ToDoList components and using their API add/remove this view when
13+
a user clicks `Move` button. See `task.gif` for the demo.

0 commit comments

Comments
 (0)