From 049c89645b7727475a0de77c104d4163eb578576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Rodr=C3=ADguez?= Date: Mon, 6 Nov 2017 19:02:18 +0100 Subject: [PATCH] docs(aio): update ToH for CLI (#19811) --- .../examples/toh-pt0/e2e/app.e2e-spec.ts | 14 + .../examples/toh-pt0/example-config.json | 0 aio/content/examples/toh-pt0/plnkr.json | 10 + .../toh-pt0/src/app/app.component.css | 0 .../toh-pt0/src/app/app.component.html | 1 + .../toh-pt0/src/app/app.component.spec.ts | 32 + .../examples/toh-pt0/src/app/app.component.ts | 12 + .../examples/toh-pt0/src/app/app.module.ts | 16 + aio/content/examples/toh-pt0/src/index.html | 14 + .../src/main.1.ts => toh-pt0/src/main.ts} | 0 .../{toh-pt5 => toh-pt0}/src/styles.1.css | 2 +- .../examples/toh-pt1/app/app.component.1.ts | 44 - .../{e2e-spec.ts => e2e/app.e2e-spec.ts} | 8 +- aio/content/examples/toh-pt1/plnkr.json | 3 +- .../toh-pt1/src/app/app.component.css | 0 .../toh-pt1/src/app/app.component.html | 2 + .../examples/toh-pt1/src/app/app.component.ts | 29 +- .../examples/toh-pt1/src/app/app.module.ts | 28 +- aio/content/examples/toh-pt1/src/app/hero.ts | 4 + .../src/app/heroes/heroes.component.1.html | 17 + .../src/app/heroes/heroes.component.css | 0 .../src/app/heroes/heroes.component.html | 10 + .../src/app/heroes/heroes.component.spec.ts | 25 + .../src/app/heroes/heroes.component.ts | 35 + aio/content/examples/toh-pt1/src/index.html | 21 +- .../{e2e-spec.ts => e2e/app.e2e-spec.ts} | 12 +- .../toh-pt2/src/app/app.component.1.html | 69 - .../toh-pt2/src/app/app.component.css | 0 .../toh-pt2/src/app/app.component.html | 2 + .../examples/toh-pt2/src/app/app.component.ts | 105 +- .../examples/toh-pt2/src/app/app.module.ts | 18 +- aio/content/examples/toh-pt2/src/app/hero.ts | 4 + .../src/app/heroes/heroes.component.1.html | 20 + .../src/app/heroes}/heroes.component.css | 22 +- .../src/app/heroes/heroes.component.html | 27 + .../src/app/heroes/heroes.component.spec.ts | 25 + .../src/app/heroes/heroes.component.ts | 36 + .../examples/toh-pt2/src/app/mock-heroes.ts | 14 + aio/content/examples/toh-pt2/src/index.html | 21 +- .../toh-pt3/app/hero-detail.component.1.ts | 35 - .../{e2e-spec.ts => e2e/app.e2e-spec.ts} | 12 +- .../toh-pt3/src/app/app.component.css | 0 .../toh-pt3/src/app/app.component.html | 2 + .../examples/toh-pt3/src/app/app.component.ts | 91 +- .../examples/toh-pt3/src/app/app.module.ts | 26 +- .../toh-pt3/src/app/hero-detail.component.ts | 29 - .../app/hero-detail/hero-detail.component.css | 0 .../hero-detail/hero-detail.component.html | 11 + .../app/hero-detail/hero-detail.component.ts | 24 + aio/content/examples/toh-pt3/src/app/hero.ts | 1 - .../src/app/heroes/heroes.component.css | 48 + .../app/heroes/heroes.component.html} | 5 +- .../src/app/heroes/heroes.component.spec.ts | 25 + .../src/app/heroes/heroes.component.ts | 25 + .../examples/toh-pt3/src/app/mock-heroes.ts | 14 + aio/content/examples/toh-pt3/src/index.html | 21 +- aio/content/examples/toh-pt3/src/main.ts | 4 +- .../{e2e-spec.ts => e2e/app.e2e-spec.ts} | 12 +- .../toh-pt4/src/app/app.component.1.ts | 65 - .../toh-pt4/src/app/app.component.css | 0 .../toh-pt4/src/app/app.component.html | 3 + .../examples/toh-pt4/src/app/app.component.ts | 97 +- .../examples/toh-pt4/src/app/app.module.ts | 25 +- .../toh-pt4/src/app/hero-detail.component.ts | 22 - .../app/hero-detail/hero-detail.component.css | 0 .../hero-detail/hero-detail.component.html | 9 + .../app/hero-detail/hero-detail.component.ts | 20 + .../toh-pt4/src/app/hero.service.1.ts | 24 +- .../toh-pt4/src/app/hero.service.2.ts | 13 - .../examples/toh-pt4/src/app/hero.service.ts | 40 +- .../src/app/heroes/heroes.component.1.ts | 19 + .../src/app/heroes/heroes.component.css | 50 + .../src/app/heroes/heroes.component.html | 14 + .../src/app/heroes/heroes.component.spec.ts | 25 + .../src/app/heroes/heroes.component.ts | 43 + .../toh-pt4/src/app/message.service.spec.ts | 15 + .../toh-pt4/src/app/message.service.ts | 14 + .../src/app/messages/messages.component.css | 35 + .../src/app/messages/messages.component.html | 8 + .../app/messages/messages.component.spec.ts | 25 + .../src/app/messages/messages.component.ts | 21 + aio/content/examples/toh-pt4/src/index.html | 21 +- .../{e2e-spec.ts => e2e/app.e2e-spec.ts} | 52 +- aio/content/examples/toh-pt5/plnkr.json | 2 +- .../toh-pt5/src/app/app-routing.module.0.ts | 10 + .../toh-pt5/src/app/app-routing.module.ts | 37 +- .../toh-pt5/src/app/app.component.1.ts | 42 - .../toh-pt5/src/app/app.component.css | 2 +- .../toh-pt5/src/app/app.component.html | 14 + .../examples/toh-pt5/src/app/app.component.ts | 18 +- .../examples/toh-pt5/src/app/app.module.1.ts | 28 - .../examples/toh-pt5/src/app/app.module.2.ts | 48 - .../examples/toh-pt5/src/app/app.module.3.ts | 58 - .../examples/toh-pt5/src/app/app.module.ts | 13 +- .../toh-pt5/src/app/dashboard.component.1.ts | 8 - .../toh-pt5/src/app/dashboard.component.ts | 33 - .../dashboard.component.1.html | 5 +- .../app/dashboard}/dashboard.component.css | 2 +- .../{ => dashboard}/dashboard.component.html | 4 +- .../app/dashboard/dashboard.component.spec.ts | 25 + .../src/app/dashboard/dashboard.component.ts | 26 + .../src/app/hero-detail.component.1.ts | 29 - .../src/app/hero-detail.component.html | 14 - .../toh-pt5/src/app/hero-detail.component.ts | 46 - .../hero-detail.component.css | 4 +- .../hero-detail/hero-detail.component.html | 12 + .../app/hero-detail/hero-detail.component.ts | 49 + .../examples/toh-pt5/src/app/hero.service.ts | 30 +- .../toh-pt5/src/app/heroes.component.html | 19 - .../toh-pt5/src/app/heroes.component.ts | 46 - .../src/app/heroes/heroes.component.css | 51 + .../src/app/heroes/heroes.component.html | 10 + .../src/app/heroes/heroes.component.spec.ts | 25 + .../src/app/heroes/heroes.component.ts | 26 + .../toh-pt5/src/app/message.service.spec.ts | 15 + .../toh-pt5/src/app/message.service.ts | 14 + .../src/app/messages/messages.component.css | 35 + .../src/app/messages/messages.component.html | 8 + .../app/messages/messages.component.spec.ts | 25 + .../src/app/messages/messages.component.ts | 16 + aio/content/examples/toh-pt5/src/index.html | 25 +- aio/content/examples/toh-pt5/src/main.ts | 2 - aio/content/examples/toh-pt6/aot/index.html | 19 - .../examples/toh-pt6/bs-config.aot.json | 14 - .../examples/toh-pt6/copy-dist-files.js | 12 - .../{e2e-spec.ts => e2e/app.e2e-spec.ts} | 127 +- aio/content/examples/toh-pt6/rollup-config.js | 30 - .../toh-pt6/src/app/app-routing.module.ts | 10 +- .../toh-pt6/src/app/app.component.css | 2 +- .../toh-pt6/src/app/app.component.html | 7 + .../examples/toh-pt6/src/app/app.component.ts | 15 +- .../examples/toh-pt6/src/app/app.module.ts | 66 +- .../toh-pt6/src/app/dashboard.component.html | 10 - .../app/dashboard}/dashboard.component.css | 2 +- .../app/dashboard/dashboard.component.html | 11 + .../app/dashboard/dashboard.component.spec.ts | 25 + .../{ => dashboard}/dashboard.component.ts | 18 +- .../src/app/hero-detail.component.html | 14 - .../toh-pt6/src/app/hero-detail.component.ts | 40 - .../hero-detail.component.css | 4 +- .../hero-detail/hero-detail.component.html | 13 + .../app/hero-detail/hero-detail.component.ts | 42 + .../toh-pt6/src/app/hero-search.component.css | 21 - .../src/app/hero-search.component.html | 11 - .../toh-pt6/src/app/hero-search.component.ts | 69 - .../toh-pt6/src/app/hero-search.service.ts | 20 - .../app/hero-search/hero-search.component.css | 39 + .../hero-search/hero-search.component.html | 17 + .../hero-search/hero-search.component.spec.ts | 25 + .../app/hero-search/hero-search.component.ts | 54 + .../examples/toh-pt6/src/app/hero.service.ts | 191 +- .../toh-pt6/src/app/heroes.component.html | 29 - .../toh-pt6/src/app/heroes.component.ts | 61 - .../src/app/{ => heroes}/heroes.component.css | 48 +- .../src/app/heroes/heroes.component.html | 27 + .../src/app/heroes/heroes.component.spec.ts | 25 + .../src/app/heroes/heroes.component.ts | 43 + .../toh-pt6/src/app/in-memory-data.service.ts | 2 +- .../toh-pt6/src/app/message.service.spec.ts | 15 + .../toh-pt6/src/app/message.service.ts | 14 + .../src/app/messages/messages.component.css | 35 + .../src/app/messages/messages.component.html | 8 + .../app/messages/messages.component.spec.ts | 25 + .../src/app/messages/messages.component.ts | 16 + .../examples/toh-pt6/src/app/mock-heroes.ts | 15 + aio/content/examples/toh-pt6/src/index.html | 21 +- aio/content/examples/toh-pt6/src/main-aot.ts | 6 - .../examples/toh-pt6/src/tsconfig.1.json | 13 - .../examples/toh-pt6/tsconfig-aot.json | 26 - aio/content/guide/template-syntax.md | 123 +- .../images/guide/toh/mini-hero-detail.png | Bin 4212 -> 0 bytes aio/content/navigation.json | 29 +- aio/content/tutorial/index.md | 64 +- aio/content/tutorial/toh-pt0.md | 117 ++ aio/content/tutorial/toh-pt1.md | 430 ++--- aio/content/tutorial/toh-pt2.md | 540 ++---- aio/content/tutorial/toh-pt3.md | 496 +---- aio/content/tutorial/toh-pt4.md | 887 ++++----- aio/content/tutorial/toh-pt5.md | 1617 +++++------------ aio/content/tutorial/toh-pt6.md | 802 ++++---- aio/tools/examples/run-example-e2e.js | 1 - .../boilerplate/cli/src/tsconfig.app.json | 3 +- 182 files changed, 4076 insertions(+), 5013 deletions(-) create mode 100644 aio/content/examples/toh-pt0/e2e/app.e2e-spec.ts create mode 100644 aio/content/examples/toh-pt0/example-config.json create mode 100644 aio/content/examples/toh-pt0/plnkr.json create mode 100644 aio/content/examples/toh-pt0/src/app/app.component.css create mode 100644 aio/content/examples/toh-pt0/src/app/app.component.html create mode 100644 aio/content/examples/toh-pt0/src/app/app.component.spec.ts create mode 100644 aio/content/examples/toh-pt0/src/app/app.component.ts create mode 100644 aio/content/examples/toh-pt0/src/app/app.module.ts create mode 100644 aio/content/examples/toh-pt0/src/index.html rename aio/content/examples/{toh-pt4/src/main.1.ts => toh-pt0/src/main.ts} (100%) rename aio/content/examples/{toh-pt5 => toh-pt0}/src/styles.1.css (92%) delete mode 100644 aio/content/examples/toh-pt1/app/app.component.1.ts rename aio/content/examples/toh-pt1/{e2e-spec.ts => e2e/app.e2e-spec.ts} (89%) create mode 100644 aio/content/examples/toh-pt1/src/app/app.component.css create mode 100644 aio/content/examples/toh-pt1/src/app/app.component.html create mode 100644 aio/content/examples/toh-pt1/src/app/hero.ts create mode 100644 aio/content/examples/toh-pt1/src/app/heroes/heroes.component.1.html create mode 100644 aio/content/examples/toh-pt1/src/app/heroes/heroes.component.css create mode 100644 aio/content/examples/toh-pt1/src/app/heroes/heroes.component.html create mode 100644 aio/content/examples/toh-pt1/src/app/heroes/heroes.component.spec.ts create mode 100644 aio/content/examples/toh-pt1/src/app/heroes/heroes.component.ts rename aio/content/examples/toh-pt2/{e2e-spec.ts => e2e/app.e2e-spec.ts} (91%) delete mode 100644 aio/content/examples/toh-pt2/src/app/app.component.1.html create mode 100644 aio/content/examples/toh-pt2/src/app/app.component.css create mode 100644 aio/content/examples/toh-pt2/src/app/app.component.html create mode 100644 aio/content/examples/toh-pt2/src/app/hero.ts create mode 100644 aio/content/examples/toh-pt2/src/app/heroes/heroes.component.1.html rename aio/content/examples/{toh-pt5/src/app => toh-pt2/src/app/heroes}/heroes.component.css (79%) create mode 100644 aio/content/examples/toh-pt2/src/app/heroes/heroes.component.html create mode 100644 aio/content/examples/toh-pt2/src/app/heroes/heroes.component.spec.ts create mode 100644 aio/content/examples/toh-pt2/src/app/heroes/heroes.component.ts create mode 100644 aio/content/examples/toh-pt2/src/app/mock-heroes.ts delete mode 100644 aio/content/examples/toh-pt3/app/hero-detail.component.1.ts rename aio/content/examples/toh-pt3/{e2e-spec.ts => e2e/app.e2e-spec.ts} (91%) create mode 100644 aio/content/examples/toh-pt3/src/app/app.component.css create mode 100644 aio/content/examples/toh-pt3/src/app/app.component.html delete mode 100644 aio/content/examples/toh-pt3/src/app/hero-detail.component.ts create mode 100644 aio/content/examples/toh-pt3/src/app/hero-detail/hero-detail.component.css create mode 100644 aio/content/examples/toh-pt3/src/app/hero-detail/hero-detail.component.html create mode 100644 aio/content/examples/toh-pt3/src/app/hero-detail/hero-detail.component.ts create mode 100644 aio/content/examples/toh-pt3/src/app/heroes/heroes.component.css rename aio/content/examples/toh-pt3/{app/app.component.1.html => src/app/heroes/heroes.component.html} (81%) create mode 100644 aio/content/examples/toh-pt3/src/app/heroes/heroes.component.spec.ts create mode 100644 aio/content/examples/toh-pt3/src/app/heroes/heroes.component.ts create mode 100644 aio/content/examples/toh-pt3/src/app/mock-heroes.ts rename aio/content/examples/toh-pt4/{e2e-spec.ts => e2e/app.e2e-spec.ts} (91%) delete mode 100644 aio/content/examples/toh-pt4/src/app/app.component.1.ts create mode 100644 aio/content/examples/toh-pt4/src/app/app.component.css create mode 100644 aio/content/examples/toh-pt4/src/app/app.component.html delete mode 100644 aio/content/examples/toh-pt4/src/app/hero-detail.component.ts create mode 100644 aio/content/examples/toh-pt4/src/app/hero-detail/hero-detail.component.css create mode 100644 aio/content/examples/toh-pt4/src/app/hero-detail/hero-detail.component.html create mode 100644 aio/content/examples/toh-pt4/src/app/hero-detail/hero-detail.component.ts delete mode 100644 aio/content/examples/toh-pt4/src/app/hero.service.2.ts create mode 100644 aio/content/examples/toh-pt4/src/app/heroes/heroes.component.1.ts create mode 100644 aio/content/examples/toh-pt4/src/app/heroes/heroes.component.css create mode 100644 aio/content/examples/toh-pt4/src/app/heroes/heroes.component.html create mode 100644 aio/content/examples/toh-pt4/src/app/heroes/heroes.component.spec.ts create mode 100644 aio/content/examples/toh-pt4/src/app/heroes/heroes.component.ts create mode 100644 aio/content/examples/toh-pt4/src/app/message.service.spec.ts create mode 100644 aio/content/examples/toh-pt4/src/app/message.service.ts create mode 100644 aio/content/examples/toh-pt4/src/app/messages/messages.component.css create mode 100644 aio/content/examples/toh-pt4/src/app/messages/messages.component.html create mode 100644 aio/content/examples/toh-pt4/src/app/messages/messages.component.spec.ts create mode 100644 aio/content/examples/toh-pt4/src/app/messages/messages.component.ts rename aio/content/examples/toh-pt5/{e2e-spec.ts => e2e/app.e2e-spec.ts} (74%) create mode 100644 aio/content/examples/toh-pt5/src/app/app-routing.module.0.ts delete mode 100644 aio/content/examples/toh-pt5/src/app/app.component.1.ts create mode 100644 aio/content/examples/toh-pt5/src/app/app.component.html delete mode 100644 aio/content/examples/toh-pt5/src/app/app.module.1.ts delete mode 100644 aio/content/examples/toh-pt5/src/app/app.module.2.ts delete mode 100644 aio/content/examples/toh-pt5/src/app/app.module.3.ts delete mode 100644 aio/content/examples/toh-pt5/src/app/dashboard.component.1.ts delete mode 100644 aio/content/examples/toh-pt5/src/app/dashboard.component.ts rename aio/content/examples/toh-pt5/src/app/{ => dashboard}/dashboard.component.1.html (60%) rename aio/content/examples/{toh-pt6/src/app => toh-pt5/src/app/dashboard}/dashboard.component.css (95%) rename aio/content/examples/toh-pt5/src/app/{ => dashboard}/dashboard.component.html (63%) create mode 100644 aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.spec.ts create mode 100644 aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.ts delete mode 100644 aio/content/examples/toh-pt5/src/app/hero-detail.component.1.ts delete mode 100644 aio/content/examples/toh-pt5/src/app/hero-detail.component.html delete mode 100644 aio/content/examples/toh-pt5/src/app/hero-detail.component.ts rename aio/content/examples/toh-pt5/src/app/{ => hero-detail}/hero-detail.component.css (87%) create mode 100644 aio/content/examples/toh-pt5/src/app/hero-detail/hero-detail.component.html create mode 100644 aio/content/examples/toh-pt5/src/app/hero-detail/hero-detail.component.ts delete mode 100644 aio/content/examples/toh-pt5/src/app/heroes.component.html delete mode 100644 aio/content/examples/toh-pt5/src/app/heroes.component.ts create mode 100644 aio/content/examples/toh-pt5/src/app/heroes/heroes.component.css create mode 100644 aio/content/examples/toh-pt5/src/app/heroes/heroes.component.html create mode 100644 aio/content/examples/toh-pt5/src/app/heroes/heroes.component.spec.ts create mode 100644 aio/content/examples/toh-pt5/src/app/heroes/heroes.component.ts create mode 100644 aio/content/examples/toh-pt5/src/app/message.service.spec.ts create mode 100644 aio/content/examples/toh-pt5/src/app/message.service.ts create mode 100644 aio/content/examples/toh-pt5/src/app/messages/messages.component.css create mode 100644 aio/content/examples/toh-pt5/src/app/messages/messages.component.html create mode 100644 aio/content/examples/toh-pt5/src/app/messages/messages.component.spec.ts create mode 100644 aio/content/examples/toh-pt5/src/app/messages/messages.component.ts delete mode 100644 aio/content/examples/toh-pt6/aot/index.html delete mode 100644 aio/content/examples/toh-pt6/bs-config.aot.json delete mode 100644 aio/content/examples/toh-pt6/copy-dist-files.js rename aio/content/examples/toh-pt6/{e2e-spec.ts => e2e/app.e2e-spec.ts} (70%) delete mode 100644 aio/content/examples/toh-pt6/rollup-config.js create mode 100644 aio/content/examples/toh-pt6/src/app/app.component.html delete mode 100644 aio/content/examples/toh-pt6/src/app/dashboard.component.html rename aio/content/examples/{toh-pt5/src/app => toh-pt6/src/app/dashboard}/dashboard.component.css (95%) create mode 100644 aio/content/examples/toh-pt6/src/app/dashboard/dashboard.component.html create mode 100644 aio/content/examples/toh-pt6/src/app/dashboard/dashboard.component.spec.ts rename aio/content/examples/toh-pt6/src/app/{ => dashboard}/dashboard.component.ts (56%) delete mode 100644 aio/content/examples/toh-pt6/src/app/hero-detail.component.html delete mode 100644 aio/content/examples/toh-pt6/src/app/hero-detail.component.ts rename aio/content/examples/toh-pt6/src/app/{ => hero-detail}/hero-detail.component.css (87%) create mode 100644 aio/content/examples/toh-pt6/src/app/hero-detail/hero-detail.component.html create mode 100644 aio/content/examples/toh-pt6/src/app/hero-detail/hero-detail.component.ts delete mode 100644 aio/content/examples/toh-pt6/src/app/hero-search.component.css delete mode 100644 aio/content/examples/toh-pt6/src/app/hero-search.component.html delete mode 100644 aio/content/examples/toh-pt6/src/app/hero-search.component.ts delete mode 100644 aio/content/examples/toh-pt6/src/app/hero-search.service.ts create mode 100644 aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.css create mode 100644 aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.html create mode 100644 aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.spec.ts create mode 100644 aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.ts delete mode 100644 aio/content/examples/toh-pt6/src/app/heroes.component.html delete mode 100644 aio/content/examples/toh-pt6/src/app/heroes.component.ts rename aio/content/examples/toh-pt6/src/app/{ => heroes}/heroes.component.css (75%) create mode 100644 aio/content/examples/toh-pt6/src/app/heroes/heroes.component.html create mode 100644 aio/content/examples/toh-pt6/src/app/heroes/heroes.component.spec.ts create mode 100644 aio/content/examples/toh-pt6/src/app/heroes/heroes.component.ts create mode 100644 aio/content/examples/toh-pt6/src/app/message.service.spec.ts create mode 100644 aio/content/examples/toh-pt6/src/app/message.service.ts create mode 100644 aio/content/examples/toh-pt6/src/app/messages/messages.component.css create mode 100644 aio/content/examples/toh-pt6/src/app/messages/messages.component.html create mode 100644 aio/content/examples/toh-pt6/src/app/messages/messages.component.spec.ts create mode 100644 aio/content/examples/toh-pt6/src/app/messages/messages.component.ts create mode 100644 aio/content/examples/toh-pt6/src/app/mock-heroes.ts delete mode 100644 aio/content/examples/toh-pt6/src/main-aot.ts delete mode 100644 aio/content/examples/toh-pt6/src/tsconfig.1.json delete mode 100644 aio/content/examples/toh-pt6/tsconfig-aot.json delete mode 100644 aio/content/images/guide/toh/mini-hero-detail.png create mode 100644 aio/content/tutorial/toh-pt0.md diff --git a/aio/content/examples/toh-pt0/e2e/app.e2e-spec.ts b/aio/content/examples/toh-pt0/e2e/app.e2e-spec.ts new file mode 100644 index 0000000000..fa35fd0f05 --- /dev/null +++ b/aio/content/examples/toh-pt0/e2e/app.e2e-spec.ts @@ -0,0 +1,14 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Tour of Heroes', () => { + beforeEach(() => { + return browser.get('/'); + }); + + it('should display "Tour of Heroes"', () => { + let title = element(by.css('app-root h1')).getText(); + expect(title).toEqual('Tour of Heroes'); + }); +}); diff --git a/aio/content/examples/toh-pt0/example-config.json b/aio/content/examples/toh-pt0/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/aio/content/examples/toh-pt0/plnkr.json b/aio/content/examples/toh-pt0/plnkr.json new file mode 100644 index 0000000000..3caa575acd --- /dev/null +++ b/aio/content/examples/toh-pt0/plnkr.json @@ -0,0 +1,10 @@ +{ + "description": "Tour of Heroes: Part 0", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1].*" + ], + "tags": ["tutorial", "tour", "heroes"] +} diff --git a/aio/content/examples/toh-pt0/src/app/app.component.css b/aio/content/examples/toh-pt0/src/app/app.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/aio/content/examples/toh-pt0/src/app/app.component.html b/aio/content/examples/toh-pt0/src/app/app.component.html new file mode 100644 index 0000000000..6213adcb47 --- /dev/null +++ b/aio/content/examples/toh-pt0/src/app/app.component.html @@ -0,0 +1 @@ +

{{title}}

diff --git a/aio/content/examples/toh-pt0/src/app/app.component.spec.ts b/aio/content/examples/toh-pt0/src/app/app.component.spec.ts new file mode 100644 index 0000000000..9510495a2d --- /dev/null +++ b/aio/content/examples/toh-pt0/src/app/app.component.spec.ts @@ -0,0 +1,32 @@ +import { TestBed, async } from '@angular/core/testing'; + +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + AppComponent + ], + }).compileComponents(); + })); + + it('should create the app', async(() => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + })); + + it(`should have as title 'app'`, async(() => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('app'); + })); + + it('should render title in a h1 tag', async(() => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); + })); +}); diff --git a/aio/content/examples/toh-pt0/src/app/app.component.ts b/aio/content/examples/toh-pt0/src/app/app.component.ts new file mode 100644 index 0000000000..8391a7e645 --- /dev/null +++ b/aio/content/examples/toh-pt0/src/app/app.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { +// #docregion set-title + title = 'Tour of Heroes'; +// #enddocregion set-title +} diff --git a/aio/content/examples/toh-pt0/src/app/app.module.ts b/aio/content/examples/toh-pt0/src/app/app.module.ts new file mode 100644 index 0000000000..f65716351a --- /dev/null +++ b/aio/content/examples/toh-pt0/src/app/app.module.ts @@ -0,0 +1,16 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; + +import { AppComponent } from './app.component'; + +@NgModule({ + declarations: [ + AppComponent + ], + imports: [ + BrowserModule + ], + providers: [], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/aio/content/examples/toh-pt0/src/index.html b/aio/content/examples/toh-pt0/src/index.html new file mode 100644 index 0000000000..1c4106381f --- /dev/null +++ b/aio/content/examples/toh-pt0/src/index.html @@ -0,0 +1,14 @@ + + + + + Tour of Heroes + + + + + + + + + diff --git a/aio/content/examples/toh-pt4/src/main.1.ts b/aio/content/examples/toh-pt0/src/main.ts similarity index 100% rename from aio/content/examples/toh-pt4/src/main.1.ts rename to aio/content/examples/toh-pt0/src/main.ts diff --git a/aio/content/examples/toh-pt5/src/styles.1.css b/aio/content/examples/toh-pt0/src/styles.1.css similarity index 92% rename from aio/content/examples/toh-pt5/src/styles.1.css rename to aio/content/examples/toh-pt0/src/styles.1.css index d01a0195db..7c4c2fe4c6 100644 --- a/aio/content/examples/toh-pt5/src/styles.1.css +++ b/aio/content/examples/toh-pt0/src/styles.1.css @@ -1,4 +1,4 @@ -/* Master Styles */ +/* Application-wide Styles */ h1 { color: #369; font-family: Arial, Helvetica, sans-serif; diff --git a/aio/content/examples/toh-pt1/app/app.component.1.ts b/aio/content/examples/toh-pt1/app/app.component.1.ts deleted file mode 100644 index cebe8e6759..0000000000 --- a/aio/content/examples/toh-pt1/app/app.component.1.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Component } from '@angular/core'; - -let t = { -// #docregion show-hero -template: `

{{title}}

{{hero}} details!

` -// #enddocregion show-hero -}; - -t = { -// #docregion show-hero-2 -template: `

{{title}}

{{hero.name}} details!

` -// #enddocregion show-hero-2 -}; - -t = { -// #docregion multi-line-strings -template: ` -

{{title}}

-

{{hero.name}} details!

-
{{hero.id}}
-
{{hero.name}}
- ` -// #enddocregion multi-line-strings -}; - - -/* -// #docregion name-input -
- - -
-// #enddocregion name-input -*/ - -///////////////// - -@Component(t) -// #docregion app-component-1 -export class AppComponent { - title = 'Tour of Heroes'; - hero = 'Windstorm'; -} -// #enddocregion app-component-1 diff --git a/aio/content/examples/toh-pt1/e2e-spec.ts b/aio/content/examples/toh-pt1/e2e/app.e2e-spec.ts similarity index 89% rename from aio/content/examples/toh-pt1/e2e-spec.ts rename to aio/content/examples/toh-pt1/e2e/app.e2e-spec.ts index b684a358fd..c8d2214f2b 100644 --- a/aio/content/examples/toh-pt1/e2e-spec.ts +++ b/aio/content/examples/toh-pt1/e2e/app.e2e-spec.ts @@ -4,7 +4,7 @@ import { browser, element, by, ElementFinder } from 'protractor'; import { promise } from 'selenium-webdriver'; const expectedH1 = 'Tour of Heroes'; -const expectedTitle = `Angular ${expectedH1}`; +const expectedTitle = `${expectedH1}`; class Hero { id: number; @@ -49,7 +49,7 @@ describe('Tutorial part 1', () => { let page = getPageElts(); let hero = await Hero.fromDetail(page.heroDetail); expect(hero.id).toEqual(expectedHero.id); - expect(hero.name).toEqual(expectedHero.name); + expect(hero.name).toEqual(expectedHero.name.toUpperCase()); }); it(`shows updated hero name`, async () => { @@ -58,13 +58,13 @@ describe('Tutorial part 1', () => { let hero = await Hero.fromDetail(page.heroDetail); let newName = expectedHero.name + nameSuffix; expect(hero.id).toEqual(expectedHero.id); - expect(hero.name).toEqual(newName); + expect(hero.name).toEqual(newName.toUpperCase()); }); }); function getPageElts() { return { - heroDetail: element(by.css('my-app')) + heroDetail: element(by.css('app-root')) }; } diff --git a/aio/content/examples/toh-pt1/plnkr.json b/aio/content/examples/toh-pt1/plnkr.json index ca75131d96..5ac3b2d3ce 100644 --- a/aio/content/examples/toh-pt1/plnkr.json +++ b/aio/content/examples/toh-pt1/plnkr.json @@ -4,7 +4,8 @@ "files":[ "!**/*.d.ts", "!**/*.js", - "!**/*.[1].*" + "!**/*.[1].*", + "!**/dummy.module.ts" ], "tags": ["tutorial", "tour", "heroes"] } diff --git a/aio/content/examples/toh-pt1/src/app/app.component.css b/aio/content/examples/toh-pt1/src/app/app.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/aio/content/examples/toh-pt1/src/app/app.component.html b/aio/content/examples/toh-pt1/src/app/app.component.html new file mode 100644 index 0000000000..ee3d478e16 --- /dev/null +++ b/aio/content/examples/toh-pt1/src/app/app.component.html @@ -0,0 +1,2 @@ +

{{title}}

+ diff --git a/aio/content/examples/toh-pt1/src/app/app.component.ts b/aio/content/examples/toh-pt1/src/app/app.component.ts index 602781b9ba..c41599e92a 100644 --- a/aio/content/examples/toh-pt1/src/app/app.component.ts +++ b/aio/content/examples/toh-pt1/src/app/app.component.ts @@ -1,33 +1,10 @@ -// #docregion import { Component } from '@angular/core'; -// #docregion hero-class-1 -export class Hero { - id: number; - name: string; -} -// #enddocregion hero-class-1 - @Component({ - selector: 'my-app', - // #docregion editing-Hero - template: ` -

{{title}}

-

{{hero.name}} details!

-
{{hero.id}}
-
- - -
- ` - // #enddocregion editing-Hero + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'Tour of Heroes'; - // #docregion hero-property-1 - hero: Hero = { - id: 1, - name: 'Windstorm' - }; - // #enddocregion hero-property-1 } diff --git a/aio/content/examples/toh-pt1/src/app/app.module.ts b/aio/content/examples/toh-pt1/src/app/app.module.ts index 8e87678efc..1c9d0ac4d3 100644 --- a/aio/content/examples/toh-pt1/src/app/app.module.ts +++ b/aio/content/examples/toh-pt1/src/app/app.module.ts @@ -1,18 +1,30 @@ +// #docplaster // #docregion -import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; // <-- NgModel lives here +import { NgModule } from '@angular/core'; +// #docregion formsmodule-js-import +import { FormsModule } from '@angular/forms'; // <-- NgModel lives here +// #enddocregion formsmodule-js-import -import { AppComponent } from './app.component'; +import { AppComponent } from './app.component'; +// #docregion heroes-import +import { HeroesComponent } from './heroes/heroes.component'; +// #enddocregion heroes-import @NgModule({ + // #docregion declarations + declarations: [ + AppComponent, + HeroesComponent + ], + // #enddocregion declarations + // #docregion ng-imports imports: [ BrowserModule, - FormsModule // <-- import the FormsModule before binding with [(ngModel)] + FormsModule ], - declarations: [ - AppComponent - ], - bootstrap: [ AppComponent ] + // #enddocregion ng-imports + providers: [], + bootstrap: [AppComponent] }) export class AppModule { } diff --git a/aio/content/examples/toh-pt1/src/app/hero.ts b/aio/content/examples/toh-pt1/src/app/hero.ts new file mode 100644 index 0000000000..e3eac516da --- /dev/null +++ b/aio/content/examples/toh-pt1/src/app/hero.ts @@ -0,0 +1,4 @@ +export class Hero { + id: number; + name: string; +} diff --git a/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.1.html b/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.1.html new file mode 100644 index 0000000000..1c71ce26db --- /dev/null +++ b/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.1.html @@ -0,0 +1,17 @@ + +{{hero}} + + + +

{{ hero.name }} Details

+
id: {{hero.id}}
+
name: {{hero.name}}
+ + + +
+ +
+ diff --git a/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.css b/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.html b/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.html new file mode 100644 index 0000000000..e1f98c577f --- /dev/null +++ b/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.html @@ -0,0 +1,10 @@ + + +

{{ hero.name | uppercase }} Details

+ +
id: {{hero.id}}
+
+ +
diff --git a/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.spec.ts b/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.spec.ts new file mode 100644 index 0000000000..9c3b1c4d9f --- /dev/null +++ b/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HeroesComponent } from './heroes.component'; + +describe('HeroesComponent', () => { + let component: HeroesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HeroesComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HeroesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.ts b/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.ts new file mode 100644 index 0000000000..06e5c69f51 --- /dev/null +++ b/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.ts @@ -0,0 +1,35 @@ +// #docplaster +// #docregion, v1 +import { Component, OnInit } from '@angular/core'; +// #enddocregion v1 +import { Hero } from '../hero'; +// #docregion v1 + +@Component({ + selector: 'app-heroes', + templateUrl: './heroes.component.html', + styleUrls: ['./heroes.component.css'] +}) +export class HeroesComponent implements OnInit { + // #enddocregion, v1 + /* + // #docregion add-hero + hero = 'Windstorm'; + // #enddocregion add-hero + */ + // #docregion + // #docregion hero-property-1 + hero: Hero = { + id: 1, + name: 'Windstorm' + }; + // #enddocregion hero-property-1 + // #docregion v1 + + constructor() { } + + ngOnInit() { + } + +} +// #enddocregion, v1 diff --git a/aio/content/examples/toh-pt1/src/index.html b/aio/content/examples/toh-pt1/src/index.html index bf9dae3ab7..1c4106381f 100644 --- a/aio/content/examples/toh-pt1/src/index.html +++ b/aio/content/examples/toh-pt1/src/index.html @@ -1,13 +1,14 @@ - + - - Angular Tour of Heroes - - - - + + + Tour of Heroes + - - Loading... - + + + + + + diff --git a/aio/content/examples/toh-pt2/e2e-spec.ts b/aio/content/examples/toh-pt2/e2e/app.e2e-spec.ts similarity index 91% rename from aio/content/examples/toh-pt2/e2e-spec.ts rename to aio/content/examples/toh-pt2/e2e/app.e2e-spec.ts index 53474d98b3..ea2c445804 100644 --- a/aio/content/examples/toh-pt2/e2e-spec.ts +++ b/aio/content/examples/toh-pt2/e2e/app.e2e-spec.ts @@ -4,7 +4,7 @@ import { browser, element, by, ElementFinder } from 'protractor'; import { promise } from 'selenium-webdriver'; const expectedH1 = 'Tour of Heroes'; -const expectedTitle = `Angular ${expectedH1}`; +const expectedTitle = `${expectedH1}`; const expectedH2 = 'My Heroes'; const targetHero = { id: 16, name: 'RubberMan' }; const nameSuffix = 'X'; @@ -85,7 +85,7 @@ function selectHeroTests() { let page = getPageElts(); let hero = await Hero.fromDetail(page.heroDetail); expect(hero.id).toEqual(targetHero.id); - expect(hero.name).toEqual(targetHero.name); + expect(hero.name).toEqual(targetHero.name.toUpperCase()); }); } @@ -100,7 +100,7 @@ function updateHeroTests() { let hero = await Hero.fromDetail(page.heroDetail); let newName = targetHero.name + nameSuffix; expect(hero.id).toEqual(targetHero.id); - expect(hero.name).toEqual(newName); + expect(hero.name).toEqual(newName.toUpperCase()); }); it(`shows updated hero name in list`, async () => { @@ -126,8 +126,8 @@ function expectHeading(hLevel: number, expectedText: string): void { function getPageElts() { return { - heroes: element.all(by.css('my-app li')), - selected: element(by.css('my-app li.selected')), - heroDetail: element(by.css('my-app > div, my-app > hero-detail > div')) + heroes: element.all(by.css('app-root li')), + selected: element(by.css('app-root li.selected')), + heroDetail: element(by.css('app-root > div, app-root > app-heroes > div')) }; } diff --git a/aio/content/examples/toh-pt2/src/app/app.component.1.html b/aio/content/examples/toh-pt2/src/app/app.component.1.html deleted file mode 100644 index 86f8228723..0000000000 --- a/aio/content/examples/toh-pt2/src/app/app.component.1.html +++ /dev/null @@ -1,69 +0,0 @@ - -
  • - {{hero.id}} {{hero.name}} -
  • - - - -

    My Heroes

    - - - - -
  • - ... -
  • - - - -

    {{selectedHero.name}} details!

    -
    {{selectedHero.id}}
    -
    - - -
    - - - -
    -

    {{selectedHero.name}} details!

    -
    {{selectedHero.id}}
    -
    - - -
    -
    - - - -heroes = HEROES; - - - -

    My Heroes

    - - - - -
  • - - - -[class.selected]="hero === selectedHero" - - - -
  • - {{hero.id}} {{hero.name}} -
  • - diff --git a/aio/content/examples/toh-pt2/src/app/app.component.css b/aio/content/examples/toh-pt2/src/app/app.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/aio/content/examples/toh-pt2/src/app/app.component.html b/aio/content/examples/toh-pt2/src/app/app.component.html new file mode 100644 index 0000000000..ee3d478e16 --- /dev/null +++ b/aio/content/examples/toh-pt2/src/app/app.component.html @@ -0,0 +1,2 @@ +

    {{title}}

    + diff --git a/aio/content/examples/toh-pt2/src/app/app.component.ts b/aio/content/examples/toh-pt2/src/app/app.component.ts index 3e7c86f150..c41599e92a 100644 --- a/aio/content/examples/toh-pt2/src/app/app.component.ts +++ b/aio/content/examples/toh-pt2/src/app/app.component.ts @@ -1,109 +1,10 @@ -// #docregion import { Component } from '@angular/core'; -export class Hero { - id: number; - name: string; -} - -// #docregion hero-array -const HEROES: Hero[] = [ - { id: 11, name: 'Mr. Nice' }, - { id: 12, name: 'Narco' }, - { id: 13, name: 'Bombasto' }, - { id: 14, name: 'Celeritas' }, - { id: 15, name: 'Magneta' }, - { id: 16, name: 'RubberMan' }, - { id: 17, name: 'Dynama' }, - { id: 18, name: 'Dr IQ' }, - { id: 19, name: 'Magma' }, - { id: 20, name: 'Tornado' } -]; -// #enddocregion hero-array - @Component({ - selector: 'my-app', - template: ` -

    {{title}}

    -

    My Heroes

    - -
    -

    {{selectedHero.name}} details!

    -
    {{selectedHero.id}}
    -
    - - -
    -
    - `, - // #docregion styles - styles: [` - .selected { - background-color: #CFD8DC !important; - color: white; - } - .heroes { - margin: 0 0 2em 0; - list-style-type: none; - padding: 0; - width: 15em; - } - .heroes li { - cursor: pointer; - position: relative; - left: 0; - background-color: #EEE; - margin: .5em; - padding: .3em 0; - height: 1.6em; - border-radius: 4px; - } - .heroes li.selected:hover { - background-color: #BBD8DC !important; - color: white; - } - .heroes li:hover { - color: #607D8B; - background-color: #DDD; - left: .1em; - } - .heroes .text { - position: relative; - top: -3px; - } - .heroes .badge { - display: inline-block; - font-size: small; - color: white; - padding: 0.8em 0.7em 0 0.7em; - background-color: #607D8B; - line-height: 1em; - position: relative; - left: -1px; - top: -4px; - height: 1.8em; - margin-right: .8em; - border-radius: 4px 0 0 4px; - } - `] - // #enddocregion styles + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'Tour of Heroes'; - heroes = HEROES; - // #docregion selected-hero - selectedHero: Hero; - // #enddocregion selected-hero - - // #docregion on-select - onSelect(hero: Hero): void { - this.selectedHero = hero; - } - // #enddocregion on-select } diff --git a/aio/content/examples/toh-pt2/src/app/app.module.ts b/aio/content/examples/toh-pt2/src/app/app.module.ts index 4c0b77ea48..bc5d60226c 100644 --- a/aio/content/examples/toh-pt2/src/app/app.module.ts +++ b/aio/content/examples/toh-pt2/src/app/app.module.ts @@ -1,18 +1,20 @@ -// #docregion -import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; -import { AppComponent } from './app.component'; +import { AppComponent } from './app.component'; +import { HeroesComponent } from './heroes/heroes.component'; @NgModule({ + declarations: [ + AppComponent, + HeroesComponent + ], imports: [ BrowserModule, FormsModule ], - declarations: [ - AppComponent - ], - bootstrap: [ AppComponent ] + providers: [], + bootstrap: [AppComponent] }) export class AppModule { } diff --git a/aio/content/examples/toh-pt2/src/app/hero.ts b/aio/content/examples/toh-pt2/src/app/hero.ts new file mode 100644 index 0000000000..e3eac516da --- /dev/null +++ b/aio/content/examples/toh-pt2/src/app/hero.ts @@ -0,0 +1,4 @@ +export class Hero { + id: number; + name: string; +} diff --git a/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.1.html b/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.1.html new file mode 100644 index 0000000000..fe140484f5 --- /dev/null +++ b/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.1.html @@ -0,0 +1,20 @@ + +

    My Heroes

    + + + + +
  • + + + +
  • + + + +[class.selected]="hero === selectedHero" + diff --git a/aio/content/examples/toh-pt5/src/app/heroes.component.css b/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.css similarity index 79% rename from aio/content/examples/toh-pt5/src/app/heroes.component.css rename to aio/content/examples/toh-pt2/src/app/heroes/heroes.component.css index b49fa0a419..e956eab987 100644 --- a/aio/content/examples/toh-pt5/src/app/heroes.component.css +++ b/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.css @@ -1,4 +1,4 @@ -/* #docregion */ +/* HeroesComponent's private CSS styles */ .selected { background-color: #CFD8DC !important; color: white; @@ -19,15 +19,15 @@ height: 1.6em; border-radius: 4px; } +.heroes li.selected:hover { + background-color: #BBD8DC !important; + color: white; +} .heroes li:hover { color: #607D8B; background-color: #DDD; left: .1em; } -.heroes li.selected:hover { - background-color: #BBD8DC !important; - color: white; -} .heroes .text { position: relative; top: -3px; @@ -46,15 +46,3 @@ margin-right: .8em; border-radius: 4px 0 0 4px; } -button { - font-family: Arial; - background-color: #eee; - border: none; - padding: 5px 10px; - border-radius: 4px; - cursor: pointer; - cursor: hand; -} -button:hover { - background-color: #cfd8dc; -} diff --git a/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.html b/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.html new file mode 100644 index 0000000000..a233263d84 --- /dev/null +++ b/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.html @@ -0,0 +1,27 @@ + +

    My Heroes

    +
      + +
    • + {{hero.id}} {{hero.name}} +
    • + +
    + + +
    + + +

    {{ selectedHero.name | uppercase }} Details

    +
    id: {{selectedHero.id}}
    +
    + +
    + + +
    + diff --git a/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.spec.ts b/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.spec.ts new file mode 100644 index 0000000000..9c3b1c4d9f --- /dev/null +++ b/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HeroesComponent } from './heroes.component'; + +describe('HeroesComponent', () => { + let component: HeroesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HeroesComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HeroesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.ts b/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.ts new file mode 100644 index 0000000000..bee5856586 --- /dev/null +++ b/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.ts @@ -0,0 +1,36 @@ +import { Component, OnInit } from '@angular/core'; +import { Hero } from '../hero'; +// #docregion import-heroes +import { HEROES } from '../mock-heroes'; +// #enddocregion import-heroes + +// #docplaster +// #docregion metadata +@Component({ + selector: 'app-heroes', + templateUrl: './heroes.component.html', + styleUrls: ['./heroes.component.css'] +}) +// #enddocregion metadata +export class HeroesComponent implements OnInit { + + // #docregion heroes + heroes = HEROES; + // #enddocregion heroes + + // #docregion on-select + selectedHero: Hero; + + // #enddocregion on-select + + constructor() { } + + ngOnInit() { + } + + // #docregion on-select + onSelect(hero: Hero): void { + this.selectedHero = hero; + } + // #enddocregion on-select +} diff --git a/aio/content/examples/toh-pt2/src/app/mock-heroes.ts b/aio/content/examples/toh-pt2/src/app/mock-heroes.ts new file mode 100644 index 0000000000..e84c2fd2b0 --- /dev/null +++ b/aio/content/examples/toh-pt2/src/app/mock-heroes.ts @@ -0,0 +1,14 @@ +import { Hero } from './hero'; + +export const HEROES: Hero[] = [ + { id: 11, name: 'Mr. Nice' }, + { id: 12, name: 'Narco' }, + { id: 13, name: 'Bombasto' }, + { id: 14, name: 'Celeritas' }, + { id: 15, name: 'Magneta' }, + { id: 16, name: 'RubberMan' }, + { id: 17, name: 'Dynama' }, + { id: 18, name: 'Dr IQ' }, + { id: 19, name: 'Magma' }, + { id: 20, name: 'Tornado' } +]; diff --git a/aio/content/examples/toh-pt2/src/index.html b/aio/content/examples/toh-pt2/src/index.html index bf9dae3ab7..1c4106381f 100644 --- a/aio/content/examples/toh-pt2/src/index.html +++ b/aio/content/examples/toh-pt2/src/index.html @@ -1,13 +1,14 @@ - + - - Angular Tour of Heroes - - - - + + + Tour of Heroes + - - Loading... - + + + + + + diff --git a/aio/content/examples/toh-pt3/app/hero-detail.component.1.ts b/aio/content/examples/toh-pt3/app/hero-detail.component.1.ts deleted file mode 100644 index fec477fbd7..0000000000 --- a/aio/content/examples/toh-pt3/app/hero-detail.component.1.ts +++ /dev/null @@ -1,35 +0,0 @@ -// #docplaster -// #docregion v1 -import { Component } from '@angular/core'; - -// #enddocregion v1 -// #docregion hero-import -import { Hero } from './hero'; -// #enddocregion hero-import - -// #docregion v1 -@Component({ - selector: 'hero-detail', -// #enddocregion v1 - // #docregion template - template: ` -
    -

    {{hero.name}} details!

    -
    {{hero.id}}
    -
    - - -
    -
    - ` - // #enddocregion template -// #docregion v1 -}) -export class HeroDetailComponent { -// #enddocregion v1 -// #docregion hero - hero: Hero; -// #enddocregion hero -// #docregion v1 -} -// #enddocregion v1 diff --git a/aio/content/examples/toh-pt3/e2e-spec.ts b/aio/content/examples/toh-pt3/e2e/app.e2e-spec.ts similarity index 91% rename from aio/content/examples/toh-pt3/e2e-spec.ts rename to aio/content/examples/toh-pt3/e2e/app.e2e-spec.ts index 2699ac8ccd..5c1f4028db 100644 --- a/aio/content/examples/toh-pt3/e2e-spec.ts +++ b/aio/content/examples/toh-pt3/e2e/app.e2e-spec.ts @@ -4,7 +4,7 @@ import { browser, element, by, ElementFinder } from 'protractor'; import { promise } from 'selenium-webdriver'; const expectedH1 = 'Tour of Heroes'; -const expectedTitle = `Angular ${expectedH1}`; +const expectedTitle = `${expectedH1}`; const expectedH2 = 'My Heroes'; const targetHero = { id: 16, name: 'RubberMan' }; const nameSuffix = 'X'; @@ -85,7 +85,7 @@ function selectHeroTests() { let page = getPageElts(); let hero = await Hero.fromDetail(page.heroDetail); expect(hero.id).toEqual(targetHero.id); - expect(hero.name).toEqual(targetHero.name); + expect(hero.name).toEqual(targetHero.name.toUpperCase()); }); } @@ -100,7 +100,7 @@ function updateHeroTests() { let hero = await Hero.fromDetail(page.heroDetail); let newName = targetHero.name + nameSuffix; expect(hero.id).toEqual(targetHero.id); - expect(hero.name).toEqual(newName); + expect(hero.name).toEqual(newName.toUpperCase()); }); it(`shows updated hero name in list`, async () => { @@ -126,8 +126,8 @@ function expectHeading(hLevel: number, expectedText: string): void { function getPageElts() { return { - heroes: element.all(by.css('my-app li')), - selected: element(by.css('my-app li.selected')), - heroDetail: element(by.css('my-app > div, my-app > hero-detail > div')) + heroes: element.all(by.css('app-root li')), + selected: element(by.css('app-root li.selected')), + heroDetail: element(by.css('app-root > div, app-root > app-heroes > app-hero-detail > div')) }; } diff --git a/aio/content/examples/toh-pt3/src/app/app.component.css b/aio/content/examples/toh-pt3/src/app/app.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/aio/content/examples/toh-pt3/src/app/app.component.html b/aio/content/examples/toh-pt3/src/app/app.component.html new file mode 100644 index 0000000000..ee3d478e16 --- /dev/null +++ b/aio/content/examples/toh-pt3/src/app/app.component.html @@ -0,0 +1,2 @@ +

    {{title}}

    + diff --git a/aio/content/examples/toh-pt3/src/app/app.component.ts b/aio/content/examples/toh-pt3/src/app/app.component.ts index 3e242914aa..c41599e92a 100644 --- a/aio/content/examples/toh-pt3/src/app/app.component.ts +++ b/aio/content/examples/toh-pt3/src/app/app.component.ts @@ -1,95 +1,10 @@ -// #docregion import { Component } from '@angular/core'; -// #docregion hero-import -import { Hero } from './hero'; -// #enddocregion hero-import - -const HEROES: Hero[] = [ - { id: 11, name: 'Mr. Nice' }, - { id: 12, name: 'Narco' }, - { id: 13, name: 'Bombasto' }, - { id: 14, name: 'Celeritas' }, - { id: 15, name: 'Magneta' }, - { id: 16, name: 'RubberMan' }, - { id: 17, name: 'Dynama' }, - { id: 18, name: 'Dr IQ' }, - { id: 19, name: 'Magma' }, - { id: 20, name: 'Tornado' } -]; - @Component({ - selector: 'my-app', -// #docregion hero-detail-template - template: ` -

    {{title}}

    -

    My Heroes

    -
      -
    • - {{hero.id}} {{hero.name}} -
    • -
    - - `, -// #enddocregion hero-detail-template - styles: [` - .selected { - background-color: #CFD8DC !important; - color: white; - } - .heroes { - margin: 0 0 2em 0; - list-style-type: none; - padding: 0; - width: 15em; - } - .heroes li { - cursor: pointer; - position: relative; - left: 0; - background-color: #EEE; - margin: .5em; - padding: .3em 0; - height: 1.6em; - border-radius: 4px; - } - .heroes li.selected:hover { - background-color: #BBD8DC !important; - color: white; - } - .heroes li:hover { - color: #607D8B; - background-color: #DDD; - left: .1em; - } - .heroes .text { - position: relative; - top: -3px; - } - .heroes .badge { - display: inline-block; - font-size: small; - color: white; - padding: 0.8em 0.7em 0 0.7em; - background-color: #607D8B; - line-height: 1em; - position: relative; - left: -1px; - top: -4px; - height: 1.8em; - margin-right: .8em; - border-radius: 4px 0 0 4px; - } - `] + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'Tour of Heroes'; - heroes = HEROES; - selectedHero: Hero; - - onSelect(hero: Hero): void { - this.selectedHero = hero; - } } diff --git a/aio/content/examples/toh-pt3/src/app/app.module.ts b/aio/content/examples/toh-pt3/src/app/app.module.ts index e04b8d304b..39fe27d3cf 100644 --- a/aio/content/examples/toh-pt3/src/app/app.module.ts +++ b/aio/content/examples/toh-pt3/src/app/app.module.ts @@ -1,24 +1,22 @@ -// #docregion -import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; -import { AppComponent } from './app.component'; -// #docregion hero-detail-import -import { HeroDetailComponent } from './hero-detail.component'; -// #enddocregion hero-detail-import +import { AppComponent } from './app.component'; +import { HeroesComponent } from './heroes/heroes.component'; +import { HeroDetailComponent } from './hero-detail/hero-detail.component'; @NgModule({ + declarations: [ + AppComponent, + HeroesComponent, + HeroDetailComponent + ], imports: [ BrowserModule, FormsModule ], -// #docregion declarations - declarations: [ - AppComponent, - HeroDetailComponent - ], -// #enddocregion declarations - bootstrap: [ AppComponent ] + providers: [], + bootstrap: [AppComponent] }) export class AppModule { } diff --git a/aio/content/examples/toh-pt3/src/app/hero-detail.component.ts b/aio/content/examples/toh-pt3/src/app/hero-detail.component.ts deleted file mode 100644 index 45a1a1e7e1..0000000000 --- a/aio/content/examples/toh-pt3/src/app/hero-detail.component.ts +++ /dev/null @@ -1,29 +0,0 @@ -// #docregion -// #docregion import-input -import { Component, Input } from '@angular/core'; -// #enddocregion import-input - -import { Hero } from './hero'; -// #docregion template -@Component({ - selector: 'hero-detail', - template: ` -
    -

    {{hero.name}} details!

    -
    {{hero.id}}
    -
    - - -
    -
    - ` -}) -// #enddocregion template -// #docregion class -export class HeroDetailComponent { -// #docregion hero - @Input() hero: Hero; -// #enddocregion hero -} -// #enddocregion class - diff --git a/aio/content/examples/toh-pt3/src/app/hero-detail/hero-detail.component.css b/aio/content/examples/toh-pt3/src/app/hero-detail/hero-detail.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/aio/content/examples/toh-pt3/src/app/hero-detail/hero-detail.component.html b/aio/content/examples/toh-pt3/src/app/hero-detail/hero-detail.component.html new file mode 100644 index 0000000000..b2b52432a0 --- /dev/null +++ b/aio/content/examples/toh-pt3/src/app/hero-detail/hero-detail.component.html @@ -0,0 +1,11 @@ +
    + +

    {{ hero.name | uppercase }} Details

    +
    id: {{hero.id}}
    +
    + +
    + +
    diff --git a/aio/content/examples/toh-pt3/src/app/hero-detail/hero-detail.component.ts b/aio/content/examples/toh-pt3/src/app/hero-detail/hero-detail.component.ts new file mode 100644 index 0000000000..973c5b2b5a --- /dev/null +++ b/aio/content/examples/toh-pt3/src/app/hero-detail/hero-detail.component.ts @@ -0,0 +1,24 @@ +// #docregion +// #docregion import-input +import { Component, OnInit, Input } from '@angular/core'; +// #enddocregion import-input +// #docregion import-hero +import { Hero } from '../hero'; +// #enddocregion import-hero + +@Component({ + selector: 'app-hero-detail', + templateUrl: './hero-detail.component.html', + styleUrls: ['./hero-detail.component.css'] +}) +export class HeroDetailComponent implements OnInit { + // #docregion input-hero + @Input() hero: Hero; + // #enddocregion input-hero + + constructor() { } + + ngOnInit() { + } + +} diff --git a/aio/content/examples/toh-pt3/src/app/hero.ts b/aio/content/examples/toh-pt3/src/app/hero.ts index f4b0cd6b35..8f7cc205c8 100644 --- a/aio/content/examples/toh-pt3/src/app/hero.ts +++ b/aio/content/examples/toh-pt3/src/app/hero.ts @@ -3,4 +3,3 @@ export class Hero { id: number; name: string; } -// #enddocregion diff --git a/aio/content/examples/toh-pt3/src/app/heroes/heroes.component.css b/aio/content/examples/toh-pt3/src/app/heroes/heroes.component.css new file mode 100644 index 0000000000..e956eab987 --- /dev/null +++ b/aio/content/examples/toh-pt3/src/app/heroes/heroes.component.css @@ -0,0 +1,48 @@ +/* HeroesComponent's private CSS styles */ +.selected { + background-color: #CFD8DC !important; + color: white; +} +.heroes { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 15em; +} +.heroes li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.heroes li.selected:hover { + background-color: #BBD8DC !important; + color: white; +} +.heroes li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} +.heroes .text { + position: relative; + top: -3px; +} +.heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} diff --git a/aio/content/examples/toh-pt3/app/app.component.1.html b/aio/content/examples/toh-pt3/src/app/heroes/heroes.component.html similarity index 81% rename from aio/content/examples/toh-pt3/app/app.component.1.html rename to aio/content/examples/toh-pt3/src/app/heroes/heroes.component.html index 8b6c3b0d82..2a78dbaa33 100644 --- a/aio/content/examples/toh-pt3/app/app.component.1.html +++ b/aio/content/examples/toh-pt3/src/app/heroes/heroes.component.html @@ -1,5 +1,5 @@ -

    {{title}}

    My Heroes

    +
    • {{hero.id}} {{hero.name}}
    + - + diff --git a/aio/content/examples/toh-pt3/src/app/heroes/heroes.component.spec.ts b/aio/content/examples/toh-pt3/src/app/heroes/heroes.component.spec.ts new file mode 100644 index 0000000000..9c3b1c4d9f --- /dev/null +++ b/aio/content/examples/toh-pt3/src/app/heroes/heroes.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HeroesComponent } from './heroes.component'; + +describe('HeroesComponent', () => { + let component: HeroesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HeroesComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HeroesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/toh-pt3/src/app/heroes/heroes.component.ts b/aio/content/examples/toh-pt3/src/app/heroes/heroes.component.ts new file mode 100644 index 0000000000..35462026c7 --- /dev/null +++ b/aio/content/examples/toh-pt3/src/app/heroes/heroes.component.ts @@ -0,0 +1,25 @@ +import { Component, OnInit } from '@angular/core'; +import { Hero } from '../hero'; +import { HEROES } from '../mock-heroes'; + +@Component({ + selector: 'app-heroes', + templateUrl: './heroes.component.html', + styleUrls: ['./heroes.component.css'] +}) +export class HeroesComponent implements OnInit { + + heroes = HEROES; + + selectedHero: Hero; + + constructor() { } + + ngOnInit() { + } + + onSelect(hero: Hero): void { + this.selectedHero = hero; + } +} + diff --git a/aio/content/examples/toh-pt3/src/app/mock-heroes.ts b/aio/content/examples/toh-pt3/src/app/mock-heroes.ts new file mode 100644 index 0000000000..e84c2fd2b0 --- /dev/null +++ b/aio/content/examples/toh-pt3/src/app/mock-heroes.ts @@ -0,0 +1,14 @@ +import { Hero } from './hero'; + +export const HEROES: Hero[] = [ + { id: 11, name: 'Mr. Nice' }, + { id: 12, name: 'Narco' }, + { id: 13, name: 'Bombasto' }, + { id: 14, name: 'Celeritas' }, + { id: 15, name: 'Magneta' }, + { id: 16, name: 'RubberMan' }, + { id: 17, name: 'Dynama' }, + { id: 18, name: 'Dr IQ' }, + { id: 19, name: 'Magma' }, + { id: 20, name: 'Tornado' } +]; diff --git a/aio/content/examples/toh-pt3/src/index.html b/aio/content/examples/toh-pt3/src/index.html index bf9dae3ab7..1c4106381f 100644 --- a/aio/content/examples/toh-pt3/src/index.html +++ b/aio/content/examples/toh-pt3/src/index.html @@ -1,13 +1,14 @@ - + - - Angular Tour of Heroes - - - - + + + Tour of Heroes + - - Loading... - + + + + + + diff --git a/aio/content/examples/toh-pt3/src/main.ts b/aio/content/examples/toh-pt3/src/main.ts index fd8f859f5c..6fd45e7d1e 100644 --- a/aio/content/examples/toh-pt3/src/main.ts +++ b/aio/content/examples/toh-pt3/src/main.ts @@ -1,4 +1,4 @@ -// #docregion pt1 +// #docregion import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; @@ -10,4 +10,4 @@ if (environment.production) { } platformBrowserDynamic().bootstrapModule(AppModule); -// #enddocregion pt1 +// #enddocregion diff --git a/aio/content/examples/toh-pt4/e2e-spec.ts b/aio/content/examples/toh-pt4/e2e/app.e2e-spec.ts similarity index 91% rename from aio/content/examples/toh-pt4/e2e-spec.ts rename to aio/content/examples/toh-pt4/e2e/app.e2e-spec.ts index 3a008d27f4..bd71754bbb 100644 --- a/aio/content/examples/toh-pt4/e2e-spec.ts +++ b/aio/content/examples/toh-pt4/e2e/app.e2e-spec.ts @@ -4,7 +4,7 @@ import { browser, element, by, ElementFinder } from 'protractor'; import { promise } from 'selenium-webdriver'; const expectedH1 = 'Tour of Heroes'; -const expectedTitle = `Angular ${expectedH1}`; +const expectedTitle = `${expectedH1}`; const expectedH2 = 'My Heroes'; const targetHero = { id: 16, name: 'RubberMan' }; const nameSuffix = 'X'; @@ -85,7 +85,7 @@ function selectHeroTests() { let page = getPageElts(); let hero = await Hero.fromDetail(page.heroDetail); expect(hero.id).toEqual(targetHero.id); - expect(hero.name).toEqual(targetHero.name); + expect(hero.name).toEqual(targetHero.name.toUpperCase()); }); } @@ -100,7 +100,7 @@ function updateHeroTests() { let hero = await Hero.fromDetail(page.heroDetail); let newName = targetHero.name + nameSuffix; expect(hero.id).toEqual(targetHero.id); - expect(hero.name).toEqual(newName); + expect(hero.name).toEqual(newName.toUpperCase()); }); it(`shows updated hero name in list`, async () => { @@ -126,8 +126,8 @@ function expectHeading(hLevel: number, expectedText: string): void { function getPageElts() { return { - heroes: element.all(by.css('my-app li')), - selected: element(by.css('my-app li.selected')), - heroDetail: element(by.css('my-app > div, my-app > hero-detail > div')) + heroes: element.all(by.css('app-root li')), + selected: element(by.css('app-root li.selected')), + heroDetail: element(by.css('app-root > div, app-root > app-heroes > app-hero-detail > div')) }; } diff --git a/aio/content/examples/toh-pt4/src/app/app.component.1.ts b/aio/content/examples/toh-pt4/src/app/app.component.1.ts deleted file mode 100644 index cfddbab537..0000000000 --- a/aio/content/examples/toh-pt4/src/app/app.component.1.ts +++ /dev/null @@ -1,65 +0,0 @@ -// #docplaster -// #docregion on-init -import { OnInit } from '@angular/core'; - -// #enddocregion on-init -import { Component } from '@angular/core'; - -import { Hero } from './hero'; -// #docregion hero-service-import -import { HeroService } from './hero.service.2'; -// #enddocregion hero-service-import - -// Testable but never shown -@Component({ - selector: 'my-app', - template: ` -
    - {{hero.name}} -
    - - `, - // #docregion providers - providers: [HeroService] - // #enddocregion providers -}) -// #docregion on-init -export class AppComponent implements OnInit { - // #enddocregion on-init - title = 'Tour of Heroes'; - // #docregion heroes-prop - heroes: Hero[]; - // #enddocregion heroes-prop - selectedHero: Hero; - - /* - // #docregion new-service - heroService = new HeroService(); // don't do this - // #enddocregion new-service - */ - // #docregion ctor - constructor(private heroService: HeroService) { } - // #enddocregion ctor - // #docregion getHeroes - getHeroes(): void { - // #docregion get-heroes - this.heroes = this.heroService.getHeroes(); - // #enddocregion get-heroes - } - // #enddocregion getHeroes - - // #docregion ng-on-init - // #docregion on-init - ngOnInit(): void { - // #enddocregion on-init - this.getHeroes(); - // #docregion on-init - } - // #enddocregion on-init - // #enddocregion ng-on-init - - onSelect(hero: Hero): void { - this.selectedHero = hero; - } - // #docregion on-init -} diff --git a/aio/content/examples/toh-pt4/src/app/app.component.css b/aio/content/examples/toh-pt4/src/app/app.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/aio/content/examples/toh-pt4/src/app/app.component.html b/aio/content/examples/toh-pt4/src/app/app.component.html new file mode 100644 index 0000000000..cb45ac499a --- /dev/null +++ b/aio/content/examples/toh-pt4/src/app/app.component.html @@ -0,0 +1,3 @@ +

    {{title}}

    + + diff --git a/aio/content/examples/toh-pt4/src/app/app.component.ts b/aio/content/examples/toh-pt4/src/app/app.component.ts index 0d57acb5b0..c41599e92a 100644 --- a/aio/content/examples/toh-pt4/src/app/app.component.ts +++ b/aio/content/examples/toh-pt4/src/app/app.component.ts @@ -1,97 +1,10 @@ -// #docplaster -// #docregion -import { Component, OnInit } from '@angular/core'; - -import { Hero } from './hero'; -// #docregion hero-service-import -import { HeroService } from './hero.service'; -// #enddocregion hero-service-import +import { Component } from '@angular/core'; @Component({ - selector: 'my-app', - // #docregion template - template: ` -

    {{title}}

    -

    My Heroes

    -
      -
    • - {{hero.id}} {{hero.name}} -
    • -
    - - `, - // #enddocregion template - styles: [` - .selected { - background-color: #CFD8DC !important; - color: white; - } - .heroes { - margin: 0 0 2em 0; - list-style-type: none; - padding: 0; - width: 15em; - } - .heroes li { - cursor: pointer; - position: relative; - left: 0; - background-color: #EEE; - margin: .5em; - padding: .3em 0; - height: 1.6em; - border-radius: 4px; - } - .heroes li.selected:hover { - background-color: #BBD8DC !important; - color: white; - } - .heroes li:hover { - color: #607D8B; - background-color: #DDD; - left: .1em; - } - .heroes .text { - position: relative; - top: -3px; - } - .heroes .badge { - display: inline-block; - font-size: small; - color: white; - padding: 0.8em 0.7em 0 0.7em; - background-color: #607D8B; - line-height: 1em; - position: relative; - left: -1px; - top: -4px; - height: 1.8em; - margin-right: .8em; - border-radius: 4px 0 0 4px; - } - `], - providers: [HeroService] + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] }) -export class AppComponent implements OnInit { +export class AppComponent { title = 'Tour of Heroes'; - heroes: Hero[]; - selectedHero: Hero; - - constructor(private heroService: HeroService) { } - -// #docregion get-heroes - getHeroes(): void { - this.heroService.getHeroes().then(heroes => this.heroes = heroes); - } -// #enddocregion get-heroes - - ngOnInit(): void { - this.getHeroes(); - } - - onSelect(hero: Hero): void { - this.selectedHero = hero; - } } diff --git a/aio/content/examples/toh-pt4/src/app/app.module.ts b/aio/content/examples/toh-pt4/src/app/app.module.ts index 3df186c62a..70b26976da 100644 --- a/aio/content/examples/toh-pt4/src/app/app.module.ts +++ b/aio/content/examples/toh-pt4/src/app/app.module.ts @@ -1,19 +1,28 @@ -import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; -import { AppComponent } from './app.component'; -import { HeroDetailComponent } from './hero-detail.component'; +import { AppComponent } from './app.component'; +import { HeroesComponent } from './heroes/heroes.component'; +import { HeroDetailComponent } from './hero-detail/hero-detail.component'; +import { HeroService } from './hero.service'; +import { MessageService } from './message.service'; +import { MessagesComponent } from './messages/messages.component'; @NgModule({ + declarations: [ + AppComponent, + HeroesComponent, + HeroDetailComponent, + MessagesComponent + ], imports: [ BrowserModule, FormsModule ], - declarations: [ - AppComponent, - HeroDetailComponent - ], + // #docregion providers + providers: [ HeroService, MessageService ], + // #enddocregion providers bootstrap: [ AppComponent ] }) export class AppModule { } diff --git a/aio/content/examples/toh-pt4/src/app/hero-detail.component.ts b/aio/content/examples/toh-pt4/src/app/hero-detail.component.ts deleted file mode 100644 index 865fb98da7..0000000000 --- a/aio/content/examples/toh-pt4/src/app/hero-detail.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -// #docregion -import { Component, Input } from '@angular/core'; -import { Hero } from './hero'; - -@Component({ - selector: 'hero-detail', - template: ` -
    -

    {{hero.name}} details!

    -
    - {{hero.id}} -
    -
    - - -
    -
    - ` -}) -export class HeroDetailComponent { - @Input() hero: Hero; -} diff --git a/aio/content/examples/toh-pt4/src/app/hero-detail/hero-detail.component.css b/aio/content/examples/toh-pt4/src/app/hero-detail/hero-detail.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/aio/content/examples/toh-pt4/src/app/hero-detail/hero-detail.component.html b/aio/content/examples/toh-pt4/src/app/hero-detail/hero-detail.component.html new file mode 100644 index 0000000000..9195b8aa85 --- /dev/null +++ b/aio/content/examples/toh-pt4/src/app/hero-detail/hero-detail.component.html @@ -0,0 +1,9 @@ +
    +

    {{ hero.name | uppercase }} Details

    +
    id: {{hero.id}}
    +
    + +
    +
    diff --git a/aio/content/examples/toh-pt4/src/app/hero-detail/hero-detail.component.ts b/aio/content/examples/toh-pt4/src/app/hero-detail/hero-detail.component.ts new file mode 100644 index 0000000000..2edf9bba38 --- /dev/null +++ b/aio/content/examples/toh-pt4/src/app/hero-detail/hero-detail.component.ts @@ -0,0 +1,20 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { Hero } from '../hero'; + +@Component({ + selector: 'app-hero-detail', + templateUrl: './hero-detail.component.html', + styleUrls: ['./hero-detail.component.css'] +}) +export class HeroDetailComponent implements OnInit { + + // #docregion hero + @Input() hero: Hero; + // #enddocregion hero + + constructor() { } + + ngOnInit() { + } + +} diff --git a/aio/content/examples/toh-pt4/src/app/hero.service.1.ts b/aio/content/examples/toh-pt4/src/app/hero.service.1.ts index 2366215259..84f5eed9ce 100644 --- a/aio/content/examples/toh-pt4/src/app/hero.service.1.ts +++ b/aio/content/examples/toh-pt4/src/app/hero.service.1.ts @@ -1,24 +1,24 @@ +/* Newly generated and synchronous versions */ // #docplaster -// #docregion -// #docregion empty-class, full +// #docregion, new import { Injectable } from '@angular/core'; -// #enddocregion empty-class +// #enddocregion new import { Hero } from './hero'; import { HEROES } from './mock-heroes'; -// #docregion empty-class, getHeroes-stub +// #docregion new @Injectable() export class HeroService { - // #enddocregion empty-class, getHeroes-stub, full - /* - // #docregion getHeroes-stub - getHeroes(): void {} // stub - // #enddocregion getHeroes-stub - */ - // #docregion full + + constructor() { } + + // #enddocregion new + // #docregion getHeroes getHeroes(): Hero[] { return HEROES; } - // #docregion empty-class, getHeroes-stub + // #enddocregion getHeroes + // #docregion new } +// #enddocregion, new diff --git a/aio/content/examples/toh-pt4/src/app/hero.service.2.ts b/aio/content/examples/toh-pt4/src/app/hero.service.2.ts deleted file mode 100644 index d14fe02410..0000000000 --- a/aio/content/examples/toh-pt4/src/app/hero.service.2.ts +++ /dev/null @@ -1,13 +0,0 @@ -// #docregion -import { Injectable } from '@angular/core'; - -import { Hero } from './hero'; -import { HEROES } from './mock-heroes'; - -@Injectable() -export class HeroService { - - getHeroes(): Hero[] { - return HEROES; - } -} diff --git a/aio/content/examples/toh-pt4/src/app/hero.service.ts b/aio/content/examples/toh-pt4/src/app/hero.service.ts index 03a1c10a4a..4129689f5e 100644 --- a/aio/content/examples/toh-pt4/src/app/hero.service.ts +++ b/aio/content/examples/toh-pt4/src/app/hero.service.ts @@ -1,29 +1,35 @@ // #docplaster // #docregion -// #docregion just-get-heroes import { Injectable } from '@angular/core'; +// #docregion import-observable +import { Observable } from 'rxjs/Rx'; +import { of } from 'rxjs/observable/of'; +// #enddocregion import-observable + +// #docregion import-heroes import { Hero } from './hero'; import { HEROES } from './mock-heroes'; +// #enddocregion import-heroes +// #docregion import-message-service +import { MessageService } from './message.service'; +// #enddocregion import-message-service @Injectable() export class HeroService { - // #docregion get-heroes - getHeroes(): Promise { - return Promise.resolve(HEROES); - } - // #enddocregion get-heroes, just-get-heroes - // #enddocregion - // See the "Take it slow" appendix - // #docregion get-heroes-slowly - getHeroesSlowly(): Promise { - return new Promise(resolve => { - // Simulate server latency with 2 second delay - setTimeout(() => resolve(this.getHeroes()), 2000); - }); + // #docregion ctor + constructor(private messageService: MessageService) { } + // #enddocregion ctor + + // #docregion getHeroes, getHeroes-1 + getHeroes(): Observable { + // #enddocregion getHeroes-1 + // Todo: send the message _after_ fetching the heroes + this.messageService.add('HeroService: fetched heroes'); + // #docregion getHeroes-1 + return of(HEROES); } - // #enddocregion get-heroes-slowly - // #docregion - // #docregion just-get-heroes + // #enddocregion getHeroes, getHeroes-1 } +// #enddocregion diff --git a/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.1.ts b/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.1.ts new file mode 100644 index 0000000000..28de0d1f0a --- /dev/null +++ b/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.1.ts @@ -0,0 +1,19 @@ +import { Hero } from '../hero'; +import { HeroService } from '../hero.service'; +import { Observable } from 'rxjs/Observable'; + +class DummyHeroesComponent { + + heroes: Observable; + + constructor(private heroService: HeroService) {} + + // #docregion getHeroes + getHeroes(): void { + // #docregion get-heroes + this.heroes = this.heroService.getHeroes(); + // #enddocregion get-heroes + } + // #enddocregion getHeroes +} + diff --git a/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.css b/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.css new file mode 100644 index 0000000000..4bef1bb3c4 --- /dev/null +++ b/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.css @@ -0,0 +1,50 @@ +/* HeroesComponent's private CSS styles */ +.selected { + background-color: #CFD8DC !important; + color: white; +} +.heroes { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 15em; +} +.heroes li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.heroes li.selected:hover { + background-color: #BBD8DC !important; + color: white; +} +.heroes li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} +.heroes .text { + position: relative; + top: -3px; +} +.heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + min-width: 16px; + text-align: right; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} diff --git a/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.html b/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.html new file mode 100644 index 0000000000..fdddd6823b --- /dev/null +++ b/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.html @@ -0,0 +1,14 @@ +

    My Heroes

    + +
      +
    • + {{hero.id}} {{hero.name}} +
    • +
    + + + + + diff --git a/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.spec.ts b/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.spec.ts new file mode 100644 index 0000000000..9c3b1c4d9f --- /dev/null +++ b/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HeroesComponent } from './heroes.component'; + +describe('HeroesComponent', () => { + let component: HeroesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HeroesComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HeroesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.ts b/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.ts new file mode 100644 index 0000000000..7fdc68a057 --- /dev/null +++ b/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.ts @@ -0,0 +1,43 @@ +// #docplaster +// #docregion +import { Component, OnInit } from '@angular/core'; + +import { Hero } from '../hero'; +// #docregion hero-service-import +import { HeroService } from '../hero.service'; +// #enddocregion hero-service-import + +@Component({ + selector: 'app-heroes', + templateUrl: './heroes.component.html', + styleUrls: ['./heroes.component.css'] +}) +export class HeroesComponent implements OnInit { + + selectedHero: Hero; + + // #docregion heroes + heroes: Hero[]; + // #enddocregion heroes + + // #docregion ctor + constructor(private heroService: HeroService) { } + // #enddocregion ctor + + // #docregion ng-on-init + ngOnInit() { + this.getHeroes(); + } + // #enddocregion ng-on-init + + onSelect(hero: Hero): void { + this.selectedHero = hero; + } + + // #docregion getHeroes + getHeroes(): void { + this.heroService.getHeroes() + .subscribe(heroes => this.heroes = heroes); + } + // #enddocregion getHeroes +} diff --git a/aio/content/examples/toh-pt4/src/app/message.service.spec.ts b/aio/content/examples/toh-pt4/src/app/message.service.spec.ts new file mode 100644 index 0000000000..63ecfd8ff6 --- /dev/null +++ b/aio/content/examples/toh-pt4/src/app/message.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { MessageService } from './message.service'; + +describe('MessageService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [MessageService] + }); + }); + + it('should be created', inject([MessageService], (service: MessageService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/aio/content/examples/toh-pt4/src/app/message.service.ts b/aio/content/examples/toh-pt4/src/app/message.service.ts new file mode 100644 index 0000000000..9b3a2cac05 --- /dev/null +++ b/aio/content/examples/toh-pt4/src/app/message.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class MessageService { + messages: string[] = []; + + add(message: string) { + this.messages.push(message); + } + + clear() { + this.messages.length = 0; + } +} diff --git a/aio/content/examples/toh-pt4/src/app/messages/messages.component.css b/aio/content/examples/toh-pt4/src/app/messages/messages.component.css new file mode 100644 index 0000000000..d08d9be581 --- /dev/null +++ b/aio/content/examples/toh-pt4/src/app/messages/messages.component.css @@ -0,0 +1,35 @@ +/* MessagesComponent's private CSS styles */ +h2 { + color: red; + font-family: Arial, Helvetica, sans-serif; + font-weight: lighter; +} +body { + margin: 2em; +} +body, input[text], button { + color: crimson; + font-family: Cambria, Georgia; +} + +button.clear { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #aaa; + cursor: auto; +} +button.clear { + color: #888; + margin-bottom: 12px; +} diff --git a/aio/content/examples/toh-pt4/src/app/messages/messages.component.html b/aio/content/examples/toh-pt4/src/app/messages/messages.component.html new file mode 100644 index 0000000000..1df7dfd989 --- /dev/null +++ b/aio/content/examples/toh-pt4/src/app/messages/messages.component.html @@ -0,0 +1,8 @@ +
    + +

    Messages

    + +
    {{message}}
    + +
    diff --git a/aio/content/examples/toh-pt4/src/app/messages/messages.component.spec.ts b/aio/content/examples/toh-pt4/src/app/messages/messages.component.spec.ts new file mode 100644 index 0000000000..3c2b2b1537 --- /dev/null +++ b/aio/content/examples/toh-pt4/src/app/messages/messages.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MessagesComponent } from './messages.component'; + +describe('MessagesComponent', () => { + let component: MessagesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MessagesComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MessagesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/toh-pt4/src/app/messages/messages.component.ts b/aio/content/examples/toh-pt4/src/app/messages/messages.component.ts new file mode 100644 index 0000000000..8a819207fb --- /dev/null +++ b/aio/content/examples/toh-pt4/src/app/messages/messages.component.ts @@ -0,0 +1,21 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +// #docregion import-message-service +import { MessageService } from '../message.service'; +// #enddocregion import-message-service + +@Component({ + selector: 'app-messages', + templateUrl: './messages.component.html', + styleUrls: ['./messages.component.css'] +}) +export class MessagesComponent implements OnInit { + + // #docregion ctor + constructor(public messageService: MessageService) {} + // #enddocregion ctor + + ngOnInit() { + } + +} diff --git a/aio/content/examples/toh-pt4/src/index.html b/aio/content/examples/toh-pt4/src/index.html index bf9dae3ab7..1c4106381f 100644 --- a/aio/content/examples/toh-pt4/src/index.html +++ b/aio/content/examples/toh-pt4/src/index.html @@ -1,13 +1,14 @@ - + - - Angular Tour of Heroes - - - - + + + Tour of Heroes + - - Loading... - + + + + + + diff --git a/aio/content/examples/toh-pt5/e2e-spec.ts b/aio/content/examples/toh-pt5/e2e/app.e2e-spec.ts similarity index 74% rename from aio/content/examples/toh-pt5/e2e-spec.ts rename to aio/content/examples/toh-pt5/e2e/app.e2e-spec.ts index a49f2ddb62..e94b7e6ca6 100644 --- a/aio/content/examples/toh-pt5/e2e-spec.ts +++ b/aio/content/examples/toh-pt5/e2e/app.e2e-spec.ts @@ -4,7 +4,7 @@ import { browser, element, by, ElementFinder } from 'protractor'; import { promise } from 'selenium-webdriver'; const expectedH1 = 'Tour of Heroes'; -const expectedTitle = `Angular ${expectedH1}`; +const expectedTitle = `${expectedH1}`; const targetHero = { id: 15, name: 'Magneta' }; const targetHeroDashboardIndex = 3; const nameSuffix = 'X'; @@ -42,22 +42,19 @@ describe('Tutorial part 5', () => { beforeAll(() => browser.get('')); function getPageElts() { - let navElts = element.all(by.css('my-app nav a')); + let navElts = element.all(by.css('app-root nav a')); return { navElts: navElts, - myDashboardHref: navElts.get(0), - myDashboard: element(by.css('my-app my-dashboard')), - topHeroes: element.all(by.css('my-app my-dashboard > div h4')), + appDashboardHref: navElts.get(0), + appDashboard: element(by.css('app-root app-dashboard')), + topHeroes: element.all(by.css('app-root app-dashboard > div h4')), - myHeroesHref: navElts.get(1), - myHeroes: element(by.css('my-app my-heroes')), - allHeroes: element.all(by.css('my-app my-heroes li')), - selectedHero: element(by.css('my-app li.selected')), - selectedHeroSubview: element(by.css('my-app my-heroes > div')), - - heroDetail: element(by.css('my-app hero-detail > div')) + appHeroesHref: navElts.get(1), + appHeroes: element(by.css('app-root app-heroes')), + allHeroes: element.all(by.css('app-root app-heroes li')), + heroDetail: element(by.css('app-root app-hero-detail > div')) }; } @@ -79,7 +76,7 @@ describe('Tutorial part 5', () => { it('has dashboard as the active view', () => { let page = getPageElts(); - expect(page.myDashboard.isPresent()).toBeTruthy(); + expect(page.appDashboard.isPresent()).toBeTruthy(); }); }); @@ -98,7 +95,7 @@ describe('Tutorial part 5', () => { it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); it(`saves and shows ${newHeroName} in Dashboard`, () => { - element(by.buttonText('Back')).click(); + element(by.buttonText('go back')).click(); let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); expect(targetHeroElt.getText()).toEqual(newHeroName); }); @@ -110,39 +107,26 @@ describe('Tutorial part 5', () => { beforeAll(() => browser.get('')); it('can switch to Heroes view', () => { - getPageElts().myHeroesHref.click(); + getPageElts().appHeroesHref.click(); let page = getPageElts(); - expect(page.myHeroes.isPresent()).toBeTruthy(); + expect(page.appHeroes.isPresent()).toBeTruthy(); expect(page.allHeroes.count()).toEqual(10, 'number of heroes'); }); - it(`selects and shows ${targetHero.name} as selected in list`, () => { - getHeroLiEltById(targetHero.id).click(); - let expectedText = `${targetHero.id} ${targetHero.name}`; - expect(getPageElts().selectedHero.getText()).toBe(expectedText); - }); - - it('shows selected hero subview', async () => { - let page = getPageElts(); - let title = page.selectedHeroSubview.element(by.css('h2')).getText(); - let expectedTitle = `${targetHero.name.toUpperCase()} is my hero`; - expect(title).toEqual(expectedTitle); - }); - it('can route to hero details', async () => { - element(by.buttonText('View Details')).click(); + getHeroLiEltById(targetHero.id).click(); let page = getPageElts(); expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); let hero = await Hero.fromDetail(page.heroDetail); expect(hero.id).toEqual(targetHero.id); - expect(hero.name).toEqual(targetHero.name); + expect(hero.name).toEqual(targetHero.name.toUpperCase()); }); it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); it(`shows ${newHeroName} in Heroes list`, () => { - element(by.buttonText('Back')).click(); + element(by.buttonText('go back')).click(); let expectedText = `${targetHero.id} ${newHeroName}`; expect(getHeroLiEltById(targetHero.id).getText()).toEqual(expectedText); }); @@ -158,7 +142,7 @@ describe('Tutorial part 5', () => { expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); let hero = await Hero.fromDetail(page.heroDetail); expect(hero.id).toEqual(targetHero.id); - expect(hero.name).toEqual(targetHero.name); + expect(hero.name).toEqual(targetHero.name.toUpperCase()); } async function updateHeroNameInDetailView() { @@ -168,7 +152,7 @@ describe('Tutorial part 5', () => { let page = getPageElts(); let hero = await Hero.fromDetail(page.heroDetail); expect(hero.id).toEqual(targetHero.id); - expect(hero.name).toEqual(newHeroName); + expect(hero.name).toEqual(newHeroName.toUpperCase()); } }); diff --git a/aio/content/examples/toh-pt5/plnkr.json b/aio/content/examples/toh-pt5/plnkr.json index db4b15d160..df6999a611 100644 --- a/aio/content/examples/toh-pt5/plnkr.json +++ b/aio/content/examples/toh-pt5/plnkr.json @@ -4,7 +4,7 @@ "files":[ "!**/*.d.ts", "!**/*.js", - "!**/*.[1,2,3].*" + "!**/*.[0,1,2,3].*" ], "tags": ["tutorial", "tour", "heroes", "router"] } diff --git a/aio/content/examples/toh-pt5/src/app/app-routing.module.0.ts b/aio/content/examples/toh-pt5/src/app/app-routing.module.0.ts new file mode 100644 index 0000000000..c855135b75 --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/app-routing.module.0.ts @@ -0,0 +1,10 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +@NgModule({ + imports: [ + CommonModule + ], + declarations: [] +}) +export class AppRoutingModule { } diff --git a/aio/content/examples/toh-pt5/src/app/app-routing.module.ts b/aio/content/examples/toh-pt5/src/app/app-routing.module.ts index dfd957782b..bfdcb7d5ec 100644 --- a/aio/content/examples/toh-pt5/src/app/app-routing.module.ts +++ b/aio/content/examples/toh-pt5/src/app/app-routing.module.ts @@ -1,20 +1,45 @@ -// #docregion +// #docplaster +// #docregion , v1 import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; -import { DashboardComponent } from './dashboard.component'; -import { HeroesComponent } from './heroes.component'; -import { HeroDetailComponent } from './hero-detail.component'; +// #enddocregion v1 +// #docregion import-dashboard +import { DashboardComponent } from './dashboard/dashboard.component'; +// #enddocregion import-dashboard +// #docregion heroes-route +import { HeroesComponent } from './heroes/heroes.component'; +// #enddocregion heroes-route +// #docregion import-herodetail +import { HeroDetailComponent } from './hero-detail/hero-detail.component'; +// #enddocregion import-herodetail +// #docregion heroes-route +// #docregion routes const routes: Routes = [ + // #enddocregion heroes-route + // #docregion redirect-route { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, - { path: 'dashboard', component: DashboardComponent }, + // #enddocregion redirect-route + // #docregion dashboard-route + { path: 'dashboard', component: DashboardComponent }, + // #enddocregion dashboard-route + // #docregion detail-route { path: 'detail/:id', component: HeroDetailComponent }, - { path: 'heroes', component: HeroesComponent } + // #enddocregion detail-route + // #docregion heroes-route + { path: 'heroes', component: HeroesComponent } ]; +// #enddocregion routes, heroes-route +// #docregion v1 @NgModule({ +// #enddocregion v1 +// #docregion ngmodule-imports imports: [ RouterModule.forRoot(routes) ], +// #enddocregion ngmodule-imports +// #docregion v1 exports: [ RouterModule ] }) export class AppRoutingModule {} +// #enddocregion , v1 diff --git a/aio/content/examples/toh-pt5/src/app/app.component.1.ts b/aio/content/examples/toh-pt5/src/app/app.component.1.ts deleted file mode 100644 index c9f5db9712..0000000000 --- a/aio/content/examples/toh-pt5/src/app/app.component.1.ts +++ /dev/null @@ -1,42 +0,0 @@ -// #docplaster -// #docregion , v2 -import { Component } from '@angular/core'; - -// #enddocregion v2 -@Component({ - selector: 'my-app', - template: ` -

    {{title}}

    - - ` -}) -// #enddocregion -// #docregion v2 -@Component({ - selector: 'my-app', - // #docregion template-v2 - template: ` -

    {{title}}

    - Heroes - - ` - // #enddocregion template-v2 -}) -// #enddocregion -@Component({ - selector: 'my-app', - // #docregion template-v3 - template: ` -

    {{title}}

    - - - ` - // #enddocregion template-v3 -}) -// #docregion , v2 -export class AppComponent { - title = 'Tour of Heroes'; -} diff --git a/aio/content/examples/toh-pt5/src/app/app.component.css b/aio/content/examples/toh-pt5/src/app/app.component.css index 071e665767..bf741e4575 100644 --- a/aio/content/examples/toh-pt5/src/app/app.component.css +++ b/aio/content/examples/toh-pt5/src/app/app.component.css @@ -1,4 +1,4 @@ -/* #docregion */ +/* AppComponent's private CSS styles */ h1 { font-size: 1.2em; color: #999; diff --git a/aio/content/examples/toh-pt5/src/app/app.component.html b/aio/content/examples/toh-pt5/src/app/app.component.html new file mode 100644 index 0000000000..12e347256e --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/app.component.html @@ -0,0 +1,14 @@ + + +

    {{title}}

    + + + + + + diff --git a/aio/content/examples/toh-pt5/src/app/app.component.ts b/aio/content/examples/toh-pt5/src/app/app.component.ts index 96bc3fe694..c41599e92a 100644 --- a/aio/content/examples/toh-pt5/src/app/app.component.ts +++ b/aio/content/examples/toh-pt5/src/app/app.component.ts @@ -1,21 +1,9 @@ -// #docregion import { Component } from '@angular/core'; @Component({ - selector: 'my-app', - // #docregion template - template: ` -

    {{title}}

    - - - `, - // #enddocregion template - // #docregion styleUrls - styleUrls: ['./app.component.css'], - // #enddocregion styleUrls + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'Tour of Heroes'; diff --git a/aio/content/examples/toh-pt5/src/app/app.module.1.ts b/aio/content/examples/toh-pt5/src/app/app.module.1.ts deleted file mode 100644 index e1cda9b620..0000000000 --- a/aio/content/examples/toh-pt5/src/app/app.module.1.ts +++ /dev/null @@ -1,28 +0,0 @@ -// #docregion -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; - -import { AppComponent } from './app.component'; -import { HeroDetailComponent } from './hero-detail.component'; -import { HeroesComponent } from './heroes.component'; -import { HeroService } from './hero.service'; - -@NgModule({ - imports: [ - BrowserModule, - FormsModule - ], - declarations: [ - AppComponent, - HeroDetailComponent, - HeroesComponent - ], - providers: [ - HeroService - ], - bootstrap: [ AppComponent ] -}) -export class AppModule { -} -// #enddocregion diff --git a/aio/content/examples/toh-pt5/src/app/app.module.2.ts b/aio/content/examples/toh-pt5/src/app/app.module.2.ts deleted file mode 100644 index 00876570f3..0000000000 --- a/aio/content/examples/toh-pt5/src/app/app.module.2.ts +++ /dev/null @@ -1,48 +0,0 @@ -// #docplaster -// #docregion -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; -import { RouterModule } from '@angular/router'; - -import { AppComponent } from './app.component'; -import { HeroDetailComponent } from './hero-detail.component'; -import { HeroesComponent } from './heroes.component'; -import { HeroService } from './hero.service'; - -@NgModule({ - imports: [ - BrowserModule, - FormsModule, - RouterModule.forRoot([ - { - path: 'heroes', - component: HeroesComponent - } - ]) - ], - declarations: [ - AppComponent, - HeroDetailComponent, - HeroesComponent - ], - providers: [ - HeroService - ], - bootstrap: [ AppComponent ] -}) -export class AppModule { -} -// #enddocregion -/* -// #docregion heroes, routing -import { RouterModule } from '@angular/router'; - -RouterModule.forRoot([ - { - path: 'heroes', - component: HeroesComponent - } -]) -// #enddocregion heroes, routing -*/ diff --git a/aio/content/examples/toh-pt5/src/app/app.module.3.ts b/aio/content/examples/toh-pt5/src/app/app.module.3.ts deleted file mode 100644 index 306d9958f0..0000000000 --- a/aio/content/examples/toh-pt5/src/app/app.module.3.ts +++ /dev/null @@ -1,58 +0,0 @@ -// #docregion -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; -import { RouterModule } from '@angular/router'; - -import { AppComponent } from './app.component'; -import { HeroDetailComponent } from './hero-detail.component'; -import { DashboardComponent } from './dashboard.component'; -import { HeroesComponent } from './heroes.component'; -import { HeroService } from './hero.service'; - -@NgModule({ - imports: [ - BrowserModule, - FormsModule, - RouterModule.forRoot([ - // #docregion redirect - { - path: '', - redirectTo: '/dashboard', - pathMatch: 'full' - }, - // #enddocregion redirect - // #docregion dashboard - { - path: 'dashboard', - component: DashboardComponent - }, - // #enddocregion dashboard - // #docregion hero-detail - { - path: 'detail/:id', - component: HeroDetailComponent - }, - // #enddocregion hero-detail - // #docregion heroes, routing - { - path: 'heroes', - component: HeroesComponent - } - // #enddocregion heroes, routing - ]) - ], - declarations: [ - AppComponent, - DashboardComponent, - HeroDetailComponent, - HeroesComponent - ], - providers: [ - HeroService - ], - bootstrap: [ AppComponent ] -}) -export class AppModule { -} -// #enddocregion diff --git a/aio/content/examples/toh-pt5/src/app/app.module.ts b/aio/content/examples/toh-pt5/src/app/app.module.ts index b376d69aba..120bf48fcd 100644 --- a/aio/content/examples/toh-pt5/src/app/app.module.ts +++ b/aio/content/examples/toh-pt5/src/app/app.module.ts @@ -4,10 +4,12 @@ import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; -import { DashboardComponent } from './dashboard.component'; -import { HeroDetailComponent } from './hero-detail.component'; -import { HeroesComponent } from './heroes.component'; +import { DashboardComponent } from './dashboard/dashboard.component'; +import { HeroDetailComponent } from './hero-detail/hero-detail.component'; +import { HeroesComponent } from './heroes/heroes.component'; import { HeroService } from './hero.service'; +import { MessageService } from './message.service'; +import { MessagesComponent } from './messages/messages.component'; // #docregion routing-module import { AppRoutingModule } from './app-routing.module'; @@ -23,11 +25,12 @@ import { AppRoutingModule } from './app-routing.module'; declarations: [ AppComponent, DashboardComponent, + HeroesComponent, HeroDetailComponent, - HeroesComponent + MessagesComponent ], // #enddocregion dashboard - providers: [ HeroService ], + providers: [ HeroService, MessageService ], bootstrap: [ AppComponent ] // #docregion routing-module }) diff --git a/aio/content/examples/toh-pt5/src/app/dashboard.component.1.ts b/aio/content/examples/toh-pt5/src/app/dashboard.component.1.ts deleted file mode 100644 index 3c92b205c8..0000000000 --- a/aio/content/examples/toh-pt5/src/app/dashboard.component.1.ts +++ /dev/null @@ -1,8 +0,0 @@ -// #docregion -import { Component } from '@angular/core'; - -@Component({ - selector: 'my-dashboard', - template: '

    My Dashboard

    ' -}) -export class DashboardComponent { } diff --git a/aio/content/examples/toh-pt5/src/app/dashboard.component.ts b/aio/content/examples/toh-pt5/src/app/dashboard.component.ts deleted file mode 100644 index 416cf8868e..0000000000 --- a/aio/content/examples/toh-pt5/src/app/dashboard.component.ts +++ /dev/null @@ -1,33 +0,0 @@ -// #docplaster -// #docregion , imports -import { Component, OnInit } from '@angular/core'; - -import { Hero } from './hero'; -import { HeroService } from './hero.service'; -// #enddocregion imports - -// #docregion metadata -@Component({ - selector: 'my-dashboard', - templateUrl: './dashboard.component.html', - // #enddocregion metadata - // #docregion css - styleUrls: [ './dashboard.component.css' ] - // #enddocregion css - // #docregion metadata -}) -// #enddocregion metadata -// #docregion class -export class DashboardComponent implements OnInit { - - heroes: Hero[] = []; - - // #docregion ctor - constructor(private heroService: HeroService) { } - // #enddocregion ctor - - ngOnInit(): void { - this.heroService.getHeroes() - .then(heroes => this.heroes = heroes.slice(1, 5)); - } -} diff --git a/aio/content/examples/toh-pt5/src/app/dashboard.component.1.html b/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.1.html similarity index 60% rename from aio/content/examples/toh-pt5/src/app/dashboard.component.1.html rename to aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.1.html index 0c556b8de0..ddb4fd29f8 100644 --- a/aio/content/examples/toh-pt5/src/app/dashboard.component.1.html +++ b/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.1.html @@ -1,9 +1,8 @@ -

    Top Heroes

    diff --git a/aio/content/examples/toh-pt6/src/app/dashboard.component.css b/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.css similarity index 95% rename from aio/content/examples/toh-pt6/src/app/dashboard.component.css rename to aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.css index dc7fb7ce06..3822cc56bb 100644 --- a/aio/content/examples/toh-pt6/src/app/dashboard.component.css +++ b/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.css @@ -1,4 +1,4 @@ -/* #docregion */ +/* DashboardComponent's private CSS styles */ [class*='col-'] { float: left; padding-right: 20px; diff --git a/aio/content/examples/toh-pt5/src/app/dashboard.component.html b/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.html similarity index 63% rename from aio/content/examples/toh-pt5/src/app/dashboard.component.html rename to aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.html index 49e77c460c..946a4d5fdb 100644 --- a/aio/content/examples/toh-pt5/src/app/dashboard.component.html +++ b/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.html @@ -1,8 +1,8 @@ -

    Top Heroes

    - +

    {{hero.name}}

    diff --git a/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.spec.ts b/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.spec.ts new file mode 100644 index 0000000000..fea6bfb4db --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DashboardComponent } from './dashboard.component'; + +describe('DashboardComponent', () => { + let component: DashboardComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DashboardComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DashboardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.ts b/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.ts new file mode 100644 index 0000000000..d4db0c406d --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.ts @@ -0,0 +1,26 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Hero } from '../hero'; +import { HeroService } from '../hero.service'; + +@Component({ + selector: 'app-dashboard', + templateUrl: './dashboard.component.html', + styleUrls: [ './dashboard.component.css' ] +}) +export class DashboardComponent implements OnInit { + heroes: Hero[] = []; + + constructor(private heroService: HeroService) { } + + ngOnInit() { + this.getHeroes(); + } + + // #docregion getHeroes + getHeroes(): void { + this.heroService.getHeroes() + .subscribe(heroes => this.heroes = heroes.slice(1, 5)); + } + // #enddocregion getHeroes +} diff --git a/aio/content/examples/toh-pt5/src/app/hero-detail.component.1.ts b/aio/content/examples/toh-pt5/src/app/hero-detail.component.1.ts deleted file mode 100644 index 2895161fee..0000000000 --- a/aio/content/examples/toh-pt5/src/app/hero-detail.component.1.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Imports in comments cause problems when the app is executed -// (some error about 'traceur' missing). Hence this separate file -// is solely for containing the transitory state of the imports. - -// #docregion added-imports -// Keep the Input import for now, you'll remove it later: -import { Component, Input, OnInit } from '@angular/core'; -import { ActivatedRoute, ParamMap } from '@angular/router'; -import { Location } from '@angular/common'; - -import { HeroService } from './hero.service'; -// #enddocregion added-imports - -// Bogus code below this point. It is only here to make lint happy. -import { Hero } from './hero'; - -@Component({}) -export class HeroDetailComponent implements OnInit { - @Input() hero: Hero; - bogus: ParamMap; - - constructor( - private heroService: HeroService, - private route: ActivatedRoute, - private location: Location - ) {} - - ngOnInit() {} -} diff --git a/aio/content/examples/toh-pt5/src/app/hero-detail.component.html b/aio/content/examples/toh-pt5/src/app/hero-detail.component.html deleted file mode 100644 index 8f2ff9d90c..0000000000 --- a/aio/content/examples/toh-pt5/src/app/hero-detail.component.html +++ /dev/null @@ -1,14 +0,0 @@ - - -
    -

    {{hero.name}} details!

    -
    - {{hero.id}}
    -
    - - -
    - - - -
    diff --git a/aio/content/examples/toh-pt5/src/app/hero-detail.component.ts b/aio/content/examples/toh-pt5/src/app/hero-detail.component.ts deleted file mode 100644 index 01f3a4c2db..0000000000 --- a/aio/content/examples/toh-pt5/src/app/hero-detail.component.ts +++ /dev/null @@ -1,46 +0,0 @@ -// #docplaster -// #docregion , v2, rxjs-import -import 'rxjs/add/operator/switchMap'; -// #enddocregion rxjs-import -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute, ParamMap } from '@angular/router'; -import { Location } from '@angular/common'; - -import { Hero } from './hero'; -import { HeroService } from './hero.service'; -// #docregion metadata -@Component({ - selector: 'hero-detail', - templateUrl: './hero-detail.component.html', - // #enddocregion metadata, v2 - styleUrls: [ './hero-detail.component.css' ] - // #docregion metadata, v2 -}) -// #enddocregion metadata -// #docregion implement -export class HeroDetailComponent implements OnInit { -// #enddocregion implement - hero: Hero; - - // #docregion ctor - constructor( - private heroService: HeroService, - private route: ActivatedRoute, - private location: Location - ) {} - // #enddocregion ctor - - // #docregion ngOnInit - ngOnInit(): void { - this.route.paramMap - .switchMap((params: ParamMap) => this.heroService.getHero(+params.get('id'))) - .subscribe(hero => this.hero = hero); - } - // #enddocregion ngOnInit - - // #docregion goBack - goBack(): void { - this.location.back(); - } -// #enddocregion goBack -} diff --git a/aio/content/examples/toh-pt5/src/app/hero-detail.component.css b/aio/content/examples/toh-pt5/src/app/hero-detail/hero-detail.component.css similarity index 87% rename from aio/content/examples/toh-pt5/src/app/hero-detail.component.css rename to aio/content/examples/toh-pt5/src/app/hero-detail/hero-detail.component.css index ab2437efd8..062544af48 100644 --- a/aio/content/examples/toh-pt5/src/app/hero-detail.component.css +++ b/aio/content/examples/toh-pt5/src/app/hero-detail/hero-detail.component.css @@ -1,4 +1,4 @@ -/* #docregion */ +/* HeroDetailComponent's private CSS styles */ label { display: inline-block; width: 3em; @@ -25,6 +25,6 @@ button:hover { } button:disabled { background-color: #eee; - color: #ccc; + color: #ccc; cursor: auto; } diff --git a/aio/content/examples/toh-pt5/src/app/hero-detail/hero-detail.component.html b/aio/content/examples/toh-pt5/src/app/hero-detail/hero-detail.component.html new file mode 100644 index 0000000000..338a747291 --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/hero-detail/hero-detail.component.html @@ -0,0 +1,12 @@ +
    +

    {{ hero.name | uppercase }} Details

    +
    id: {{hero.id}}
    +
    + +
    + + + +
    diff --git a/aio/content/examples/toh-pt5/src/app/hero-detail/hero-detail.component.ts b/aio/content/examples/toh-pt5/src/app/hero-detail/hero-detail.component.ts new file mode 100644 index 0000000000..637ba05f66 --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/hero-detail/hero-detail.component.ts @@ -0,0 +1,49 @@ +// #docplaster +// #docregion +import { Component, OnInit, Input } from '@angular/core'; +// #docregion added-imports +import { ActivatedRoute } from '@angular/router'; +import { Location } from '@angular/common'; + +// #enddocregion added-imports +import { Hero } from '../hero'; +// #docregion added-imports +import { HeroService } from '../hero.service'; +// #enddocregion added-imports + +@Component({ + selector: 'app-hero-detail', + templateUrl: './hero-detail.component.html', + styleUrls: [ './hero-detail.component.css' ] +}) +export class HeroDetailComponent implements OnInit { + @Input() hero: Hero; + + // #docregion ctor + constructor( + private route: ActivatedRoute, + private heroService: HeroService, + private location: Location + ) {} + // #enddocregion ctor + + // #docregion ngOnInit + ngOnInit(): void { + this.getHero(); + } + + // #docregion getHero + getHero(): void { + const id = +this.route.snapshot.paramMap.get('id'); + this.heroService.getHero(id) + .subscribe(hero => this.hero = hero); + } + // #enddocregion getHero + // #enddocregion ngOnInit + + // #docregion goBack + goBack(): void { + this.location.back(); + } +// #enddocregion goBack +} diff --git a/aio/content/examples/toh-pt5/src/app/hero.service.ts b/aio/content/examples/toh-pt5/src/app/hero.service.ts index ee5a684762..2bde8cc06a 100644 --- a/aio/content/examples/toh-pt5/src/app/hero.service.ts +++ b/aio/content/examples/toh-pt5/src/app/hero.service.ts @@ -1,26 +1,28 @@ -// #docplaster -// #docregion +import { Injectable } from '@angular/core'; + +import { Observable } from 'rxjs/Rx'; +import { of } from 'rxjs/observable/of'; + import { Hero } from './hero'; import { HEROES } from './mock-heroes'; -import { Injectable } from '@angular/core'; +import { MessageService } from './message.service'; @Injectable() export class HeroService { - getHeroes(): Promise { - return Promise.resolve(HEROES); - } - getHeroesSlowly(): Promise { - return new Promise(resolve => { - // Simulate server latency with 2 second delay - setTimeout(() => resolve(this.getHeroes()), 2000); - }); + constructor(private messageService: MessageService) { } + + getHeroes(): Observable { + // Todo: send the message _after_ fetching the heroes + this.messageService.add('HeroService: fetched heroes'); + return of(HEROES); } // #docregion getHero - getHero(id: number): Promise { - return this.getHeroes() - .then(heroes => heroes.find(hero => hero.id === id)); + getHero(id: number): Observable { + // Todo: send the message _after_ fetching the hero + this.messageService.add(`HeroService: fetched hero id=${id}`); + return of(HEROES.find(hero => hero.id === id)); } // #enddocregion getHero } diff --git a/aio/content/examples/toh-pt5/src/app/heroes.component.html b/aio/content/examples/toh-pt5/src/app/heroes.component.html deleted file mode 100644 index db41c4692e..0000000000 --- a/aio/content/examples/toh-pt5/src/app/heroes.component.html +++ /dev/null @@ -1,19 +0,0 @@ - - -

    My Heroes

    -
      -
    • - {{hero.id}} {{hero.name}} -
    • -
    - -
    -

    - - {{selectedHero.name | uppercase}} is my hero - -

    - -
    diff --git a/aio/content/examples/toh-pt5/src/app/heroes.component.ts b/aio/content/examples/toh-pt5/src/app/heroes.component.ts deleted file mode 100644 index def615e6b9..0000000000 --- a/aio/content/examples/toh-pt5/src/app/heroes.component.ts +++ /dev/null @@ -1,46 +0,0 @@ -// #docplaster -// #docregion -import { Component, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; - -import { Hero } from './hero'; -import { HeroService } from './hero.service'; - -// #docregion renaming, metadata -@Component({ - selector: 'my-heroes', - // #enddocregion renaming - templateUrl: './heroes.component.html', - styleUrls: [ './heroes.component.css' ] - // #docregion renaming -}) -// #enddocregion metadata -// #docregion class -export class HeroesComponent implements OnInit { - // #enddocregion renaming - heroes: Hero[]; - selectedHero: Hero; - - constructor( - private router: Router, - private heroService: HeroService) { } - - getHeroes(): void { - this.heroService.getHeroes().then(heroes => this.heroes = heroes); - } - - ngOnInit(): void { - this.getHeroes(); - } - - onSelect(hero: Hero): void { - this.selectedHero = hero; - } - - // #docregion gotoDetail - gotoDetail(): void { - this.router.navigate(['/detail', this.selectedHero.id]); - } - // #enddocregion gotoDetail - // #docregion renaming -} diff --git a/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.css b/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.css new file mode 100644 index 0000000000..91e0badceb --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.css @@ -0,0 +1,51 @@ +/* HeroesComponent's private CSS styles */ +.heroes { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 15em; +} +.heroes li { + position: relative; + cursor: pointer; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} + +.heroes li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} + +.heroes a { + color: #888; + text-decoration: none; + position: relative; + display: block; + width: 250px; +} + +.heroes a:hover { + color:#607D8B; +} + +.heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + min-width: 16px; + text-align: right; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} diff --git a/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.html b/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.html new file mode 100644 index 0000000000..bd7e454e45 --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.html @@ -0,0 +1,10 @@ +

    My Heroes

    + +
    + diff --git a/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.spec.ts b/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.spec.ts new file mode 100644 index 0000000000..9c3b1c4d9f --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HeroesComponent } from './heroes.component'; + +describe('HeroesComponent', () => { + let component: HeroesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HeroesComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HeroesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.ts b/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.ts new file mode 100644 index 0000000000..3a893ba554 --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.ts @@ -0,0 +1,26 @@ +import { Component, OnInit } from '@angular/core'; + +import { Hero } from '../hero'; +import { HeroService } from '../hero.service'; + +@Component({ + selector: 'app-heroes', + templateUrl: './heroes.component.html', + styleUrls: ['./heroes.component.css'] +}) +// #docregion class +export class HeroesComponent implements OnInit { + heroes: Hero[]; + + constructor(private heroService: HeroService) { } + + ngOnInit() { + this.getHeroes(); + } + + getHeroes(): void { + this.heroService.getHeroes() + .subscribe(heroes => this.heroes = heroes); + } +} +// #enddocregion class diff --git a/aio/content/examples/toh-pt5/src/app/message.service.spec.ts b/aio/content/examples/toh-pt5/src/app/message.service.spec.ts new file mode 100644 index 0000000000..63ecfd8ff6 --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/message.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { MessageService } from './message.service'; + +describe('MessageService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [MessageService] + }); + }); + + it('should be created', inject([MessageService], (service: MessageService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/aio/content/examples/toh-pt5/src/app/message.service.ts b/aio/content/examples/toh-pt5/src/app/message.service.ts new file mode 100644 index 0000000000..9b3a2cac05 --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/message.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class MessageService { + messages: string[] = []; + + add(message: string) { + this.messages.push(message); + } + + clear() { + this.messages.length = 0; + } +} diff --git a/aio/content/examples/toh-pt5/src/app/messages/messages.component.css b/aio/content/examples/toh-pt5/src/app/messages/messages.component.css new file mode 100644 index 0000000000..d08d9be581 --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/messages/messages.component.css @@ -0,0 +1,35 @@ +/* MessagesComponent's private CSS styles */ +h2 { + color: red; + font-family: Arial, Helvetica, sans-serif; + font-weight: lighter; +} +body { + margin: 2em; +} +body, input[text], button { + color: crimson; + font-family: Cambria, Georgia; +} + +button.clear { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #aaa; + cursor: auto; +} +button.clear { + color: #888; + margin-bottom: 12px; +} diff --git a/aio/content/examples/toh-pt5/src/app/messages/messages.component.html b/aio/content/examples/toh-pt5/src/app/messages/messages.component.html new file mode 100644 index 0000000000..1df7dfd989 --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/messages/messages.component.html @@ -0,0 +1,8 @@ +
    + +

    Messages

    + +
    {{message}}
    + +
    diff --git a/aio/content/examples/toh-pt5/src/app/messages/messages.component.spec.ts b/aio/content/examples/toh-pt5/src/app/messages/messages.component.spec.ts new file mode 100644 index 0000000000..3c2b2b1537 --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/messages/messages.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MessagesComponent } from './messages.component'; + +describe('MessagesComponent', () => { + let component: MessagesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MessagesComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MessagesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/toh-pt5/src/app/messages/messages.component.ts b/aio/content/examples/toh-pt5/src/app/messages/messages.component.ts new file mode 100644 index 0000000000..17c8b2701f --- /dev/null +++ b/aio/content/examples/toh-pt5/src/app/messages/messages.component.ts @@ -0,0 +1,16 @@ +import { Component, OnInit } from '@angular/core'; +import { MessageService } from '../message.service'; + +@Component({ + selector: 'app-messages', + templateUrl: './messages.component.html', + styleUrls: ['./messages.component.css'] +}) +export class MessagesComponent implements OnInit { + + constructor(public messageService: MessageService) {} + + ngOnInit() { + } + +} diff --git a/aio/content/examples/toh-pt5/src/index.html b/aio/content/examples/toh-pt5/src/index.html index ad300fc244..f5fed0967e 100644 --- a/aio/content/examples/toh-pt5/src/index.html +++ b/aio/content/examples/toh-pt5/src/index.html @@ -1,17 +1,16 @@ - + - + + + Tour of Heroes - - - - Angular Tour of Heroes - - - - + + - - Loading... - + + + + + + diff --git a/aio/content/examples/toh-pt5/src/main.ts b/aio/content/examples/toh-pt5/src/main.ts index d89536473a..a9ca1caf8c 100644 --- a/aio/content/examples/toh-pt5/src/main.ts +++ b/aio/content/examples/toh-pt5/src/main.ts @@ -1,5 +1,3 @@ -// #docregion -// main entry point import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; diff --git a/aio/content/examples/toh-pt6/aot/index.html b/aio/content/examples/toh-pt6/aot/index.html deleted file mode 100644 index cb8ecc4461..0000000000 --- a/aio/content/examples/toh-pt6/aot/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - Angular Tour of Heroes - - - - - - - - - - Loading... - - - diff --git a/aio/content/examples/toh-pt6/bs-config.aot.json b/aio/content/examples/toh-pt6/bs-config.aot.json deleted file mode 100644 index e59a7403a0..0000000000 --- a/aio/content/examples/toh-pt6/bs-config.aot.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "open": false, - "logLevel": "silent", - "port": 8080, - "server": { - "baseDir": "aot", - "routes": { - "/node_modules": "node_modules" - }, - "middleware": { - "0": null - } - } -} diff --git a/aio/content/examples/toh-pt6/copy-dist-files.js b/aio/content/examples/toh-pt6/copy-dist-files.js deleted file mode 100644 index 080864e99c..0000000000 --- a/aio/content/examples/toh-pt6/copy-dist-files.js +++ /dev/null @@ -1,12 +0,0 @@ -// #docregion -var fs = require('fs'); -var resources = [ - 'node_modules/core-js/client/shim.min.js', - 'node_modules/zone.js/dist/zone.min.js', - 'src/styles.css' -]; -resources.map(function(f) { - var path = f.split('/'); - var t = 'aot/' + path[path.length-1]; - fs.createReadStream(f).pipe(fs.createWriteStream(t)); -}); diff --git a/aio/content/examples/toh-pt6/e2e-spec.ts b/aio/content/examples/toh-pt6/e2e/app.e2e-spec.ts similarity index 70% rename from aio/content/examples/toh-pt6/e2e-spec.ts rename to aio/content/examples/toh-pt6/e2e/app.e2e-spec.ts index c7208da7f9..b51be25f84 100644 --- a/aio/content/examples/toh-pt6/e2e-spec.ts +++ b/aio/content/examples/toh-pt6/e2e/app.e2e-spec.ts @@ -4,8 +4,8 @@ import { browser, element, by, ElementFinder, ElementArrayFinder } from 'protrac import { promise } from 'selenium-webdriver'; const expectedH1 = 'Tour of Heroes'; -const expectedTitle = `Angular ${expectedH1}`; -const targetHero = { id: 14, name: 'Celeritas' }; +const expectedTitle = `${expectedH1}`; +const targetHero = { id: 15, name: 'Magneta' }; const targetHeroDashboardIndex = 3; const nameSuffix = 'X'; const newHeroName = targetHero.name + nameSuffix; @@ -26,7 +26,8 @@ class Hero { // Hero from hero list
  • element. static async fromLi(li: ElementFinder): Promise { - let strings = await li.all(by.xpath('span')).getText(); + let stringsFromA = await li.all(by.css('a')).getText(); + let strings = stringsFromA[0].split(' '); return { id: +strings[0], name: strings[1] }; } @@ -48,32 +49,31 @@ describe('Tutorial part 6', () => { beforeAll(() => browser.get('')); function getPageElts() { - let navElts = element.all(by.css('my-app nav a')); + let navElts = element.all(by.css('app-root nav a')); return { navElts: navElts, - myDashboardHref: navElts.get(0), - myDashboard: element(by.css('my-app my-dashboard')), - topHeroes: element.all(by.css('my-app my-dashboard > div h4')), + appDashboardHref: navElts.get(0), + appDashboard: element(by.css('app-root app-dashboard')), + topHeroes: element.all(by.css('app-root app-dashboard > div h4')), - myHeroesHref: navElts.get(1), - myHeroes: element(by.css('my-app my-heroes')), - allHeroes: element.all(by.css('my-app my-heroes li')), - selectedHero: element(by.css('my-app li.selected')), - selectedHeroSubview: element(by.css('my-app my-heroes > div:last-child')), + appHeroesHref: navElts.get(1), + appHeroes: element(by.css('app-root app-heroes')), + allHeroes: element.all(by.css('app-root app-heroes li')), + selectedHeroSubview: element(by.css('app-root app-heroes > div:last-child')), - heroDetail: element(by.css('my-app hero-detail > div')), + heroDetail: element(by.css('app-root app-hero-detail > div')), searchBox: element(by.css('#search-box')), - searchResults: element.all(by.css('.search-result')) + searchResults: element.all(by.css('.search-result li')) }; } describe('Initial page', () => { it(`has title '${expectedTitle}'`, () => { - expect(browser.getTitle()).toEqual(expectedTitle); + expect(browser.getTitle()).toEqual(expectedTitle); }); it(`has h1 '${expectedH1}'`, () => { @@ -88,7 +88,7 @@ describe('Tutorial part 6', () => { it('has dashboard as the active view', () => { let page = getPageElts(); - expect(page.myDashboard.isPresent()).toBeTruthy(); + expect(page.appDashboard.isPresent()).toBeTruthy(); }); }); @@ -107,8 +107,8 @@ describe('Tutorial part 6', () => { it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); it(`cancels and shows ${targetHero.name} in Dashboard`, () => { - element(by.buttonText('Back')).click(); - browser.waitForAngular(); // seems necessary to gets tests to past for toh-pt6 + element(by.buttonText('go back')).click(); + browser.waitForAngular(); // seems necessary to gets tests to pass for toh-pt6 let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); expect(targetHeroElt.getText()).toEqual(targetHero.name); @@ -119,8 +119,8 @@ describe('Tutorial part 6', () => { it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); it(`saves and shows ${newHeroName} in Dashboard`, () => { - element(by.buttonText('Save')).click(); - browser.waitForAngular(); // seems necessary to gets tests to past for toh-pt6 + element(by.buttonText('save')).click(); + browser.waitForAngular(); // seems necessary to gets tests to pass for toh-pt6 let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); expect(targetHeroElt.getText()).toEqual(newHeroName); @@ -133,40 +133,29 @@ describe('Tutorial part 6', () => { beforeAll(() => browser.get('')); it('can switch to Heroes view', () => { - getPageElts().myHeroesHref.click(); + getPageElts().appHeroesHref.click(); let page = getPageElts(); - expect(page.myHeroes.isPresent()).toBeTruthy(); - expect(page.allHeroes.count()).toEqual(11, 'number of heroes'); + expect(page.appHeroes.isPresent()).toBeTruthy(); + expect(page.allHeroes.count()).toEqual(10, 'number of heroes'); }); - it(`selects and shows ${targetHero.name} as selected in list`, () => { + it('can route to hero details', async () => { getHeroLiEltById(targetHero.id).click(); - expect(Hero.fromLi(getPageElts().selectedHero)).toEqual(targetHero); - }); - - it('shows selected hero subview', () => { - let page = getPageElts(); - let title = page.selectedHeroSubview.element(by.css('h2')).getText(); - let expectedTitle = `${targetHero.name.toUpperCase()} is my hero`; - expect(title).toEqual(expectedTitle); - }); - - it('can route to hero details', () => { - element(by.buttonText('View Details')).click(); let page = getPageElts(); expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); - let hero = Hero.fromDetail(page.heroDetail); - expect(hero).toEqual(targetHero); + let hero = await Hero.fromDetail(page.heroDetail); + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(targetHero.name.toUpperCase()); }); it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); it(`shows ${newHeroName} in Heroes list`, () => { - element(by.buttonText('Save')).click(); - browser.waitForAngular(); // seems necessary to gets tests to past for toh-pt6 - let expectedHero = {id: targetHero.id, name: newHeroName}; - expect(Hero.fromLi(getHeroLiEltById(targetHero.id))).toEqual(expectedHero); + element(by.buttonText('save')).click(); + browser.waitForAngular(); + let expectedText = `${targetHero.id} ${newHeroName}`; + expect(getHeroAEltById(targetHero.id).getText()).toEqual(expectedText); }); it(`deletes ${newHeroName} from Heroes list`, async () => { @@ -175,12 +164,13 @@ describe('Tutorial part 6', () => { li.element(by.buttonText('x')).click(); const page = getPageElts(); - expect(page.myHeroes.isPresent()).toBeTruthy(); - expect(page.allHeroes.count()).toEqual(10, 'number of heroes'); + expect(page.appHeroes.isPresent()).toBeTruthy(); + expect(page.allHeroes.count()).toEqual(9, 'number of heroes'); const heroesAfter = await toHeroArray(page.allHeroes); + // console.log(await Hero.fromLi(page.allHeroes[0])); const expectedHeroes = heroesBefore.filter(h => h.name !== newHeroName); expect(heroesAfter).toEqual(expectedHeroes); - expect(page.selectedHeroSubview.isPresent()).toBeFalsy(); + // expect(page.selectedHeroSubview.isPresent()).toBeFalsy(); }); it(`adds back ${targetHero.name}`, async () => { @@ -189,7 +179,7 @@ describe('Tutorial part 6', () => { const numHeroes = heroesBefore.length; element(by.css('input')).sendKeys(newHeroName); - element(by.buttonText('Add')).click(); + element(by.buttonText('add')).click(); let page = getPageElts(); let heroesAfter = await toHeroArray(page.allHeroes); @@ -206,20 +196,21 @@ describe('Tutorial part 6', () => { beforeAll(() => browser.get('')); - it(`searches for 'Ce'`, async () => { - getPageElts().searchBox.sendKeys('Ce'); + it(`searches for 'Ma'`, async () => { + getPageElts().searchBox.sendKeys('Ma'); + browser.sleep(1000); + + expect(getPageElts().searchResults.count()).toBe(4); + }); + + it(`continues search with 'g'`, async () => { + getPageElts().searchBox.sendKeys('g'); browser.sleep(1000); expect(getPageElts().searchResults.count()).toBe(2); }); - it(`continues search with 'l'`, async () => { - getPageElts().searchBox.sendKeys('l'); - browser.sleep(1000); - expect(getPageElts().searchResults.count()).toBe(1); - }); - it(`continues search with 'e' and gets ${targetHero.name}`, async () => { - getPageElts().searchBox.sendKeys('e'); + getPageElts().searchBox.sendKeys('n'); browser.sleep(1000); let page = getPageElts(); expect(page.searchResults.count()).toBe(1); @@ -234,28 +225,33 @@ describe('Tutorial part 6', () => { let page = getPageElts(); expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); - expect(Hero.fromDetail(page.heroDetail)).toEqual(targetHero); + let hero2 = await Hero.fromDetail(page.heroDetail); + expect(hero2.id).toEqual(targetHero.id); + expect(hero2.name).toEqual(targetHero.name.toUpperCase()); }); }); - function dashboardSelectTargetHero() { + async function dashboardSelectTargetHero() { let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); expect(targetHeroElt.getText()).toEqual(targetHero.name); targetHeroElt.click(); - browser.waitForAngular(); // seems necessary to gets tests to past for toh-pt6 + browser.waitForAngular(); // seems necessary to gets tests to pass for toh-pt6 let page = getPageElts(); expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); - let hero = Hero.fromDetail(page.heroDetail); - expect(hero).toEqual(targetHero); + let hero = await Hero.fromDetail(page.heroDetail); + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(targetHero.name.toUpperCase()); } async function updateHeroNameInDetailView() { // Assumes that the current view is the hero details view. addToHeroName(nameSuffix); - let hero = await Hero.fromDetail(getPageElts().heroDetail); - expect(hero).toEqual({id: targetHero.id, name: newHeroName}); + let page = getPageElts(); + let hero = await Hero.fromDetail(page.heroDetail); + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(newHeroName.toUpperCase()); } }); @@ -271,11 +267,16 @@ function expectHeading(hLevel: number, expectedText: string): void { expect(hText).toEqual(expectedText, hTag); }; -function getHeroLiEltById(id: number): ElementFinder { +function getHeroAEltById(id: number): ElementFinder { let spanForId = element(by.cssContainingText('li span.badge', id.toString())); return spanForId.element(by.xpath('..')); } +function getHeroLiEltById(id: number): ElementFinder { + let spanForId = element(by.cssContainingText('li span.badge', id.toString())); + return spanForId.element(by.xpath('../..')); +} + async function toHeroArray(allHeroes: ElementArrayFinder): Promise { let promisedHeroes = await allHeroes.map(Hero.fromLi); // The cast is necessary to get around issuing with the signature of Promise.all() diff --git a/aio/content/examples/toh-pt6/rollup-config.js b/aio/content/examples/toh-pt6/rollup-config.js deleted file mode 100644 index 5689edcff4..0000000000 --- a/aio/content/examples/toh-pt6/rollup-config.js +++ /dev/null @@ -1,30 +0,0 @@ -// #docregion -import rollup from 'rollup' -import nodeResolve from 'rollup-plugin-node-resolve' -import commonjs from 'rollup-plugin-commonjs'; -import uglify from 'rollup-plugin-uglify' - -//paths are relative to the execution path -export default { - entry: 'src/main-aot.js', - dest: 'aot/dist/build.js', // output a single application bundle - sourceMap: true, - sourceMapFile: 'aot/dist/build.js.map', - format: 'iife', - onwarn: function(warning) { - // Skip certain warnings - - // should intercept ... but doesn't in some rollup versions - if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; } - - // console.warn everything else - console.warn( warning.message ); - }, - plugins: [ - nodeResolve({jsnext: true, module: true}), - commonjs({ - include: ['node_modules/rxjs/**'] - }), - uglify() - ] -} diff --git a/aio/content/examples/toh-pt6/src/app/app-routing.module.ts b/aio/content/examples/toh-pt6/src/app/app-routing.module.ts index bc070f6c31..969e78b276 100644 --- a/aio/content/examples/toh-pt6/src/app/app-routing.module.ts +++ b/aio/content/examples/toh-pt6/src/app/app-routing.module.ts @@ -1,15 +1,15 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; -import { DashboardComponent } from './dashboard.component'; -import { HeroesComponent } from './heroes.component'; -import { HeroDetailComponent } from './hero-detail.component'; +import { DashboardComponent } from './dashboard/dashboard.component'; +import { HeroesComponent } from './heroes/heroes.component'; +import { HeroDetailComponent } from './hero-detail/hero-detail.component'; const routes: Routes = [ { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, - { path: 'dashboard', component: DashboardComponent }, + { path: 'dashboard', component: DashboardComponent }, { path: 'detail/:id', component: HeroDetailComponent }, - { path: 'heroes', component: HeroesComponent } + { path: 'heroes', component: HeroesComponent } ]; @NgModule({ diff --git a/aio/content/examples/toh-pt6/src/app/app.component.css b/aio/content/examples/toh-pt6/src/app/app.component.css index 071e665767..bf741e4575 100644 --- a/aio/content/examples/toh-pt6/src/app/app.component.css +++ b/aio/content/examples/toh-pt6/src/app/app.component.css @@ -1,4 +1,4 @@ -/* #docregion */ +/* AppComponent's private CSS styles */ h1 { font-size: 1.2em; color: #999; diff --git a/aio/content/examples/toh-pt6/src/app/app.component.html b/aio/content/examples/toh-pt6/src/app/app.component.html new file mode 100644 index 0000000000..49c7d171b6 --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/app.component.html @@ -0,0 +1,7 @@ +

    {{title}}

    + + + diff --git a/aio/content/examples/toh-pt6/src/app/app.component.ts b/aio/content/examples/toh-pt6/src/app/app.component.ts index a9fe05a9a8..c41599e92a 100644 --- a/aio/content/examples/toh-pt6/src/app/app.component.ts +++ b/aio/content/examples/toh-pt6/src/app/app.component.ts @@ -1,17 +1,8 @@ -// #docplaster -// #docregion -import { Component } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ - selector: 'my-app', - template: ` -

    {{title}}

    - - - `, + selector: 'app-root', + templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { diff --git a/aio/content/examples/toh-pt6/src/app/app.module.ts b/aio/content/examples/toh-pt6/src/app/app.module.ts index 58eeb10c54..a5734c5018 100644 --- a/aio/content/examples/toh-pt6/src/app/app.module.ts +++ b/aio/content/examples/toh-pt6/src/app/app.module.ts @@ -1,52 +1,56 @@ // #docplaster -// #docregion -// #docregion v1, v2 -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; -import { HttpModule } from '@angular/http'; +// #docregion, v1 +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpClientModule } from '@angular/common/http'; -import { AppRoutingModule } from './app-routing.module'; - -// #enddocregion v1 -// Imports for loading & configuring the in-memory web api -import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; +// #docregion import-in-mem-stuff +import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api'; import { InMemoryDataService } from './in-memory-data.service'; +// #enddocregion import-in-mem-stuff + +import { AppRoutingModule } from './app-routing.module'; -// #docregion v1 import { AppComponent } from './app.component'; -import { DashboardComponent } from './dashboard.component'; -import { HeroesComponent } from './heroes.component'; -import { HeroDetailComponent } from './hero-detail.component'; +import { DashboardComponent } from './dashboard/dashboard.component'; +import { HeroDetailComponent } from './hero-detail/hero-detail.component'; +import { HeroesComponent } from './heroes/heroes.component'; +// #enddocregion v1 +import { HeroSearchComponent } from './hero-search/hero-search.component'; +// #docregion v1 import { HeroService } from './hero.service'; -// #enddocregion v1, v2 -import { HeroSearchComponent } from './hero-search.component'; -// #docregion v1, v2 +import { MessageService } from './message.service'; +import { MessagesComponent } from './messages/messages.component'; @NgModule({ imports: [ BrowserModule, FormsModule, - HttpModule, - // #enddocregion v1 - // #docregion in-mem-web-api - InMemoryWebApiModule.forRoot(InMemoryDataService), - // #enddocregion in-mem-web-api - // #docregion v1 - AppRoutingModule + AppRoutingModule, + // #docregion in-mem-web-api-imports + HttpClientModule, + + // The HttpClientInMemoryWebApiModule module intercepts HTTP requests + // and returns simulated server responses. + // Remove it when a real server is ready to receive requests. + HttpClientInMemoryWebApiModule.forRoot( + InMemoryDataService, { dataEncapsulation: false } + ) + // #enddocregion in-mem-web-api-imports ], - // #docregion search declarations: [ AppComponent, DashboardComponent, - HeroDetailComponent, HeroesComponent, - // #enddocregion v1, v2 + HeroDetailComponent, + MessagesComponent, + // #enddocregion v1 HeroSearchComponent - // #docregion v1, v2 + // #docregion v1 ], - // #enddocregion search - providers: [ HeroService ], + providers: [ HeroService, MessageService ], bootstrap: [ AppComponent ] }) export class AppModule { } +// #enddocregion , v1 diff --git a/aio/content/examples/toh-pt6/src/app/dashboard.component.html b/aio/content/examples/toh-pt6/src/app/dashboard.component.html deleted file mode 100644 index db8546ccd2..0000000000 --- a/aio/content/examples/toh-pt6/src/app/dashboard.component.html +++ /dev/null @@ -1,10 +0,0 @@ - -

    Top Heroes

    - - diff --git a/aio/content/examples/toh-pt5/src/app/dashboard.component.css b/aio/content/examples/toh-pt6/src/app/dashboard/dashboard.component.css similarity index 95% rename from aio/content/examples/toh-pt5/src/app/dashboard.component.css rename to aio/content/examples/toh-pt6/src/app/dashboard/dashboard.component.css index dc7fb7ce06..3822cc56bb 100644 --- a/aio/content/examples/toh-pt5/src/app/dashboard.component.css +++ b/aio/content/examples/toh-pt6/src/app/dashboard/dashboard.component.css @@ -1,4 +1,4 @@ -/* #docregion */ +/* DashboardComponent's private CSS styles */ [class*='col-'] { float: left; padding-right: 20px; diff --git a/aio/content/examples/toh-pt6/src/app/dashboard/dashboard.component.html b/aio/content/examples/toh-pt6/src/app/dashboard/dashboard.component.html new file mode 100644 index 0000000000..b70c0c7d6e --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/dashboard/dashboard.component.html @@ -0,0 +1,11 @@ +

    Top Heroes

    + + + diff --git a/aio/content/examples/toh-pt6/src/app/dashboard/dashboard.component.spec.ts b/aio/content/examples/toh-pt6/src/app/dashboard/dashboard.component.spec.ts new file mode 100644 index 0000000000..fea6bfb4db --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/dashboard/dashboard.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DashboardComponent } from './dashboard.component'; + +describe('DashboardComponent', () => { + let component: DashboardComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DashboardComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DashboardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/toh-pt6/src/app/dashboard.component.ts b/aio/content/examples/toh-pt6/src/app/dashboard/dashboard.component.ts similarity index 56% rename from aio/content/examples/toh-pt6/src/app/dashboard.component.ts rename to aio/content/examples/toh-pt6/src/app/dashboard/dashboard.component.ts index 9960aa77d4..b2904a2c08 100644 --- a/aio/content/examples/toh-pt6/src/app/dashboard.component.ts +++ b/aio/content/examples/toh-pt6/src/app/dashboard/dashboard.component.ts @@ -1,22 +1,24 @@ -// #docregion , search +// #docregion import { Component, OnInit } from '@angular/core'; - -import { Hero } from './hero'; -import { HeroService } from './hero.service'; +import { Hero } from '../hero'; +import { HeroService } from '../hero.service'; @Component({ - selector: 'my-dashboard', + selector: 'app-dashboard', templateUrl: './dashboard.component.html', styleUrls: [ './dashboard.component.css' ] }) -// #enddocregion search export class DashboardComponent implements OnInit { heroes: Hero[] = []; constructor(private heroService: HeroService) { } - ngOnInit(): void { + ngOnInit() { + this.getHeroes(); + } + + getHeroes(): void { this.heroService.getHeroes() - .then(heroes => this.heroes = heroes.slice(1, 5)); + .subscribe(heroes => this.heroes = heroes.slice(1, 5)); } } diff --git a/aio/content/examples/toh-pt6/src/app/hero-detail.component.html b/aio/content/examples/toh-pt6/src/app/hero-detail.component.html deleted file mode 100644 index 32fe6d4391..0000000000 --- a/aio/content/examples/toh-pt6/src/app/hero-detail.component.html +++ /dev/null @@ -1,14 +0,0 @@ - -
    -

    {{hero.name}} details!

    -
    - {{hero.id}}
    -
    - - -
    - - - - -
    diff --git a/aio/content/examples/toh-pt6/src/app/hero-detail.component.ts b/aio/content/examples/toh-pt6/src/app/hero-detail.component.ts deleted file mode 100644 index e0222aded7..0000000000 --- a/aio/content/examples/toh-pt6/src/app/hero-detail.component.ts +++ /dev/null @@ -1,40 +0,0 @@ -// #docregion -import 'rxjs/add/operator/switchMap'; -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute, ParamMap } from '@angular/router'; -import { Location } from '@angular/common'; - -import { Hero } from './hero'; -import { HeroService } from './hero.service'; - -@Component({ - selector: 'hero-detail', - templateUrl: './hero-detail.component.html', - styleUrls: [ './hero-detail.component.css' ] -}) -export class HeroDetailComponent implements OnInit { - hero: Hero; - - constructor( - private heroService: HeroService, - private route: ActivatedRoute, - private location: Location - ) {} - - ngOnInit(): void { - this.route.paramMap - .switchMap((params: ParamMap) => this.heroService.getHero(+params.get('id'))) - .subscribe(hero => this.hero = hero); - } - - // #docregion save - save(): void { - this.heroService.update(this.hero) - .then(() => this.goBack()); - } - // #enddocregion save - - goBack(): void { - this.location.back(); - } -} diff --git a/aio/content/examples/toh-pt6/src/app/hero-detail.component.css b/aio/content/examples/toh-pt6/src/app/hero-detail/hero-detail.component.css similarity index 87% rename from aio/content/examples/toh-pt6/src/app/hero-detail.component.css rename to aio/content/examples/toh-pt6/src/app/hero-detail/hero-detail.component.css index ab2437efd8..062544af48 100644 --- a/aio/content/examples/toh-pt6/src/app/hero-detail.component.css +++ b/aio/content/examples/toh-pt6/src/app/hero-detail/hero-detail.component.css @@ -1,4 +1,4 @@ -/* #docregion */ +/* HeroDetailComponent's private CSS styles */ label { display: inline-block; width: 3em; @@ -25,6 +25,6 @@ button:hover { } button:disabled { background-color: #eee; - color: #ccc; + color: #ccc; cursor: auto; } diff --git a/aio/content/examples/toh-pt6/src/app/hero-detail/hero-detail.component.html b/aio/content/examples/toh-pt6/src/app/hero-detail/hero-detail.component.html new file mode 100644 index 0000000000..a57d510897 --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/hero-detail/hero-detail.component.html @@ -0,0 +1,13 @@ +
    +

    {{ hero.name | uppercase }} Details

    +
    id: {{hero.id}}
    +
    + +
    + + + + +
    diff --git a/aio/content/examples/toh-pt6/src/app/hero-detail/hero-detail.component.ts b/aio/content/examples/toh-pt6/src/app/hero-detail/hero-detail.component.ts new file mode 100644 index 0000000000..d1259eebf0 --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/hero-detail/hero-detail.component.ts @@ -0,0 +1,42 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Location } from '@angular/common'; + +import { Hero } from '../hero'; +import { HeroService } from '../hero.service'; + +@Component({ + selector: 'app-hero-detail', + templateUrl: './hero-detail.component.html', + styleUrls: [ './hero-detail.component.css' ] +}) +export class HeroDetailComponent implements OnInit { + @Input() hero: Hero; + + constructor( + private route: ActivatedRoute, + private heroService: HeroService, + private location: Location + ) {} + + ngOnInit(): void { + this.getHero(); + } + + getHero(): void { + const id = +this.route.snapshot.paramMap.get('id'); + this.heroService.getHero(id) + .subscribe(hero => this.hero = hero); + } + + goBack(): void { + this.location.back(); + } + + // #docregion save + save(): void { + this.heroService.updateHero(this.hero) + .subscribe(() => this.goBack()); + } +// #enddocregion save +} diff --git a/aio/content/examples/toh-pt6/src/app/hero-search.component.css b/aio/content/examples/toh-pt6/src/app/hero-search.component.css deleted file mode 100644 index 9bf8d13457..0000000000 --- a/aio/content/examples/toh-pt6/src/app/hero-search.component.css +++ /dev/null @@ -1,21 +0,0 @@ -/* #docregion */ -.search-result{ - border-bottom: 1px solid gray; - border-left: 1px solid gray; - border-right: 1px solid gray; - width:195px; - height: 16px; - padding: 5px; - background-color: white; - cursor: pointer; -} - -.search-result:hover { - color: #eee; - background-color: #607D8B; -} - -#search-box{ - width: 200px; - height: 20px; -} diff --git a/aio/content/examples/toh-pt6/src/app/hero-search.component.html b/aio/content/examples/toh-pt6/src/app/hero-search.component.html deleted file mode 100644 index 08c0560c5b..0000000000 --- a/aio/content/examples/toh-pt6/src/app/hero-search.component.html +++ /dev/null @@ -1,11 +0,0 @@ - -
    -

    Hero Search

    - -
    -
    - {{hero.name}} -
    -
    -
    diff --git a/aio/content/examples/toh-pt6/src/app/hero-search.component.ts b/aio/content/examples/toh-pt6/src/app/hero-search.component.ts deleted file mode 100644 index 8b2d32f06b..0000000000 --- a/aio/content/examples/toh-pt6/src/app/hero-search.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -// #docplaster -// #docregion -import { Component, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; - -// #docregion rxjs-imports -import { Observable } from 'rxjs/Observable'; -import { Subject } from 'rxjs/Subject'; - -// Observable class extensions -import 'rxjs/add/observable/of'; - -// Observable operators -import 'rxjs/add/operator/catch'; -import 'rxjs/add/operator/debounceTime'; -import 'rxjs/add/operator/distinctUntilChanged'; -// #enddocregion rxjs-imports - -import { HeroSearchService } from './hero-search.service'; -import { Hero } from './hero'; - -@Component({ - selector: 'hero-search', - templateUrl: './hero-search.component.html', - styleUrls: [ './hero-search.component.css' ], - providers: [HeroSearchService] -}) -export class HeroSearchComponent implements OnInit { - // #docregion search - heroes: Observable; - // #enddocregion search - // #docregion searchTerms - private searchTerms = new Subject(); - // #enddocregion searchTerms - - constructor( - private heroSearchService: HeroSearchService, - private router: Router) {} - // #docregion searchTerms - - // Push a search term into the observable stream. - search(term: string): void { - this.searchTerms.next(term); - } - // #enddocregion searchTerms - // #docregion search - - ngOnInit(): void { - this.heroes = this.searchTerms - .debounceTime(300) // wait 300ms after each keystroke before considering the term - .distinctUntilChanged() // ignore if next search term is same as previous - .switchMap(term => term // switch to new observable each time the term changes - // return the http search observable - ? this.heroSearchService.search(term) - // or the observable of empty heroes if there was no search term - : Observable.of([])) - .catch(error => { - // TODO: add real error handling - console.log(error); - return Observable.of([]); - }); - } - // #enddocregion search - - gotoDetail(hero: Hero): void { - let link = ['/detail', hero.id]; - this.router.navigate(link); - } -} diff --git a/aio/content/examples/toh-pt6/src/app/hero-search.service.ts b/aio/content/examples/toh-pt6/src/app/hero-search.service.ts deleted file mode 100644 index 52bf95a158..0000000000 --- a/aio/content/examples/toh-pt6/src/app/hero-search.service.ts +++ /dev/null @@ -1,20 +0,0 @@ -// #docregion -import { Injectable } from '@angular/core'; -import { Http } from '@angular/http'; - -import { Observable } from 'rxjs/Observable'; -import 'rxjs/add/operator/map'; - -import { Hero } from './hero'; - -@Injectable() -export class HeroSearchService { - - constructor(private http: Http) {} - - search(term: string): Observable { - return this.http - .get(`api/heroes/?name=${term}`) - .map(response => response.json().data as Hero[]); - } -} diff --git a/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.css b/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.css new file mode 100644 index 0000000000..0f2c8cdd10 --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.css @@ -0,0 +1,39 @@ +/* HeroSearch private styles */ +.search-result li { + border-bottom: 1px solid gray; + border-left: 1px solid gray; + border-right: 1px solid gray; + width:195px; + height: 16px; + padding: 5px; + background-color: white; + cursor: pointer; + list-style-type: none; +} + +.search-result li:hover { + background-color: #607D8B; +} + +.search-result li a { + color: #888; + display: block; + text-decoration: none; +} + +.search-result li a:hover { + color: white; +} +.search-result li a:active { + color: white; +} +#search-box { + width: 200px; + height: 20px; +} + + +ul.search-result { + margin-top: 0; + padding-left: 0; +} diff --git a/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.html b/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.html new file mode 100644 index 0000000000..102851a3bc --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.html @@ -0,0 +1,17 @@ +
    +

    Hero Search

    + + + + + + +
    diff --git a/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.spec.ts b/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.spec.ts new file mode 100644 index 0000000000..901bb7f2ab --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HeroSearchComponent } from './hero-search.component'; + +describe('HeroSearchComponent', () => { + let component: HeroSearchComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HeroSearchComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HeroSearchComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.ts b/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.ts new file mode 100644 index 0000000000..b218e9e30c --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.ts @@ -0,0 +1,54 @@ +// #docplaster +// #docregion +import { Component, OnInit } from '@angular/core'; + +// #docregion rxjs-imports +import { Observable } from 'rxjs/Observable'; +import { Subject } from 'rxjs/Subject'; +import { of } from 'rxjs/observable/of'; + +import { + debounceTime, distinctUntilChanged, switchMap + } from 'rxjs/operators'; +// #enddocregion rxjs-imports + +import { Hero } from '../hero'; +import { HeroService } from '../hero.service'; + +@Component({ + selector: 'app-hero-search', + templateUrl: './hero-search.component.html', + styleUrls: [ './hero-search.component.css' ] +}) +export class HeroSearchComponent implements OnInit { + // #docregion heroes-stream + heroes$: Observable; + // #enddocregion heroes-stream + // #docregion searchTerms + private searchTerms = new Subject(); + // #enddocregion searchTerms + + constructor(private heroService: HeroService) {} + // #docregion searchTerms + + // Push a search term into the observable stream. + search(term: string): void { + this.searchTerms.next(term); + } + // #enddocregion searchTerms + + ngOnInit(): void { + // #docregion search + this.heroes$ = this.searchTerms.pipe( + // wait 300ms after each keystroke before considering the term + debounceTime(300), + + // ignore new term if same as previous term + distinctUntilChanged(), + + // switch to new search observable each time the term changes + switchMap((term: string) => this.heroService.searchHeroes(term)), + ); + // #enddocregion search + } +} diff --git a/aio/content/examples/toh-pt6/src/app/hero.service.ts b/aio/content/examples/toh-pt6/src/app/hero.service.ts index 29fe5c2e0e..b1d2c222da 100644 --- a/aio/content/examples/toh-pt6/src/app/hero.service.ts +++ b/aio/content/examples/toh-pt6/src/app/hero.service.ts @@ -1,87 +1,158 @@ // #docplaster -// #docregion , imports -import { Injectable } from '@angular/core'; -import { Headers, Http } from '@angular/http'; +// #docregion +import { Injectable } from '@angular/core'; +// #docregion import-httpclient +import { HttpClient, HttpHeaders } from '@angular/common/http'; +// #enddocregion import-httpclient -// #docregion rxjs -import 'rxjs/add/operator/toPromise'; -// #enddocregion rxjs +import { Observable } from 'rxjs/Observable'; +import { of } from 'rxjs/observable/of'; +// #docregion import-rxjs-operators +import { catchError, map, tap } from 'rxjs/operators'; +// #enddocregion import-rxjs-operators import { Hero } from './hero'; -// #enddocregion imports +import { MessageService } from './message.service'; + +// #docregion http-options +const httpOptions = { + headers: new HttpHeaders({ 'Content-Type': 'application/json' }) +}; +// #enddocregion http-options @Injectable() export class HeroService { - // #docregion update - private headers = new Headers({'Content-Type': 'application/json'}); - // #enddocregion update - // #docregion getHeroes + // #docregion heroesUrl private heroesUrl = 'api/heroes'; // URL to web api + // #enddocregion heroesUrl - constructor(private http: Http) { } + // #docregion ctor + constructor( + private http: HttpClient, + private messageService: MessageService) { } + // #enddocregion ctor - getHeroes(): Promise { - return this.http.get(this.heroesUrl) - // #docregion to-promise - .toPromise() - // #enddocregion to-promise - // #docregion to-data - .then(response => response.json().data as Hero[]) - // #enddocregion to-data - // #docregion catch - .catch(this.handleError); - // #enddocregion catch + // #docregion getHeroes, getHeroes-1 + /** GET heroes from the server */ + // #docregion getHeroes-2 + getHeroes (): Observable { + return this.http.get(this.heroesUrl) + // #enddocregion getHeroes-1 + .pipe( + // #enddocregion getHeroes-2 + tap(heroes => this.log(`fetched heroes`)), + // #docregion getHeroes-2 + catchError(this.handleError('getHeroes', [])) + ); + // #docregion getHeroes-1 } + // #enddocregion getHeroes, getHeroes-1, getHeroes-2 - // #enddocregion getHeroes + // #docregion getHeroNo404 + /** GET hero by id. Return `undefined` when id not found */ + getHeroNo404(id: number): Observable { + const url = `${this.heroesUrl}/?id=${id}`; + return this.http.get(url) + .pipe( + map(heroes => heroes[0]), // returns a {0|1} element array + // #enddocregion getHeroNo404 + tap(h => { + const outcome = h ? `fetched` : `did not find`; + this.log(`${outcome} hero id=${id}`); + }), + catchError(this.handleError(`getHero id=${id}`)) + // #docregion getHeroNo404 + ); + } + // #enddocregion getHeroNo404 // #docregion getHero - getHero(id: number): Promise { + /** GET hero by id. Will 404 if id not found */ + getHero(id: number): Observable { const url = `${this.heroesUrl}/${id}`; - return this.http.get(url) - .toPromise() - .then(response => response.json().data as Hero) - .catch(this.handleError); + return this.http.get(url).pipe( + tap(_ => this.log(`fetched hero id=${id}`)), + catchError(this.handleError(`getHero id=${id}`)) + ); } // #enddocregion getHero - // #docregion delete - delete(id: number): Promise { + // #docregion searchHeroes + /* GET heroes whose name contains search term */ + searchHeroes(term: string): Observable { + if (!term.trim()) { + // if not search term, return empty hero array. + return of([]); + } + return this.http.get(`api/heroes/?name=${term}`).pipe( + tap(_ => this.log(`found heroes matching "${term}"`)), + catchError(this.handleError('searchHeroes', [])) + ); + } + // #enddocregion searchHeroes + + //////// Save methods ////////// + + // #docregion addHero + /** POST: add a new hero to the server */ + addHero (hero: Hero): Observable { + return this.http.post(this.heroesUrl, hero, httpOptions).pipe( + tap((hero: Hero) => this.log(`added hero w/ id=${hero.id}`)), + catchError(this.handleError('addHero')) + ); + } + // #enddocregion addHero + + // #docregion deleteHero + /** DELETE: delete the hero from the server */ + deleteHero (hero: Hero | number): Observable { + const id = typeof hero === 'number' ? hero : hero.id; const url = `${this.heroesUrl}/${id}`; - return this.http.delete(url, {headers: this.headers}) - .toPromise() - .then(() => null) - .catch(this.handleError); - } - // #enddocregion delete - // #docregion create - create(name: string): Promise { - return this.http - .post(this.heroesUrl, JSON.stringify({name: name}), {headers: this.headers}) - .toPromise() - .then(res => res.json().data as Hero) - .catch(this.handleError); + return this.http.delete(url, httpOptions).pipe( + tap(_ => this.log(`deleted hero id=${id}`)), + catchError(this.handleError('deleteHero')) + ); } - // #enddocregion create - // #docregion update + // #enddocregion deleteHero - update(hero: Hero): Promise { - const url = `${this.heroesUrl}/${hero.id}`; - return this.http - .put(url, JSON.stringify(hero), {headers: this.headers}) - .toPromise() - .then(() => hero) - .catch(this.handleError); + // #docregion updateHero + /** PUT: update the hero on the server */ + updateHero (hero: Hero): Observable { + return this.http.put(this.heroesUrl, hero, httpOptions).pipe( + tap(_ => this.log(`updated hero id=${hero.id}`)), + catchError(this.handleError('updateHero')) + ); } - // #enddocregion update + // #enddocregion updateHero - // #docregion getHeroes, handleError - private handleError(error: any): Promise { - console.error('An error occurred', error); // for demo purposes only - return Promise.reject(error.message || error); + // #docregion handleError + /** + * Handle Http operation that failed. + * Let the app continue. + * @param operation - name of the operation that failed + * @param result - optional value to return as the observable result + */ + private handleError (operation = 'operation', result?: T) { + return (error: any): Observable => { + + // TODO: send the error to remote logging infrastructure + console.error(error); // log to console instead + + // TODO: better job of transforming error for user consumption + this.log(`${operation} failed: ${error.message}`); + + // Let the app keep running by returning an empty result. + return of(result as T); + }; } - // #enddocregion getHeroes, handleError + // #enddocregion handleError + + // #docregion log + /** Log a HeroService message with the MessageService */ + private log(message: string) { + this.messageService.add('HeroService: ' + message); + } + // #enddocregion log } - diff --git a/aio/content/examples/toh-pt6/src/app/heroes.component.html b/aio/content/examples/toh-pt6/src/app/heroes.component.html deleted file mode 100644 index 392d241d52..0000000000 --- a/aio/content/examples/toh-pt6/src/app/heroes.component.html +++ /dev/null @@ -1,29 +0,0 @@ - -

    My Heroes

    - -
    - - -
    - -
      - -
    • - {{hero.id}} - {{hero.name}} - - - -
    • - -
    -
    -

    - {{selectedHero.name | uppercase}} is my hero -

    - -
    diff --git a/aio/content/examples/toh-pt6/src/app/heroes.component.ts b/aio/content/examples/toh-pt6/src/app/heroes.component.ts deleted file mode 100644 index 6350b803c4..0000000000 --- a/aio/content/examples/toh-pt6/src/app/heroes.component.ts +++ /dev/null @@ -1,61 +0,0 @@ -// #docregion -import { Component, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; - -import { Hero } from './hero'; -import { HeroService } from './hero.service'; - -@Component({ - selector: 'my-heroes', - templateUrl: './heroes.component.html', - styleUrls: [ './heroes.component.css' ] -}) -export class HeroesComponent implements OnInit { - heroes: Hero[]; - selectedHero: Hero; - - constructor( - private heroService: HeroService, - private router: Router) { } - - getHeroes(): void { - this.heroService - .getHeroes() - .then(heroes => this.heroes = heroes); - } - - // #docregion add - add(name: string): void { - name = name.trim(); - if (!name) { return; } - this.heroService.create(name) - .then(hero => { - this.heroes.push(hero); - this.selectedHero = null; - }); - } - // #enddocregion add - - // #docregion delete - delete(hero: Hero): void { - this.heroService - .delete(hero.id) - .then(() => { - this.heroes = this.heroes.filter(h => h !== hero); - if (this.selectedHero === hero) { this.selectedHero = null; } - }); - } - // #enddocregion delete - - ngOnInit(): void { - this.getHeroes(); - } - - onSelect(hero: Hero): void { - this.selectedHero = hero; - } - - gotoDetail(): void { - this.router.navigate(['/detail', this.selectedHero.id]); - } -} diff --git a/aio/content/examples/toh-pt6/src/app/heroes.component.css b/aio/content/examples/toh-pt6/src/app/heroes/heroes.component.css similarity index 75% rename from aio/content/examples/toh-pt6/src/app/heroes.component.css rename to aio/content/examples/toh-pt6/src/app/heroes/heroes.component.css index d2c958a911..62634648ad 100644 --- a/aio/content/examples/toh-pt6/src/app/heroes.component.css +++ b/aio/content/examples/toh-pt6/src/app/heroes/heroes.component.css @@ -1,8 +1,4 @@ -/* #docregion */ -.selected { - background-color: #CFD8DC !important; - color: white; -} +/* HeroesComponent's private CSS styles */ .heroes { margin: 0 0 2em 0; list-style-type: none; @@ -10,28 +6,33 @@ width: 15em; } .heroes li { - cursor: pointer; position: relative; - left: 0; + cursor: pointer; background-color: #EEE; margin: .5em; padding: .3em 0; height: 1.6em; border-radius: 4px; } + .heroes li:hover { color: #607D8B; background-color: #DDD; left: .1em; } -.heroes li.selected:hover { - background-color: #BBD8DC !important; - color: white; -} -.heroes .text { + +.heroes a { + color: #888; + text-decoration: none; position: relative; - top: -3px; + display: block; + width: 250px; } + +.heroes a:hover { + color:#607D8B; +} + .heroes .badge { display: inline-block; font-size: small; @@ -43,26 +44,33 @@ left: -1px; top: -4px; height: 1.8em; + min-width: 16px; + text-align: right; margin-right: .8em; border-radius: 4px 0 0 4px; } -button { - font-family: Arial; + +/* #docregion additions */ +.button { background-color: #eee; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer; cursor: hand; + font-family: Arial; } + button:hover { background-color: #cfd8dc; } -/* #docregion additions */ + button.delete { - float:right; - margin-top: 2px; - margin-right: .8em; + position: relative; + left: 194px; + top: -32px; background-color: gray !important; - color:white; + color: white; } +/* #enddocregion additions */ + diff --git a/aio/content/examples/toh-pt6/src/app/heroes/heroes.component.html b/aio/content/examples/toh-pt6/src/app/heroes/heroes.component.html new file mode 100644 index 0000000000..e674889f6d --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/heroes/heroes.component.html @@ -0,0 +1,27 @@ +

    My Heroes

    + + +
    + + + +
    + + + + + diff --git a/aio/content/examples/toh-pt6/src/app/heroes/heroes.component.spec.ts b/aio/content/examples/toh-pt6/src/app/heroes/heroes.component.spec.ts new file mode 100644 index 0000000000..9c3b1c4d9f --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/heroes/heroes.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HeroesComponent } from './heroes.component'; + +describe('HeroesComponent', () => { + let component: HeroesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HeroesComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HeroesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/toh-pt6/src/app/heroes/heroes.component.ts b/aio/content/examples/toh-pt6/src/app/heroes/heroes.component.ts new file mode 100644 index 0000000000..7cdeca088a --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/heroes/heroes.component.ts @@ -0,0 +1,43 @@ +import { Component, OnInit } from '@angular/core'; + +import { Hero } from '../hero'; +import { HeroService } from '../hero.service'; + +@Component({ + selector: 'app-heroes', + templateUrl: './heroes.component.html', + styleUrls: ['./heroes.component.css'] +}) +export class HeroesComponent implements OnInit { + heroes: Hero[]; + + constructor(private heroService: HeroService) { } + + ngOnInit() { + this.getHeroes(); + } + + getHeroes(): void { + this.heroService.getHeroes() + .subscribe(heroes => this.heroes = heroes); + } + + // #docregion add + add(name: string): void { + name = name.trim(); + if (!name) { return; } + this.heroService.addHero({ name } as Hero) + .subscribe(hero => { + this.heroes.push(hero); + }); + } + // #enddocregion add + + // #docregion delete + delete(hero: Hero): void { + this.heroes = this.heroes.filter(h => h !== hero); + this.heroService.deleteHero(hero).subscribe(); + } + // #enddocregion delete + +} diff --git a/aio/content/examples/toh-pt6/src/app/in-memory-data.service.ts b/aio/content/examples/toh-pt6/src/app/in-memory-data.service.ts index 88c6d72931..005545c19a 100644 --- a/aio/content/examples/toh-pt6/src/app/in-memory-data.service.ts +++ b/aio/content/examples/toh-pt6/src/app/in-memory-data.service.ts @@ -1,9 +1,9 @@ // #docregion , init import { InMemoryDbService } from 'angular-in-memory-web-api'; + export class InMemoryDataService implements InMemoryDbService { createDb() { const heroes = [ - { id: 0, name: 'Zero' }, { id: 11, name: 'Mr. Nice' }, { id: 12, name: 'Narco' }, { id: 13, name: 'Bombasto' }, diff --git a/aio/content/examples/toh-pt6/src/app/message.service.spec.ts b/aio/content/examples/toh-pt6/src/app/message.service.spec.ts new file mode 100644 index 0000000000..63ecfd8ff6 --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/message.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { MessageService } from './message.service'; + +describe('MessageService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [MessageService] + }); + }); + + it('should be created', inject([MessageService], (service: MessageService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/aio/content/examples/toh-pt6/src/app/message.service.ts b/aio/content/examples/toh-pt6/src/app/message.service.ts new file mode 100644 index 0000000000..9b3a2cac05 --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/message.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class MessageService { + messages: string[] = []; + + add(message: string) { + this.messages.push(message); + } + + clear() { + this.messages.length = 0; + } +} diff --git a/aio/content/examples/toh-pt6/src/app/messages/messages.component.css b/aio/content/examples/toh-pt6/src/app/messages/messages.component.css new file mode 100644 index 0000000000..d08d9be581 --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/messages/messages.component.css @@ -0,0 +1,35 @@ +/* MessagesComponent's private CSS styles */ +h2 { + color: red; + font-family: Arial, Helvetica, sans-serif; + font-weight: lighter; +} +body { + margin: 2em; +} +body, input[text], button { + color: crimson; + font-family: Cambria, Georgia; +} + +button.clear { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #aaa; + cursor: auto; +} +button.clear { + color: #888; + margin-bottom: 12px; +} diff --git a/aio/content/examples/toh-pt6/src/app/messages/messages.component.html b/aio/content/examples/toh-pt6/src/app/messages/messages.component.html new file mode 100644 index 0000000000..1df7dfd989 --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/messages/messages.component.html @@ -0,0 +1,8 @@ +
    + +

    Messages

    + +
    {{message}}
    + +
    diff --git a/aio/content/examples/toh-pt6/src/app/messages/messages.component.spec.ts b/aio/content/examples/toh-pt6/src/app/messages/messages.component.spec.ts new file mode 100644 index 0000000000..3c2b2b1537 --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/messages/messages.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MessagesComponent } from './messages.component'; + +describe('MessagesComponent', () => { + let component: MessagesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MessagesComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MessagesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/toh-pt6/src/app/messages/messages.component.ts b/aio/content/examples/toh-pt6/src/app/messages/messages.component.ts new file mode 100644 index 0000000000..17c8b2701f --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/messages/messages.component.ts @@ -0,0 +1,16 @@ +import { Component, OnInit } from '@angular/core'; +import { MessageService } from '../message.service'; + +@Component({ + selector: 'app-messages', + templateUrl: './messages.component.html', + styleUrls: ['./messages.component.css'] +}) +export class MessagesComponent implements OnInit { + + constructor(public messageService: MessageService) {} + + ngOnInit() { + } + +} diff --git a/aio/content/examples/toh-pt6/src/app/mock-heroes.ts b/aio/content/examples/toh-pt6/src/app/mock-heroes.ts new file mode 100644 index 0000000000..1771a7103b --- /dev/null +++ b/aio/content/examples/toh-pt6/src/app/mock-heroes.ts @@ -0,0 +1,15 @@ +// #docregion +import { Hero } from './hero'; + +export const HEROES: Hero[] = [ + { id: 11, name: 'Mr. Nice' }, + { id: 12, name: 'Narco' }, + { id: 13, name: 'Bombasto' }, + { id: 14, name: 'Celeritas' }, + { id: 15, name: 'Magneta' }, + { id: 16, name: 'RubberMan' }, + { id: 17, name: 'Dynama' }, + { id: 18, name: 'Dr IQ' }, + { id: 19, name: 'Magma' }, + { id: 20, name: 'Tornado' } +]; diff --git a/aio/content/examples/toh-pt6/src/index.html b/aio/content/examples/toh-pt6/src/index.html index 8d270fad4d..1c4106381f 100644 --- a/aio/content/examples/toh-pt6/src/index.html +++ b/aio/content/examples/toh-pt6/src/index.html @@ -1,13 +1,14 @@ - - + - - - Angular Tour of Heroes - - + + + Tour of Heroes + - - Loading... - + + + + + + diff --git a/aio/content/examples/toh-pt6/src/main-aot.ts b/aio/content/examples/toh-pt6/src/main-aot.ts deleted file mode 100644 index bd2ca604a3..0000000000 --- a/aio/content/examples/toh-pt6/src/main-aot.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion -import { platformBrowser } from '@angular/platform-browser'; - -import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory'; - -platformBrowser().bootstrapModuleFactory(AppModuleNgFactory); diff --git a/aio/content/examples/toh-pt6/src/tsconfig.1.json b/aio/content/examples/toh-pt6/src/tsconfig.1.json deleted file mode 100644 index fb3d43db90..0000000000 --- a/aio/content/examples/toh-pt6/src/tsconfig.1.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "target": "es5", - "module": "commonjs", - "moduleResolution": "node", - "sourceMap": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "lib": [ "es2015", "dom" ], - "noImplicitAny": true, - "suppressImplicitAnyIndexErrors": true - } -} \ No newline at end of file diff --git a/aio/content/examples/toh-pt6/tsconfig-aot.json b/aio/content/examples/toh-pt6/tsconfig-aot.json deleted file mode 100644 index 2a88388860..0000000000 --- a/aio/content/examples/toh-pt6/tsconfig-aot.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "target": "es5", - "module": "es2015", - "moduleResolution": "node", - "sourceMap": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "lib": ["es2015", "dom"], - "noImplicitAny": true, - "suppressImplicitAnyIndexErrors": true, - "typeRoots": [ - "./node_modules/@types/" - ] - }, - - "files": [ - "src/app/app.module.ts", - "src/main-aot.ts" - ], - - "angularCompilerOptions": { - "genDir": "aot", - "skipMetadataEmit" : true - } -} diff --git a/aio/content/guide/template-syntax.md b/aio/content/guide/template-syntax.md index 9c5f58c1d1..31741ccb4d 100644 --- a/aio/content/guide/template-syntax.md +++ b/aio/content/guide/template-syntax.md @@ -1188,7 +1188,7 @@ Adding an `ngClass` property binding to `currentClasses` sets the element's clas
    -It's up to you to call `setCurrentClassess()`, both initially and when the dependent properties change. +It's up to you to call `setCurrentClasses()`, both initially and when the dependent properties change.
    @@ -1212,7 +1212,7 @@ Try binding `ngStyle` to a key:value control object. Each key of the object is a style name; its value is whatever is appropriate for that style. Consider a `setCurrentStyles` component method that sets a component property, `currentStyles` -with an object that defines three styles, based on the state of three other component propertes: +with an object that defines three styles, based on the state of three other component properties: @@ -1410,7 +1410,7 @@ The `nullHero` will never be displayed.
    See also the -[_safe navigation operator_](guide/template-syntax#safe-navigation-operator "Safe naviation operator (?.)") +[_safe navigation operator_](guide/template-syntax#safe-navigation-operator "Safe navigation operator (?.)") described below.
    @@ -1472,7 +1472,7 @@ The `NgForOf` directive iterates over the `heroes` array returned by the parent and sets `hero` to the current item from the array during each iteration. You reference the `hero` input variable within the `NgForOf` host element -(and within its descendents) to access the hero's properties. +(and within its descendants) to access the hero's properties. Here it is referenced first in an interpolation and then passed in a binding to the `hero` property of the `` component. @@ -1658,64 +1658,100 @@ This example declares the `fax` variable as `ref-fax` instead of `#fax`. {@a inputs-outputs} -## Input and output properties ( @Input and @Output ) +## Input and Output properties -So far, you've focused mainly on binding to component members within template expressions and statements -that appear on the *right side of the binding declaration*. -A member in that position is a data binding **source**. +An _Input_ property is a _settable_ property annotated with an `@Input` decorator. +Values flow _into_ the property when it is data bound with a [property binding](#property-binding) -This section concentrates on binding to **targets**, which are directive -properties on the *left side of the binding declaration*. -These directive properties must be declared as **inputs** or **outputs**. +An _Output_ property is an _observable_ property annotated with an `@Output` decorator. +The property almost always returns an Angular [`EventEmitter`](api/core/EventEmitter). +Values flow _out_ of the component as events bound with an [event binding](#event-binding). + +You can only bind to _another_ component or directive through its _Input_ and _Output_ properties.
    -Remember: All **components** are **directives**. +Remember that all **components** are **directives**. +The following discussion refers to _components_ for brevity and +because this topic is mostly a concern for component authors.
    -
    +

    Discussion

    -Note the important distinction between a data binding **target** and a data binding **source**. - -The *target* of a binding is to the *left* of the `=`. -The *source* is on the *right* of the `=`. - -The *target* of a binding is the property or event inside the binding punctuation: `[]`, `()` or `[()]`. -The *source* is either inside quotes (`" "`) or within an interpolation (`{{}}`). - -Every member of a **source** directive is automatically available for binding. -You don't have to do anything special to access a directive member in a template expression or statement. - -You have *limited* access to members of a **target** directive. -You can only bind to properties that are explicitly identified as *inputs* and *outputs*. - -
    - -In the following snippet, `iconUrl` and `onSave` are data-bound members of the `AppComponent` -and are referenced within quoted syntax to the _right_ of the equals (`=`). +You are usually binding a template to its _own component class_. +In such binding expressions, the component's property or method is to the _right_ of the (`=`). -They are *neither inputs nor outputs* of the component. They are **sources** for their bindings. -The targets are the native `` and `