Differenzansicht 03-event-binding
im Vergleich zu 02-property-binding

← Zurück zur Ãœbersicht | Demo | Quelltext auf GitHub
src/app/app.component.html CHANGED
@@ -1,3 +1,6 @@
1
  <main>
2
- <bm-book-list></bm-book-list>
 
 
 
3
  </main>
1
  <main>
2
+ <bm-book-list *ngIf="!book"
3
+ (selectBook)="showDetails($event)"></bm-book-list>
4
+ <bm-book-details *ngIf="book"
5
+ (leave)="showList()" [book]="book"></bm-book-details>
6
  </main>
src/app/app.component.ts CHANGED
@@ -1,4 +1,5 @@
1
  import { Component } from '@angular/core';
 
2
 
3
  @Component({
4
  selector: 'bm-root',
@@ -6,4 +7,13 @@ import { Component } from '@angular/core';
6
  styleUrls: ['./app.component.css']
7
  })
8
  export class AppComponent {
 
 
 
 
 
 
 
 
 
9
  }
1
  import { Component } from '@angular/core';
2
+ import { Book } from './shared/book';
3
 
4
  @Component({
5
  selector: 'bm-root',
7
  styleUrls: ['./app.component.css']
8
  })
9
  export class AppComponent {
10
+ book: Book | null = null;
11
+
12
+ showList() {
13
+ this.book = null;
14
+ }
15
+
16
+ showDetails(book: Book) {
17
+ this.book = book;
18
+ }
19
  }
src/app/app.module.ts CHANGED
@@ -5,12 +5,14 @@ import { AppRoutingModule } from './app-routing.module';
5
  import { AppComponent } from './app.component';
6
  import { BookListComponent } from './book-list/book-list.component';
7
  import { BookListItemComponent } from './book-list-item/book-list-item.component';
 
8
 
9
  @NgModule({
10
  declarations: [
11
  AppComponent,
12
  BookListComponent,
13
- BookListItemComponent
 
14
  ],
15
  imports: [
16
  BrowserModule,
5
  import { AppComponent } from './app.component';
6
  import { BookListComponent } from './book-list/book-list.component';
7
  import { BookListItemComponent } from './book-list-item/book-list-item.component';
8
+ import { BookDetailsComponent } from './book-details/book-details.component';
9
 
10
  @NgModule({
11
  declarations: [
12
  AppComponent,
13
  BookListComponent,
14
+ BookListItemComponent,
15
+ BookDetailsComponent
16
  ],
17
  imports: [
18
  BrowserModule,
src/app/book-details/book-details.component.html ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="details" *ngIf="book">
2
+ <h1>{{ book.title }}</h1>
3
+ <p role="doc-subtitle" *ngIf="book.subtitle">{{ book.subtitle }}</p>
4
+ <div class="header">
5
+ <div>
6
+ <h2>Authors</h2>
7
+ <ul>
8
+ <li *ngFor="let author of book.authors">{{ author }}</li>
9
+ </ul>
10
+ </div>
11
+ <div>
12
+ <h2>ISBN</h2>
13
+ {{ book.isbn }}
14
+ </div>
15
+ <div *ngIf="book.published">
16
+ <h2>Published</h2>
17
+ {{ book.published }}
18
+ </div>
19
+ </div>
20
+ <h2>Description</h2>
21
+ <p>{{ book.description }}</p>
22
+ <img *ngIf="book.thumbnailUrl"
23
+ [src]="book.thumbnailUrl"
24
+ alt="Cover">
25
+ <button class="arrow-left" (click)="doLeave()">
26
+ Back to list
27
+ </button>
28
+ </div>
src/app/book-details/book-details.component.spec.ts ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { BookDetailsComponent } from './book-details.component';
4
+
5
+ describe('BookDetailsComponent', () => {
6
+ let component: BookDetailsComponent;
7
+ let fixture: ComponentFixture<BookDetailsComponent>;
8
+
9
+ beforeEach(async () => {
10
+ await TestBed.configureTestingModule({
11
+ declarations: [ BookDetailsComponent ]
12
+ })
13
+ .compileComponents();
14
+
15
+ fixture = TestBed.createComponent(BookDetailsComponent);
16
+ component = fixture.componentInstance;
17
+ fixture.detectChanges();
18
+ });
19
+
20
+ it('should create', () => {
21
+ expect(component).toBeTruthy();
22
+ });
23
+ });
src/app/book-details/book-details.component.ts ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Component, Input, Output, EventEmitter } from '@angular/core';
2
+ import { Book } from '../shared/book';
3
+
4
+ @Component({
5
+ selector: 'bm-book-details',
6
+ templateUrl: './book-details.component.html',
7
+ styleUrls: ['./book-details.component.css']
8
+ })
9
+ export class BookDetailsComponent {
10
+ @Input() book?: Book;
11
+ @Output() leave = new EventEmitter<void>();
12
+
13
+ doLeave() {
14
+ this.leave.emit();
15
+ }
16
+ }
src/app/book-list/book-list.component.html CHANGED
@@ -1,7 +1,7 @@
1
  <h1>Books</h1>
2
  <ul class="book-list">
3
  <li *ngFor="let book of books">
4
- <bm-book-list-item [book]="book"></bm-book-list-item>
5
  </li>
6
  <li *ngIf="!books.length">
7
  No books available.
1
  <h1>Books</h1>
2
  <ul class="book-list">
3
  <li *ngFor="let book of books">
4
+ <bm-book-list-item [book]="book" (click)="doSelect(book)"></bm-book-list-item>
5
  </li>
6
  <li *ngIf="!books.length">
7
  No books available.
src/app/book-list/book-list.component.integration.spec.ts ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { BookListItemComponent } from '../book-list-item/book-list-item.component';
4
+ import { Book } from '../shared/book';
5
+ import { BookListComponent } from './book-list.component';
6
+
7
+ describe('BookListComponent', () => {
8
+ let component: BookListComponent;
9
+ let fixture: ComponentFixture<BookListComponent>;
10
+
11
+ beforeEach(async () => {
12
+ await TestBed.configureTestingModule({
13
+ declarations: [
14
+ BookListComponent,
15
+ BookListItemComponent
16
+ ]
17
+ })
18
+ .compileComponents();
19
+
20
+ fixture = TestBed.createComponent(BookListComponent);
21
+ component = fixture.componentInstance;
22
+ fixture.detectChanges();
23
+ });
24
+
25
+ it('should trigger an event on clicking the thumbnail', () => {
26
+
27
+ let receivedBook: Book | undefined;
28
+ component.selectBook.subscribe(book => {
29
+ receivedBook = book;
30
+ });
31
+
32
+ fixture.nativeElement
33
+ .querySelector('img').click();
34
+ expect(receivedBook?.title).toBe('Tierisch gut kochen');
35
+ });
36
+ });
src/app/book-list/book-list.component.shallow.spec.ts ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { BookListComponent } from './book-list.component';
4
+ import { Book } from '../shared/book';
5
+
6
+ describe('BookListComponent', () => {
7
+ let component: BookListComponent;
8
+ let fixture: ComponentFixture<BookListComponent>;
9
+
10
+ beforeEach(async () => {
11
+ await TestBed.configureTestingModule({
12
+ declarations: [BookListComponent]
13
+ })
14
+ .compileComponents();
15
+
16
+ fixture = TestBed.createComponent(BookListComponent);
17
+ component = fixture.componentInstance;
18
+ fixture.detectChanges();
19
+ });
20
+
21
+ it('should trigger an event on click', () => {
22
+
23
+ let receivedBook: Book | undefined;
24
+ component.selectBook.subscribe(book => {
25
+ receivedBook = book;
26
+ });
27
+
28
+ fixture.nativeElement
29
+ .querySelector('bm-book-list-item').click();
30
+ expect(receivedBook?.title).toBe('Tierisch gut kochen');
31
+ });
32
+ });
src/app/book-list/book-list.component.spec.ts CHANGED
@@ -1,23 +1,27 @@
1
- import { ComponentFixture, TestBed } from '@angular/core/testing';
2
-
3
  import { BookListComponent } from './book-list.component';
 
4
 
5
  describe('BookListComponent', () => {
 
6
  let component: BookListComponent;
7
- let fixture: ComponentFixture<BookListComponent>;
8
 
9
- beforeEach(async () => {
10
- await TestBed.configureTestingModule({
11
- declarations: [ BookListComponent ]
12
- })
13
- .compileComponents();
14
 
15
- fixture = TestBed.createComponent(BookListComponent);
16
- component = fixture.componentInstance;
17
- fixture.detectChanges();
18
  });
19
 
20
- it('should create', () => {
21
- expect(component).toBeTruthy();
 
 
 
 
 
 
 
 
22
  });
23
  });
 
 
1
  import { BookListComponent } from './book-list.component';
2
+ import { Book } from '../shared/book';
3
 
4
  describe('BookListComponent', () => {
5
+
6
  let component: BookListComponent;
 
7
 
8
+ beforeEach(() => {
9
+ component = new BookListComponent();
10
+ });
 
 
11
 
12
+ it('should hold a hardcoded list of 2 books', () => {
13
+ expect(component.books).toHaveSize(2);
 
14
  });
15
 
16
+ it('should trigger an event on "doSelect"', () => {
17
+
18
+ const sentBook = {} as Book;
19
+ let receivedBook: Book | undefined;
20
+ component.selectBook.subscribe(book => {
21
+ receivedBook = book;
22
+ });
23
+
24
+ component.doSelect(sentBook);
25
+ expect(receivedBook).toBe(sentBook);
26
  });
27
  });
src/app/book-list/book-list.component.stub.spec.ts ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+ import { BookListComponent } from './book-list.component';
4
+ import { Book } from '../shared/book';
5
+ import { Component, Input } from '@angular/core';
6
+
7
+ @Component({
8
+ selector: 'bm-book-list-item',
9
+ template: ''
10
+ })
11
+ class TestBookListItemComponent {
12
+ @Input() book?: Book;
13
+ }
14
+
15
+ describe('BookListComponent', () => {
16
+ let component: BookListComponent;
17
+ let fixture: ComponentFixture<BookListComponent>;
18
+
19
+ beforeEach(async () => {
20
+ await TestBed.configureTestingModule({
21
+ declarations: [
22
+ BookListComponent,
23
+ TestBookListItemComponent // NEU
24
+ ]
25
+ })
26
+ .compileComponents();
27
+
28
+ fixture = TestBed.createComponent(BookListComponent);
29
+ component = fixture.componentInstance;
30
+ fixture.detectChanges();
31
+ });
32
+
33
+ it('should trigger an event on click', () => {
34
+
35
+ let receivedBook: Book | undefined;
36
+ component.selectBook.subscribe(book => {
37
+ receivedBook = book;
38
+ });
39
+
40
+ fixture.nativeElement
41
+ .querySelector('bm-book-list-item').click();
42
+ expect(receivedBook?.title).toBe('Tierisch gut kochen');
43
+ });
44
+ });
src/app/book-list/book-list.component.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Component } from '@angular/core';
2
 
3
  import { Book } from '../shared/book';
4
 
@@ -9,6 +9,7 @@ import { Book } from '../shared/book';
9
  })
10
  export class BookListComponent {
11
  books: Book[] = [];
 
12
 
13
  constructor() {
14
  this.books = [
@@ -32,4 +33,8 @@ export class BookListComponent {
32
  }
33
  ];
34
  }
 
 
 
 
35
  }
1
+ import { Component, EventEmitter, Output } from '@angular/core';
2
 
3
  import { Book } from '../shared/book';
4
 
9
  })
10
  export class BookListComponent {
11
  books: Book[] = [];
12
+ @Output() selectBook = new EventEmitter<Book>();
13
 
14
  constructor() {
15
  this.books = [
33
  }
34
  ];
35
  }
36
+
37
+ doSelect(book: Book) {
38
+ this.selectBook.emit(book);
39
+ }
40
  }
src/app/book-list/book-list.component.without-error-shallow.spec.ts ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
2
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
3
+
4
+ import { Book } from '../shared/book';
5
+ import { BookListComponent } from './book-list.component';
6
+
7
+ describe('BookListComponent', () => {
8
+ let component: BookListComponent;
9
+ let fixture: ComponentFixture<BookListComponent>;
10
+
11
+ beforeEach(async () => {
12
+ await TestBed.configureTestingModule({
13
+ declarations: [BookListComponent],
14
+ schemas: [CUSTOM_ELEMENTS_SCHEMA] // NEU
15
+ })
16
+ .compileComponents();
17
+
18
+ fixture = TestBed.createComponent(BookListComponent);
19
+ component = fixture.componentInstance;
20
+ fixture.detectChanges();
21
+ });
22
+
23
+ it('should trigger an event on click', () => {
24
+
25
+ let receivedBook: Book | undefined;
26
+ component.selectBook.subscribe(book => {
27
+ receivedBook = book;
28
+ });
29
+
30
+ fixture.nativeElement
31
+ .querySelector('bm-book-list-item').click();
32
+ expect(receivedBook?.title).toBe('Tierisch gut kochen');
33
+ });
34
+ });