Compare commits
146 Commits
Author | SHA1 | Date | |
---|---|---|---|
769c132d22 | |||
ee65d0d4ab | |||
cd48a5383d | |||
0323affe18 | |||
b793aa3f85 | |||
4382ceae02 | |||
9a81e52eac | |||
903aef07f4 | |||
7f15c014d3 | |||
546299b6f2 | |||
a593b3f877 | |||
2bb4263a26 | |||
0c4430b384 | |||
c68826059c | |||
1cdffbdc2e | |||
00f44ee6d4 | |||
dcfde77de5 | |||
4994527e71 | |||
69eb46ad97 | |||
6e190b1a3f | |||
2b1820dfea | |||
9af4dcc442 | |||
16ba4ae2a7 | |||
cd95db482d | |||
e5cbc9b22b | |||
cd2a2f7989 | |||
8031e58410 | |||
508db0f467 | |||
57047acf17 | |||
3e992e18eb | |||
d801941266 | |||
4dc066b979 | |||
71c1446def | |||
ca14509bfe | |||
19fe45dfdc | |||
42b7f8525b | |||
7f1c5f6248 | |||
7089c20ce5 | |||
b9609020f6 | |||
ea0f031995 | |||
2e1fc36c4e | |||
47c486860e | |||
77ee22eb6e | |||
8c0c689338 | |||
f971f83f06 | |||
895b0454f8 | |||
8febb5ac55 | |||
7d6d4c436c | |||
c15b223001 | |||
1423cc0ad2 | |||
e483078d6f | |||
29481a17b1 | |||
09b374c92c | |||
3f6b279033 | |||
b4c77d551b | |||
588a3ed79d | |||
9e33dc3e6a | |||
0930820748 | |||
96ff4971f2 | |||
c9b9be6c2e | |||
736afea5f1 | |||
a14dc2d7a4 | |||
a357daeaf7 | |||
ec4dced523 | |||
69786c2814 | |||
50bcaa6f5b | |||
6bf8e37827 | |||
91f2b1e4d7 | |||
c7075fe710 | |||
e2e0be4ac6 | |||
f6864cce91 | |||
ef038e8060 | |||
3580a6c986 | |||
67e9812c14 | |||
61b08629fd | |||
d727561c5e | |||
39ecc7b5b6 | |||
23f0a04387 | |||
e884c0cd7b | |||
ab72e06cde | |||
5218f5a401 | |||
e8b00ec404 | |||
94b0e8f288 | |||
157b948e6b | |||
7b9d62b2ed | |||
e4eed73591 | |||
a52123f538 | |||
15193fce98 | |||
572a5e4bd3 | |||
601fae944d | |||
d46f1f28e2 | |||
a2df6031ad | |||
542b7cd925 | |||
ce1b741255 | |||
4a1b4f17ae | |||
7ea8985500 | |||
eefae6d96d | |||
9f430f0ad9 | |||
60b5bf7b99 | |||
7671c73655 | |||
6d7a4ff45e | |||
cfa6ab1910 | |||
2f930a5d44 | |||
886df3e604 | |||
72900eccaf | |||
d9b1136ba4 | |||
97fc5f662e | |||
3ad67e5ef6 | |||
baec8abc75 | |||
1e3c015d89 | |||
9419165079 | |||
1f749fead5 | |||
3d60f6de5f | |||
8aefbfe7bc | |||
2d12af3589 | |||
57bef7306c | |||
c09a879b69 | |||
95d7144aba | |||
29d2986454 | |||
4a73dfc500 | |||
ac3e91bc2e | |||
516956905d | |||
81e8eeb0d8 | |||
cfae2c27cb | |||
f4be046d04 | |||
7081e39a78 | |||
5d5bb58e5a | |||
f65fa3aa1c | |||
dbbfab3ee8 | |||
b87ae8e5f9 | |||
8b1d28ff48 | |||
463e967abb | |||
71b8bbef95 | |||
a2cf677714 | |||
9e1ce318a8 | |||
a00c2a9210 | |||
a677d8b330 | |||
7fe89ba4ea | |||
a8af83bf36 | |||
c75e16aae8 | |||
1affcc63c0 | |||
34395aeea1 | |||
f64de2e9f3 | |||
86ad77c1b1 | |||
d5c815f1f2 | |||
32c6d5313a |
9
.bazelrc
9
.bazelrc
@ -33,8 +33,9 @@ test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test
|
||||
# See https://github.com/bazelbuild/bazel/issues/4603
|
||||
build --symlink_prefix=dist/
|
||||
|
||||
# Performance: avoid stat'ing input files
|
||||
build --watchfs
|
||||
# Disable watchfs as it causes tests to be flaky on Windows
|
||||
# https://github.com/angular/angular/issues/29541
|
||||
build --nowatchfs
|
||||
|
||||
# Turn off legacy external runfiles
|
||||
run --nolegacy_external_runfiles
|
||||
@ -57,7 +58,9 @@ test --incompatible_strict_action_env
|
||||
###############################
|
||||
|
||||
# Releases should always be stamped with version control info
|
||||
build:release --workspace_status_command=./tools/bazel_stamp_vars.sh
|
||||
# This command assumes node on the path and is a workaround for
|
||||
# https://github.com/bazelbuild/bazel/issues/4802
|
||||
build:release --workspace_status_command="node ./tools/bazel_stamp_vars.js"
|
||||
|
||||
###############################
|
||||
# Output #
|
||||
|
@ -170,10 +170,7 @@ jobs:
|
||||
|
||||
# Setup remote execution and run RBE-compatible tests.
|
||||
- *setup_bazel_remote_execution
|
||||
- run: yarn bazel test //... --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only,-local
|
||||
# Now run RBE incompatible tests locally.
|
||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||
- run: yarn bazel test //... --build_tag_filters=-ivy-only,local --test_tag_filters=-ivy-only,local
|
||||
- run: yarn bazel test //... --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only
|
||||
|
||||
# Temporary job to test what will happen when we flip the Ivy flag to true
|
||||
test_ivy_aot:
|
||||
@ -269,12 +266,6 @@ jobs:
|
||||
steps:
|
||||
- *attach_workspace
|
||||
- *init_environment
|
||||
# Rename the Ivy packages dist folder to "dist/packages-dist" as the AIO
|
||||
# package installer picks up the locally built packages from that location.
|
||||
# *Note*: We could also adjust the packages installer, but given we won't have
|
||||
# two different folders of Angular distributions in the future, it's likely not
|
||||
# worth the efforts to change the AIO packages installer.
|
||||
- run: mv dist/packages-dist-ivy-aot dist/packages-dist
|
||||
# Build aio with Ivy (using local Angular packages)
|
||||
- run: yarn --cwd aio build-with-ivy --progress=false
|
||||
|
||||
@ -555,7 +546,7 @@ workflows:
|
||||
- build-npm-packages
|
||||
# - test_aio_local_ivy:
|
||||
# requires:
|
||||
# - build-ivy-npm-packages
|
||||
# - build-npm-packages
|
||||
- test_aio_tools:
|
||||
requires:
|
||||
- build-npm-packages
|
||||
|
@ -141,7 +141,7 @@ function getJson(url) {
|
||||
const opts = {headers: {Accept: 'application/json'}};
|
||||
const onResponse = res => {
|
||||
const statusCode = res.statusCode || -1;
|
||||
const isSuccess = (200 <= statusCode) && (statusCode <= 400);
|
||||
const isSuccess = (200 <= statusCode) && (statusCode < 400);
|
||||
let responseText = '';
|
||||
|
||||
res.
|
||||
|
8
.github/CODEOWNERS
vendored
8
.github/CODEOWNERS
vendored
@ -46,6 +46,7 @@
|
||||
# andrewseguin - Andrew Seguin
|
||||
# benlesh - Ben Lesh
|
||||
# brandonroberts - Brandon Roberts
|
||||
# devversion - Paul Gschwendtner
|
||||
# filipesilva - Filipe Silva
|
||||
# gkalpak - George Kalpakas
|
||||
# hansl - Hans Larsen
|
||||
@ -87,6 +88,7 @@
|
||||
# - IgorMinar
|
||||
# - kara
|
||||
# - mhevery
|
||||
# - alexeagle
|
||||
|
||||
|
||||
# ===========================================================
|
||||
@ -325,6 +327,7 @@
|
||||
# ===========================================================
|
||||
#
|
||||
# - alexeagle
|
||||
# - devversion
|
||||
# - filipesilva
|
||||
# - gkalpak
|
||||
# - IgorMinar
|
||||
@ -429,6 +432,7 @@
|
||||
/packages/platform-browser-dynamic/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/platform-webworker/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/platform-webworker-dynamic/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/packages/examples/common/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
|
||||
/aio/content/guide/architecture-components.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/architecture-modules.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
@ -509,6 +513,7 @@
|
||||
/aio/content/guide/module-types.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
|
||||
/aio/content/guide/template-syntax.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/built-in-template-functions/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/event-binding/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/interpolation/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/template-syntax/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
@ -624,6 +629,7 @@
|
||||
/packages/service-worker/** @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/service-worker-getting-started.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/service-worker-getting-started/** @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/app-shell.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/service-worker-communications.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/service-worker-config.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/service-worker-devops.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
@ -776,7 +782,6 @@ testing/** @angular/fw-test
|
||||
/aio/content/guide/npm-packages.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/browser-support.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/typescript-configuration.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/quickstart/** @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/setup.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/examples/setup/** @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/build.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
@ -818,6 +823,7 @@ testing/** @angular/fw-test
|
||||
/* @angular/fw-dev-infra
|
||||
/.buildkite/** @angular/fw-dev-infra
|
||||
/.circleci/** @angular/fw-dev-infra
|
||||
/.codefresh/** @angular/fw-dev-infra
|
||||
/.github/** @angular/fw-dev-infra
|
||||
/.vscode/** @angular/fw-dev-infra
|
||||
/docs/BAZEL.md @angular/fw-dev-infra
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,6 +14,7 @@ pubspec.lock
|
||||
.idea/
|
||||
.settings/
|
||||
.vscode/launch.json
|
||||
.vscode/settings.json
|
||||
*.swo
|
||||
modules/.settings
|
||||
modules/.vscode
|
||||
|
23
.vscode/README.md
vendored
Normal file
23
.vscode/README.md
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
# VSCode Configuration
|
||||
|
||||
This folder contains opt-in [Workspace Settings](https://code.visualstudio.com/docs/getstarted/settings) and [Extension Recommendations](https://code.visualstudio.com/docs/editor/extension-gallery#_workspace-recommended-extensions) that the Angular team recommends using when working on this repository.
|
||||
|
||||
## Usage
|
||||
|
||||
To use the recommended settings follow the steps below:
|
||||
|
||||
- install <https://marketplace.visualstudio.com/items?itemName=xaver.clang-format>
|
||||
- copy `.vscode/recommended-settings.json` to `.vscode/settings.json`
|
||||
- restart the editor
|
||||
|
||||
If you already have your custom workspace settings you should instead manually merge the file content.
|
||||
|
||||
This isn't an automatic process so you will need to repeat it when settings are updated.
|
||||
|
||||
To see the recommended extensions select "Extensions: Show Recommended Extensions" in the [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette).
|
||||
|
||||
## Editing `.vscode/recommended-settings.json`
|
||||
|
||||
If you wish to add extra configuration items please keep in mind any settings you add here will be used by many users.
|
||||
|
||||
Try to keep these settings to things that help facilitate the development process and avoid altering the user workflow whenever possible.
|
@ -1,4 +1,7 @@
|
||||
{
|
||||
// Format js and ts files on save with `clang-format.executable`
|
||||
// If `clang-format.executable` is not being used, these two settings should be removed otherwise it will break existing formatting.
|
||||
// You can instead run `yarn gulp format` to manually format your code.
|
||||
"[javascript]": {
|
||||
"editor.formatOnSave": true,
|
||||
},
|
||||
@ -8,6 +11,7 @@
|
||||
// Please install https://marketplace.visualstudio.com/items?itemName=xaver.clang-format to take advantage of `clang-format` in VSCode.
|
||||
// (See https://clang.llvm.org/docs/ClangFormat.html for more info `clang-format`.)
|
||||
"clang-format.executable": "${workspaceRoot}/node_modules/.bin/clang-format",
|
||||
// Exclude third party modules and build artifacts from the editor watchers/searches.
|
||||
"files.watcherExclude": {
|
||||
"**/.git/objects/**": true,
|
||||
"**/.git/subtree-cache/**": true,
|
||||
@ -16,9 +20,6 @@
|
||||
"**/dist/**": true,
|
||||
"**/aio/src/generated/**": true,
|
||||
},
|
||||
"workbench.colorCustomizations": {
|
||||
"statusBar.background" : "#CB2B38",
|
||||
},
|
||||
"search.exclude": {
|
||||
"**/node_modules": true,
|
||||
"**/bower_components": true,
|
@ -1,11 +1,15 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
exports_files([
|
||||
"tsconfig.json",
|
||||
"LICENSE",
|
||||
"protractor-perf.conf.js",
|
||||
])
|
||||
|
||||
alias(
|
||||
name = "tsconfig.json",
|
||||
actual = "//packages:tsconfig-build.json",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "web_test_bootstrap_scripts",
|
||||
# do not sort
|
||||
|
40
CHANGELOG.md
40
CHANGELOG.md
@ -1,3 +1,43 @@
|
||||
<a name="7.2.14"></a>
|
||||
## [7.2.14](https://github.com/angular/angular/compare/7.2.13...7.2.14) (2019-04-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **common:** prevent repeated application of HttpParams mutations ([#29045](https://github.com/angular/angular/issues/29045)) ([ee65d0d](https://github.com/angular/angular/commit/ee65d0d)), closes [#20430](https://github.com/angular/angular/issues/20430)
|
||||
|
||||
|
||||
|
||||
<a name="7.2.13"></a>
|
||||
## [7.2.13](https://github.com/angular/angular/compare/7.2.12...7.2.13) (2019-04-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bazel:** use //:tsconfig.json as the default for ng_module ([#29670](https://github.com/angular/angular/issues/29670)) ([#29711](https://github.com/angular/angular/issues/29711)) ([9e33dc3](https://github.com/angular/angular/commit/9e33dc3))
|
||||
* **platform-browser:** insert APP_ID in styles, contentAttr and hostAttr ([#17745](https://github.com/angular/angular/issues/17745)) ([ca14509](https://github.com/angular/angular/commit/ca14509))
|
||||
|
||||
|
||||
|
||||
<a name="7.2.12"></a>
|
||||
## [7.2.12](https://github.com/angular/angular/compare/7.2.11...7.2.12) (2019-04-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **common:** escape query selector used when anchor scrolling ([#29577](https://github.com/angular/angular/issues/29577)) ([7671c73](https://github.com/angular/angular/commit/7671c73)), closes [#28193](https://github.com/angular/angular/issues/28193)
|
||||
* **router:** adjust setting navigationTransition when a new navigation cancels an existing one ([#29636](https://github.com/angular/angular/issues/29636)) ([e884c0c](https://github.com/angular/angular/commit/e884c0c)), closes [#29389](https://github.com/angular/angular/issues/29389) [#29590](https://github.com/angular/angular/issues/29590)
|
||||
|
||||
|
||||
|
||||
<a name="7.2.11"></a>
|
||||
## [7.2.11](https://github.com/angular/angular/compare/7.2.10...7.2.11) (2019-03-26)
|
||||
|
||||
This release contains various API docs improvements.
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="7.2.10"></a>
|
||||
## [7.2.10](https://github.com/angular/angular/compare/7.2.9...7.2.10) (2019-03-20)
|
||||
|
||||
|
@ -41,16 +41,6 @@ Here are the most important tasks you might need to use:
|
||||
- `yarn example-e2e --filter=foo` - limit e2e tests to those containing the word "foo"
|
||||
- `yarn example-e2e --setup --local` - run e2e tests with the local version of Angular contained in the "dist" folder
|
||||
|
||||
## Developing on Windows
|
||||
The `packages/` directory may contain Linux-specific symlinks, which are not recognized by Windows.
|
||||
These unresolved links cause the docs generation process to fail because it cannot locate certain files.
|
||||
|
||||
> Hint: The following steps require administration rights or [Windows Developer Mode](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development) enabled!
|
||||
|
||||
To fix this problem, run `scripts/windows/create-symlinks.sh`. This command creates temporary files where the symlinks used to be. Make sure not to commit those files with your documentation changes.
|
||||
When you are done making and testing your documentation changes, you can restore the original symlinks and delete the temporary files by running `scripts/windows/remove-symlinks.sh`.
|
||||
|
||||
It's necessary to remove the temporary files, because otherwise they're displayed as local changes in your git working copy and certain operations are blocked.
|
||||
|
||||
## Using ServiceWorker locally
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Image metadata and config
|
||||
FROM debian:jessie
|
||||
FROM debian:stretch
|
||||
|
||||
LABEL name="angular.io PR preview" \
|
||||
description="This image implements the PR preview functionality for angular.io." \
|
||||
@ -40,7 +40,7 @@ ARG AIO_TRUSTED_PR_LABEL="aio: preview"
|
||||
ARG TEST_AIO_TRUSTED_PR_LABEL="aio: preview"
|
||||
ARG AIO_PREVIEW_SERVER_HOSTNAME=preview.localhost
|
||||
ARG TEST_AIO_PREVIEW_SERVER_HOSTNAME=preview.localhost
|
||||
ARG AIO_ARTIFACT_MAX_SIZE=20971520
|
||||
ARG AIO_ARTIFACT_MAX_SIZE=26214400
|
||||
ARG TEST_AIO_ARTIFACT_MAX_SIZE=200
|
||||
ARG AIO_PREVIEW_SERVER_PORT=3000
|
||||
ARG TEST_AIO_PREVIEW_SERVER_PORT=3001
|
||||
@ -76,21 +76,20 @@ RUN apt-get update -y && apt-get install -y curl
|
||||
RUN curl --silent --show-error --location https://deb.nodesource.com/setup_10.x | bash -
|
||||
RUN curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
|
||||
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
|
||||
RUN echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/backports.list
|
||||
RUN echo "deb http://ftp.debian.org/debian stretch-backports main" | tee /etc/apt/sources.list.d/backports.list
|
||||
|
||||
|
||||
# Install packages
|
||||
RUN apt-get update -y && apt-get install -y \
|
||||
chkconfig \
|
||||
cron \
|
||||
dnsmasq \
|
||||
nano \
|
||||
nodejs \
|
||||
openssl \
|
||||
rsyslog \
|
||||
yarn
|
||||
RUN apt-get install -t jessie-backports -y nginx
|
||||
RUN yarn global add pm2@2
|
||||
cron=3.0pl1-128+deb9u1 \
|
||||
dnsmasq=2.76-5+deb9u2 \
|
||||
nano=2.7.4-1 \
|
||||
nginx=1.10.3-1+deb9u2 \
|
||||
nodejs=10.15.3-1nodesource1 \
|
||||
openssl=1.1.0j-1~deb9u1 \
|
||||
rsyslog=8.24.0-1 \
|
||||
yarn=1.15.2-1
|
||||
RUN yarn global add pm2@3.5.0
|
||||
|
||||
|
||||
# Set up log rotation
|
||||
@ -151,8 +150,7 @@ RUN sed -i "s|{{\$AIO_PREVIEW_SERVER_PORT}}|$TEST_AIO_PREVIEW_SERVER_PORT|g" /et
|
||||
|
||||
|
||||
# Set up pm2
|
||||
RUN pm2 startup systemv -u root > /dev/null
|
||||
RUN chkconfig pm2-root on
|
||||
RUN pm2 startup --user root > /dev/null
|
||||
|
||||
|
||||
# Set up the shell scripts
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Imports
|
||||
import * as cp from 'child_process';
|
||||
import * as fs from 'fs';
|
||||
import * as http from 'http';
|
||||
import * as path from 'path';
|
||||
import * as shell from 'shelljs';
|
||||
import {AIO_DOWNLOADS_DIR, HIDDEN_DIR_PREFIX} from '../common/constants';
|
||||
@ -105,18 +104,7 @@ class Helper {
|
||||
Object.keys(this.portPerScheme).forEach(scheme => suiteFactory(scheme, this.portPerScheme[scheme]));
|
||||
}
|
||||
|
||||
public verifyResponse(status: number | [number, string], regex: string | RegExp = /^/): VerifyCmdResultFn {
|
||||
let statusCode: number;
|
||||
let statusText: string;
|
||||
|
||||
if (Array.isArray(status)) {
|
||||
statusCode = status[0];
|
||||
statusText = status[1];
|
||||
} else {
|
||||
statusCode = status;
|
||||
statusText = http.STATUS_CODES[statusCode] || 'UNKNOWN_STATUS_CODE';
|
||||
}
|
||||
|
||||
public verifyResponse(status: number, regex: string | RegExp = /^/): VerifyCmdResultFn {
|
||||
return (result: CmdResult) => {
|
||||
const [headers, body] = result.stdout.
|
||||
split(/(?:\r?\n){2,}/).
|
||||
@ -131,7 +119,7 @@ class Helper {
|
||||
}
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(headers).toContain(`${statusCode} ${statusText}`);
|
||||
expect(headers).toMatch(new RegExp(`HTTP/(?:1\\.1|2) ${status} `));
|
||||
expect(body).toMatch(regex);
|
||||
};
|
||||
}
|
||||
|
@ -259,10 +259,10 @@ describe(`nginx`, () => {
|
||||
|
||||
it('should disallow non-GET requests', async () => {
|
||||
await Promise.all([
|
||||
h.runCmd(`curl -iLX POST ${baseUrl}/42`).then(h.verifyResponse([405, 'Not Allowed'])),
|
||||
h.runCmd(`curl -iLX PUT ${baseUrl}/42`).then(h.verifyResponse([405, 'Not Allowed'])),
|
||||
h.runCmd(`curl -iLX PATCH ${baseUrl}/42`).then(h.verifyResponse([405, 'Not Allowed'])),
|
||||
h.runCmd(`curl -iLX DELETE ${baseUrl}/42`).then(h.verifyResponse([405, 'Not Allowed'])),
|
||||
h.runCmd(`curl -iLX POST ${baseUrl}/42`).then(h.verifyResponse(405)),
|
||||
h.runCmd(`curl -iLX PUT ${baseUrl}/42`).then(h.verifyResponse(405)),
|
||||
h.runCmd(`curl -iLX PATCH ${baseUrl}/42`).then(h.verifyResponse(405)),
|
||||
h.runCmd(`curl -iLX DELETE ${baseUrl}/42`).then(h.verifyResponse(405)),
|
||||
]);
|
||||
});
|
||||
|
||||
@ -295,10 +295,10 @@ describe(`nginx`, () => {
|
||||
const url = `${scheme}://${host}/circle-build`;
|
||||
|
||||
Promise.all([
|
||||
h.runCmd(`curl -iLX GET ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
|
||||
h.runCmd(`curl -iLX PUT ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
|
||||
h.runCmd(`curl -iLX PATCH ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
|
||||
h.runCmd(`curl -iLX DELETE ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
|
||||
h.runCmd(`curl -iLX GET ${url}`).then(h.verifyResponse(405)),
|
||||
h.runCmd(`curl -iLX PUT ${url}`).then(h.verifyResponse(405)),
|
||||
h.runCmd(`curl -iLX PATCH ${url}`).then(h.verifyResponse(405)),
|
||||
h.runCmd(`curl -iLX DELETE ${url}`).then(h.verifyResponse(405)),
|
||||
]).then(done);
|
||||
});
|
||||
|
||||
@ -334,10 +334,10 @@ describe(`nginx`, () => {
|
||||
|
||||
it('should disallow non-POST requests', done => {
|
||||
Promise.all([
|
||||
h.runCmd(`curl -iLX GET ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
|
||||
h.runCmd(`curl -iLX PUT ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
|
||||
h.runCmd(`curl -iLX PATCH ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
|
||||
h.runCmd(`curl -iLX DELETE ${url}`).then(h.verifyResponse([405, 'Not Allowed'])),
|
||||
h.runCmd(`curl -iLX GET ${url}`).then(h.verifyResponse(405)),
|
||||
h.runCmd(`curl -iLX PUT ${url}`).then(h.verifyResponse(405)),
|
||||
h.runCmd(`curl -iLX PATCH ${url}`).then(h.verifyResponse(405)),
|
||||
h.runCmd(`curl -iLX DELETE ${url}`).then(h.verifyResponse(405)),
|
||||
]).then(done);
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular-devkit/core/src/workspace/workspace-schema.json",
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"cli": {
|
||||
"packageManager": "yarn",
|
||||
@ -21,6 +21,7 @@
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"tsConfig": "src/tsconfig.app.json",
|
||||
"webWorkerTsConfig": "src/tsconfig.worker.json",
|
||||
"aot": true,
|
||||
"optimization": true,
|
||||
"buildOptimizer": true,
|
||||
@ -35,7 +36,6 @@
|
||||
"assets": [
|
||||
"src/assets",
|
||||
"src/generated",
|
||||
"src/app/search/search-worker.js",
|
||||
"src/pwa-manifest.json",
|
||||
"src/google385281288605d160.html",
|
||||
{
|
||||
@ -123,6 +123,7 @@
|
||||
"karmaConfig": "src/karma.conf.js",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "src/tsconfig.spec.json",
|
||||
"webWorkerTsConfig": "src/tsconfig.worker.json",
|
||||
"scripts": [],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
@ -130,7 +131,6 @@
|
||||
"assets": [
|
||||
"src/assets",
|
||||
"src/generated",
|
||||
"src/app/search/search-worker.js",
|
||||
"src/pwa-manifest.json",
|
||||
"src/google385281288605d160.html",
|
||||
{
|
||||
|
3
aio/content/examples/.gitignore
vendored
3
aio/content/examples/.gitignore
vendored
@ -92,3 +92,6 @@ upgrade-phonecat-3-final/tsconfig-aot.json
|
||||
upgrade-phonecat-3-final/rollup-config.js
|
||||
!upgrade-phonecat-*/**/karma.conf.js
|
||||
!upgrade-phonecat-*/**/karma-test-shim.js
|
||||
|
||||
# schematics
|
||||
!schematics-for-libraries/projects/my-lib/package.json
|
@ -1,24 +0,0 @@
|
||||
{
|
||||
"description": "Contact NgModule v.1",
|
||||
"files": [
|
||||
"src/app/app.component.1b.ts",
|
||||
"src/app/app.module.1b.ts",
|
||||
"src/app/highlight.directive.ts",
|
||||
"src/app/title.component.html",
|
||||
"src/app/title.component.ts",
|
||||
"src/app/user.service.ts",
|
||||
|
||||
"src/app/contact/awesome.pipe.ts",
|
||||
"src/app/contact/contact.component.css",
|
||||
"src/app/contact/contact.component.html",
|
||||
"src/app/contact/contact.component.3.ts",
|
||||
"src/app/contact/contact.service.ts",
|
||||
"src/app/contact/contact-highlight.directive.ts",
|
||||
|
||||
"src/main.1b.ts",
|
||||
"src/styles.css",
|
||||
"src/index.1b.html"
|
||||
],
|
||||
"main": "src/index.1b.html",
|
||||
"tags": ["NgModule"]
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
{
|
||||
"description": "Contact NgModule v.2",
|
||||
"files": [
|
||||
"src/app/app.component.2.ts",
|
||||
"src/app/app.module.2.ts",
|
||||
"src/app/highlight.directive.ts",
|
||||
"src/app/title.component.html",
|
||||
"src/app/title.component.ts",
|
||||
"src/app/user.service.ts",
|
||||
|
||||
"src/app/contact/contact.component.css",
|
||||
"src/app/contact/contact.component.html",
|
||||
"src/app/contact/contact.service.ts",
|
||||
|
||||
"src/app/contact/awesome.pipe.ts",
|
||||
"src/app/contact/contact.component.3.ts",
|
||||
"src/app/contact/contact.module.2.ts",
|
||||
"src/app/contact/contact-highlight.directive.ts",
|
||||
|
||||
"src/main.2.ts",
|
||||
"src/styles.css",
|
||||
"src/index.2.html"
|
||||
],
|
||||
"main": "src/index.2.html",
|
||||
"tags": ["NgModule"]
|
||||
}
|
@ -1,223 +0,0 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { browser, element, by } from 'protractor';
|
||||
|
||||
describe('NgModule', function () {
|
||||
|
||||
// helpers
|
||||
const gold = 'rgba(255, 215, 0, 1)';
|
||||
const powderblue = 'rgba(176, 224, 230, 1)';
|
||||
const lightgray = 'rgba(211, 211, 211, 1)';
|
||||
const white = 'rgba(0, 0, 0, 0)';
|
||||
|
||||
function getCommonsSectionStruct() {
|
||||
const buttons = element.all(by.css('nav a'));
|
||||
|
||||
return {
|
||||
title: element.all(by.tagName('h1')).get(0),
|
||||
welcome: element.all(by.css('app-title p i')).get(0),
|
||||
contactButton: buttons.get(0),
|
||||
crisisButton: buttons.get(1),
|
||||
heroesButton: buttons.get(2)
|
||||
};
|
||||
}
|
||||
|
||||
function getContactSectionStruct() {
|
||||
const buttons = element.all(by.css('app-contact form button'));
|
||||
|
||||
return {
|
||||
header: element.all(by.css('app-contact h2')).get(0),
|
||||
popupMessage: element.all(by.css('app-contact div')).get(0),
|
||||
contactNameHeader: element.all(by.css('app-contact form h3')).get(0),
|
||||
input: element.all(by.css('app-contact form input')).get(0),
|
||||
validationError: element.all(by.css('app-contact form .alert')).get(0),
|
||||
saveButton: buttons.get(0), // can't be tested
|
||||
nextContactButton: buttons.get(1),
|
||||
newContactButton: buttons.get(2)
|
||||
};
|
||||
}
|
||||
|
||||
function getCrisisSectionStruct() {
|
||||
return {
|
||||
title: element.all(by.css('ng-component h3')).get(0),
|
||||
items: element.all(by.css('ng-component a')),
|
||||
itemId: element.all(by.css('ng-component div')).get(0),
|
||||
listLink: element.all(by.css('ng-component a')).get(0),
|
||||
};
|
||||
}
|
||||
|
||||
function getHeroesSectionStruct() {
|
||||
return {
|
||||
header: element.all(by.css('ng-component h2')).get(0),
|
||||
title: element.all(by.css('ng-component h3')).get(0),
|
||||
items: element.all(by.css('ng-component a')),
|
||||
itemId: element.all(by.css('ng-component ng-component div div')).get(0),
|
||||
itemInput: element.all(by.css('ng-component ng-component input')).get(0),
|
||||
listLink: element.all(by.css('ng-component ng-component a')).get(0),
|
||||
};
|
||||
}
|
||||
|
||||
// tests
|
||||
function appTitleTests(color: string, name?: string) {
|
||||
return function() {
|
||||
it('should have a gray header', function() {
|
||||
const commons = getCommonsSectionStruct();
|
||||
expect(commons.title.getCssValue('backgroundColor')).toBe(color);
|
||||
});
|
||||
|
||||
it('should welcome us', function () {
|
||||
const commons = getCommonsSectionStruct();
|
||||
expect(commons.welcome.getText()).toBe('Welcome, ' + (name || 'Sherlock Holmes'));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function contactTests(color: string, name?: string) {
|
||||
return function() {
|
||||
it('shows the contact\'s owner', function() {
|
||||
const contacts = getContactSectionStruct();
|
||||
expect(contacts.header.getText()).toBe('Contact of ' + (name || 'Sherlock Holmes'));
|
||||
});
|
||||
|
||||
it('can cycle between contacts', function () {
|
||||
const contacts = getContactSectionStruct();
|
||||
const nextButton = contacts.nextContactButton;
|
||||
expect(contacts.contactNameHeader.getText()).toBe('Awesome Sam Spade');
|
||||
expect(contacts.contactNameHeader.getCssValue('backgroundColor')).toBe(color);
|
||||
nextButton.click().then(function () {
|
||||
expect(contacts.contactNameHeader.getText()).toBe('Awesome Nick Danger');
|
||||
return nextButton.click();
|
||||
}).then(function () {
|
||||
expect(contacts.contactNameHeader.getText()).toBe('Awesome Nancy Drew');
|
||||
});
|
||||
});
|
||||
|
||||
it('can change an existing contact', function () {
|
||||
const contacts = getContactSectionStruct();
|
||||
contacts.input.sendKeys('a');
|
||||
expect(contacts.input.getCssValue('backgroundColor')).toBe(color);
|
||||
expect(contacts.contactNameHeader.getText()).toBe('Awesome Sam Spadea');
|
||||
});
|
||||
|
||||
it('can create a new contact', function () {
|
||||
const contacts = getContactSectionStruct();
|
||||
const newContactButton = contacts.newContactButton;
|
||||
newContactButton.click().then(function () {
|
||||
expect(contacts.validationError.getText()).toBe('Name is required');
|
||||
contacts.input.sendKeys('John Doe');
|
||||
expect(contacts.contactNameHeader.getText()).toBe('Awesome John Doe');
|
||||
expect(contacts.validationError.getText()).toBe('');
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
describe('index.html', function () {
|
||||
beforeEach(function () {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
describe('app-title', appTitleTests(white, 'Miss Marple'));
|
||||
|
||||
describe('contact', contactTests(lightgray, 'Miss Marple'));
|
||||
|
||||
describe('crisis center', function () {
|
||||
beforeEach(function () {
|
||||
getCommonsSectionStruct().crisisButton.click();
|
||||
});
|
||||
|
||||
it('shows a list of crisis', function () {
|
||||
const crisis = getCrisisSectionStruct();
|
||||
expect(crisis.title.getText()).toBe('Crisis List');
|
||||
expect(crisis.items.count()).toBe(4);
|
||||
expect(crisis.items.get(0).getText()).toBe('1 - Dragon Burning Cities');
|
||||
});
|
||||
|
||||
it('can navigate to one crisis details', function () {
|
||||
const crisis = getCrisisSectionStruct();
|
||||
crisis.items.get(0).click().then(function() {
|
||||
expect(crisis.itemId.getText()).toBe('Crisis id: 1');
|
||||
return crisis.listLink.click();
|
||||
}).then(function () {
|
||||
// We are back to the list
|
||||
expect(crisis.items.count()).toBe(4);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('heroes', function () {
|
||||
beforeEach(function () {
|
||||
getCommonsSectionStruct().heroesButton.click();
|
||||
});
|
||||
|
||||
it('shows a list of heroes', function() {
|
||||
const heroes = getHeroesSectionStruct();
|
||||
expect(heroes.header.getText()).toBe('Heroes of Miss Marple');
|
||||
expect(heroes.title.getText()).toBe('Hero List');
|
||||
expect(heroes.items.count()).toBe(6);
|
||||
expect(heroes.items.get(0).getText()).toBe('11 - Mr. Nice');
|
||||
});
|
||||
|
||||
it('can navigate and edit one hero details', function () {
|
||||
const heroes = getHeroesSectionStruct();
|
||||
heroes.items.get(0).click().then(function () {
|
||||
expect(heroes.itemId.getText()).toBe('Id: 11');
|
||||
heroes.itemInput.sendKeys(' try');
|
||||
return heroes.listLink.click();
|
||||
}).then(function () {
|
||||
// We are back to the list
|
||||
expect(heroes.items.count()).toBe(6);
|
||||
expect(heroes.items.get(0).getText()).toBe('11 - Mr. Nice try');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// describe('index.0.html', function() {
|
||||
// beforeEach(function () {
|
||||
// browser.get('index.0.html');
|
||||
// });
|
||||
|
||||
// it('has a title', function () {
|
||||
// const title = element.all(by.tagName('h1')).get(0);
|
||||
// expect(title.getText()).toBe('Minimal NgModule');
|
||||
// });
|
||||
// });
|
||||
|
||||
// describe('index.1.html', function () {
|
||||
// beforeEach(function () {
|
||||
// browser.get('index.1.html');
|
||||
// });
|
||||
|
||||
// describe('app-title', appTitleTests(powderblue));
|
||||
// });
|
||||
|
||||
// describe('index.1b.html', function () {
|
||||
// beforeEach(function () {
|
||||
// browser.get('index.1b.html');
|
||||
// });
|
||||
|
||||
// describe('app-title', appTitleTests(powderblue));
|
||||
|
||||
// describe('contact', contactTests(powderblue));
|
||||
// });
|
||||
|
||||
// describe('index.2.html', function () {
|
||||
// beforeEach(function () {
|
||||
// browser.get('index.2.html');
|
||||
// });
|
||||
|
||||
// describe('app-title', appTitleTests(gold));
|
||||
|
||||
// describe('contact', contactTests(powderblue));
|
||||
// });
|
||||
|
||||
// describe('index.3.html', function () {
|
||||
// beforeEach(function () {
|
||||
// browser.get('index.3.html');
|
||||
// });
|
||||
|
||||
// describe('app-title', appTitleTests(gold));
|
||||
// });
|
||||
|
||||
});
|
@ -1,12 +0,0 @@
|
||||
{
|
||||
"description": "Minimal NgModule",
|
||||
"files": [
|
||||
"src/app/app.component.0.ts",
|
||||
"src/app/app.module.0.ts",
|
||||
"src/main.0.ts",
|
||||
"src/styles.css",
|
||||
"src/index.0.html"
|
||||
],
|
||||
"main": "src/index.0.html",
|
||||
"tags": ["NgModule"]
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
{
|
||||
"description": "NgModule v.3",
|
||||
"files": [
|
||||
"src/app/app.component.3.ts",
|
||||
"src/app/app.module.3.ts",
|
||||
"src/app/app-routing.module.3.ts",
|
||||
|
||||
"src/app/highlight.directive.ts",
|
||||
"src/app/title.component.html",
|
||||
"src/app/title.component.ts",
|
||||
"src/app/user.service.ts",
|
||||
|
||||
"src/app/contact/contact.component.css",
|
||||
"src/app/contact/contact.component.html",
|
||||
"src/app/contact/contact.service.ts",
|
||||
|
||||
"src/app/contact/awesome.pipe.ts",
|
||||
"src/app/contact/contact.component.3.ts",
|
||||
"src/app/contact/contact.module.3.ts",
|
||||
"src/app/contact/contact-routing.module.3.ts",
|
||||
"src/app/contact/contact-highlight.directive.ts",
|
||||
|
||||
"src/app/crisis/*.ts",
|
||||
|
||||
"src/app/hero/hero-detail.component.ts",
|
||||
"src/app/hero/hero-list.component.ts",
|
||||
"src/app/hero/hero.service.ts",
|
||||
|
||||
"src/app/hero/hero.component.3.ts",
|
||||
"src/app/hero/hero.module.3.ts",
|
||||
"src/app/hero/hero-routing.module.3.ts",
|
||||
"src/app/hero/highlight.directive.ts",
|
||||
|
||||
"src/main.3.ts",
|
||||
"src/styles.css",
|
||||
"src/index.3.html"
|
||||
],
|
||||
"main": "src/index.3.html",
|
||||
"tags": ["NgModule"]
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { ContactModule } from './contact/contact.module.3';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: 'contact', pathMatch: 'full'},
|
||||
{ path: 'crisis', loadChildren: './crisis/crisis.module#CrisisModule' },
|
||||
{ path: 'heroes', loadChildren: './hero/hero.module.3#HeroModule' }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
ContactModule,
|
||||
RouterModule.forRoot(routes)
|
||||
],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule {}
|
@ -1,30 +0,0 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { ContactModule } from './contact/contact.module';
|
||||
|
||||
// #docregion routes
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: 'contact', pathMatch: 'full'},
|
||||
// #docregion lazy-routes
|
||||
{ path: 'crisis', loadChildren: './crisis/crisis.module#CrisisModule' },
|
||||
{ path: 'heroes', loadChildren: './hero/hero.module#HeroModule' }
|
||||
// #enddocregion lazy-routes
|
||||
];
|
||||
// #enddocregion routes
|
||||
|
||||
@NgModule({
|
||||
// #docregion imports
|
||||
imports: [
|
||||
ContactModule,
|
||||
// #docregion forRoot
|
||||
RouterModule.forRoot(routes),
|
||||
// #enddocregion forRoot
|
||||
],
|
||||
// #enddocregion imports
|
||||
// #docregion exports
|
||||
exports: [RouterModule]
|
||||
// #enddocregion exports
|
||||
})
|
||||
export class AppRoutingModule {}
|
@ -1,17 +0,0 @@
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
// #enddocregion
|
||||
/*
|
||||
// #docregion template
|
||||
template: '<h1 highlight>{{title}}</h1>'
|
||||
// #enddocregion template
|
||||
*/
|
||||
// #docregion
|
||||
template: '<app-title></app-title>'
|
||||
})
|
||||
export class AppComponent {}
|
||||
// #enddocregion
|
@ -1,13 +0,0 @@
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
// #docregion template
|
||||
template: `
|
||||
<app-title></app-title>
|
||||
<app-contact></app-contact>
|
||||
`
|
||||
// #enddocregion template
|
||||
})
|
||||
export class AppComponent {}
|
@ -1,10 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<app-title></app-title>
|
||||
<app-contact></app-contact>
|
||||
`
|
||||
})
|
||||
export class AppComponent {}
|
@ -1,17 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
// #docregion template
|
||||
template: `
|
||||
<app-title></app-title>
|
||||
<nav>
|
||||
<a routerLink="contact" routerLinkActive="active">Contact</a>
|
||||
<a routerLink="crisis" routerLinkActive="active">Crisis Center</a>
|
||||
<a routerLink="heroes" routerLinkActive="active">Heroes</a>
|
||||
</nav>
|
||||
<router-outlet></router-outlet>
|
||||
`
|
||||
// #enddocregion template
|
||||
})
|
||||
export class AppComponent {}
|
@ -1,17 +0,0 @@
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<app-title></app-title>
|
||||
<nav>
|
||||
<a routerLink="contact" routerLinkActive="active">Contact</a>
|
||||
<a routerLink="crisis" routerLinkActive="active">Crisis Center</a>
|
||||
<a routerLink="heroes" routerLinkActive="active">Heroes</a>
|
||||
</nav>
|
||||
<router-outlet></router-outlet>
|
||||
`
|
||||
})
|
||||
export class AppComponent {}
|
@ -1,13 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { AppComponent } from './app.component.0';
|
||||
|
||||
@NgModule({
|
||||
// #docregion imports
|
||||
imports: [ BrowserModule ],
|
||||
// #enddocregion imports
|
||||
declarations: [ AppComponent ],
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule { }
|
@ -1,52 +0,0 @@
|
||||
// #docplaster
|
||||
// #docregion
|
||||
/* Angular Imports */
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
/* App Imports */
|
||||
// #enddocregion
|
||||
import { AppComponent } from './app.component.1';
|
||||
/*
|
||||
// #docregion
|
||||
import { AppComponent } from './app.component';
|
||||
// #enddocregion
|
||||
*/
|
||||
// #docregion
|
||||
import { HighlightDirective } from './highlight.directive';
|
||||
import { TitleComponent } from './title.component';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
/* Contact Related Imports */
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { AwesomePipe } from './contact/awesome.pipe';
|
||||
import { ContactComponent } from './contact/contact.component.3';
|
||||
import {
|
||||
ContactHighlightDirective as ContactHighlightDirective
|
||||
} from './contact/contact-highlight.directive';
|
||||
|
||||
@NgModule({
|
||||
// #docregion imports
|
||||
imports: [ BrowserModule, FormsModule ],
|
||||
// #enddocregion imports
|
||||
// #docregion declarations, directive, component
|
||||
declarations: [
|
||||
AppComponent,
|
||||
HighlightDirective,
|
||||
// #enddocregion directive
|
||||
TitleComponent,
|
||||
// #enddocregion component
|
||||
|
||||
AwesomePipe,
|
||||
ContactComponent,
|
||||
ContactHighlightDirective
|
||||
// #docregion directive, component
|
||||
],
|
||||
// #enddocregion declarations, directive, component
|
||||
// #docregion providers
|
||||
providers: [ UserService ],
|
||||
// #enddocregion providers
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule { }
|
@ -1,46 +0,0 @@
|
||||
// #docplaster
|
||||
// #docregion
|
||||
/* Angular Imports */
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
/* App Imports */
|
||||
// #enddocregion
|
||||
import { AppComponent } from './app.component.1b';
|
||||
/*
|
||||
// #docregion
|
||||
import { AppComponent } from './app.component';
|
||||
// #enddocregion
|
||||
*/
|
||||
// #docregion
|
||||
import { HighlightDirective } from './highlight.directive';
|
||||
import { TitleComponent } from './title.component';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
/* Contact Imports */
|
||||
// #enddocregion
|
||||
import { ContactComponent } from './contact/contact.component.3';
|
||||
/*
|
||||
// #docregion
|
||||
import { ContactComponent } from './contact/contact.component';
|
||||
// #enddocregion
|
||||
*/
|
||||
// #docregion
|
||||
import { AwesomePipe } from './contact/awesome.pipe';
|
||||
import { ContactService } from './contact/contact.service';
|
||||
import { ContactHighlightDirective } from './contact/contact-highlight.directive';
|
||||
|
||||
@NgModule({
|
||||
imports: [ BrowserModule, FormsModule ],
|
||||
// #docregion declarations
|
||||
declarations: [
|
||||
AppComponent, HighlightDirective, TitleComponent,
|
||||
AwesomePipe, ContactComponent, ContactHighlightDirective
|
||||
],
|
||||
// #docregion providers
|
||||
providers: [ ContactService, UserService ],
|
||||
// #enddocregion providers
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule { }
|
@ -1,36 +0,0 @@
|
||||
// #docplaster
|
||||
// #docregion
|
||||
/* Angular Imports */
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
/* App Imports */
|
||||
// #enddocregion
|
||||
import { AppComponent } from './app.component.2';
|
||||
/*
|
||||
// #docregion
|
||||
import { AppComponent } from './app.component';
|
||||
// #enddocregion
|
||||
*/
|
||||
// #docregion
|
||||
import { HighlightDirective } from './highlight.directive';
|
||||
import { TitleComponent } from './title.component';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
/* Contact Imports */
|
||||
// #enddocregion
|
||||
import { ContactModule } from './contact/contact.module.2';
|
||||
/*
|
||||
// #docregion
|
||||
import { ContactModule } from './contact/contact.module';
|
||||
// #enddocregion
|
||||
*/
|
||||
// #docregion
|
||||
|
||||
@NgModule({
|
||||
imports: [ BrowserModule, ContactModule ],
|
||||
declarations: [ AppComponent, HighlightDirective, TitleComponent ],
|
||||
providers: [ UserService ],
|
||||
bootstrap: [ AppComponent ],
|
||||
})
|
||||
export class AppModule { }
|
@ -1,39 +0,0 @@
|
||||
// #docplaster
|
||||
// #docregion
|
||||
// #docregion v4
|
||||
/* Angular Imports */
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
/* App Imports */
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
/* Core Modules */
|
||||
import { CoreModule } from './core/core.module';
|
||||
|
||||
/* Routing Module */
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
|
||||
@NgModule({
|
||||
// #docregion import-for-root
|
||||
imports: [
|
||||
BrowserModule,
|
||||
// #enddocregion v4
|
||||
// #enddocregion import-for-root
|
||||
/*
|
||||
// #docregion v4
|
||||
CoreModule,
|
||||
// #enddocregion v4
|
||||
*/
|
||||
// #docregion import-for-root
|
||||
CoreModule.forRoot({userName: 'Miss Marple'}),
|
||||
// #docregion v4
|
||||
AppRoutingModule
|
||||
],
|
||||
// #enddocregion import-for-root
|
||||
declarations: [ AppComponent ],
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule { }
|
||||
// #enddocregion v4
|
||||
// #enddocregion
|
@ -1,14 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import { ContactComponent } from './contact.component.3';
|
||||
|
||||
const routes = [
|
||||
{ path: 'contact', component: ContactComponent}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [ RouterModule.forChild(routes) ],
|
||||
exports: [ RouterModule ]
|
||||
})
|
||||
export class ContactRoutingModule {}
|
@ -1,16 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import { ContactComponent } from './contact.component';
|
||||
|
||||
// #docregion routing
|
||||
const routes = [
|
||||
{ path: 'contact', component: ContactComponent}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [ RouterModule.forChild(routes) ],
|
||||
exports: [ RouterModule ]
|
||||
})
|
||||
export class ContactRoutingModule {}
|
||||
// #enddocregion
|
@ -1,53 +0,0 @@
|
||||
// #docregion
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import { Contact, ContactService } from './contact.service';
|
||||
import { UserService } from '../user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-contact',
|
||||
templateUrl: './contact.component.html',
|
||||
styleUrls: [ './contact.component.css' ]
|
||||
})
|
||||
export class ContactComponent implements OnInit {
|
||||
contact: Contact;
|
||||
contacts: Contact[];
|
||||
|
||||
msg = 'Loading contacts ...';
|
||||
userName = '';
|
||||
|
||||
constructor(private contactService: ContactService, userService: UserService) {
|
||||
this.userName = userService.userName;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.contactService.getContacts().subscribe(contacts => {
|
||||
this.msg = '';
|
||||
this.contacts = contacts;
|
||||
this.contact = contacts[0];
|
||||
});
|
||||
}
|
||||
|
||||
next() {
|
||||
let ix = 1 + this.contacts.indexOf(this.contact);
|
||||
if (ix >= this.contacts.length) { ix = 0; }
|
||||
this.contact = this.contacts[ix];
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
// POST-DEMO TODO: do something like save it
|
||||
this.displayMessage('Saved ' + this.contact.name);
|
||||
}
|
||||
|
||||
newContact() {
|
||||
this.displayMessage('New contact');
|
||||
this.contact = {id: 42, name: ''};
|
||||
this.contacts.push(this.contact);
|
||||
}
|
||||
|
||||
/** Display a message briefly, then remove it. */
|
||||
displayMessage(msg: string) {
|
||||
this.msg = msg;
|
||||
setTimeout(() => this.msg = '', 1500);
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/* #docregion */
|
||||
.ng-valid[required] {
|
||||
border-left: 5px solid #42A948; /* green */
|
||||
}
|
||||
|
||||
.ng-invalid {
|
||||
border-left: 5px solid #a94442; /* red */
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 15px;
|
||||
margin: 8px 0;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.alert-danger {
|
||||
color: #a94442;
|
||||
background-color: #f2dede;
|
||||
border-color: #ebccd1;
|
||||
}
|
||||
|
||||
.msg {
|
||||
color: blue;
|
||||
background-color: whitesmoke;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
padding-top: 12px;
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
<!-- #docregion -->
|
||||
<h2>Contact of {{userName}}</h2>
|
||||
<div *ngIf="msg" class="msg">{{msg}}</div>
|
||||
|
||||
<form *ngIf="contacts" (ngSubmit)="onSubmit()" #contactForm="ngForm">
|
||||
<!-- #docregion awesome -->
|
||||
<h3 highlight>{{ contact.name | awesome }}</h3>
|
||||
<!-- #enddocregion awesome -->
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
|
||||
<!-- #docregion ngModel -->
|
||||
<input type="text" class="form-control" required
|
||||
[(ngModel)]="contact.name"
|
||||
name="name" #name="ngModel" >
|
||||
<!-- #enddocregion ngModel -->
|
||||
|
||||
<div [hidden]="name.valid" class="alert alert-danger">
|
||||
Name is required
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button type="submit" class="btn btn-default"
|
||||
[disabled]="!contactForm.form.valid">
|
||||
Save</button>
|
||||
|
||||
<button type="button" class="btn" (click)="next()"
|
||||
[disabled]="!contactForm.form.valid">
|
||||
Next Contact</button>
|
||||
|
||||
<button type="button" class="btn" (click)="newContact()">
|
||||
New Contact</button>
|
||||
</div>
|
||||
</form>
|
||||
<!-- #enddocregion -->
|
@ -1,54 +0,0 @@
|
||||
// Exact copy except import UserService from core
|
||||
// #docregion
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import { Contact, ContactService } from './contact.service';
|
||||
import { UserService } from '../core/user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-contact',
|
||||
templateUrl: './contact.component.html',
|
||||
styleUrls: [ './contact.component.css' ]
|
||||
})
|
||||
export class ContactComponent implements OnInit {
|
||||
contact: Contact;
|
||||
contacts: Contact[];
|
||||
|
||||
msg = 'Loading contacts ...';
|
||||
userName = '';
|
||||
|
||||
constructor(private contactService: ContactService, userService: UserService) {
|
||||
this.userName = userService.userName;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.contactService.getContacts().subscribe(contacts => {
|
||||
this.msg = '';
|
||||
this.contacts = contacts;
|
||||
this.contact = contacts[0];
|
||||
});
|
||||
}
|
||||
|
||||
next() {
|
||||
let ix = 1 + this.contacts.indexOf(this.contact);
|
||||
if (ix >= this.contacts.length) { ix = 0; }
|
||||
this.contact = this.contacts[ix];
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
// POST-DEMO TODO: do something like save it
|
||||
this.displayMessage('Saved ' + this.contact.name);
|
||||
}
|
||||
|
||||
newContact() {
|
||||
this.displayMessage('New contact');
|
||||
this.contact = {id: 42, name: ''};
|
||||
this.contacts.push(this.contact);
|
||||
}
|
||||
|
||||
/** Display a message briefly, then remove it. */
|
||||
displayMessage(msg: string) {
|
||||
this.msg = msg;
|
||||
setTimeout(() => this.msg = '', 1500);
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule
|
||||
],
|
||||
declarations: []
|
||||
})
|
||||
export class ContactModule { }
|
@ -1,37 +0,0 @@
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { AwesomePipe } from './awesome.pipe';
|
||||
// #enddocregion
|
||||
import { ContactComponent } from './contact.component.3';
|
||||
/*
|
||||
// #docregion
|
||||
import { ContactComponent } from './contact.component';
|
||||
// #enddocregion
|
||||
*/
|
||||
// #docregion
|
||||
import { ContactHighlightDirective } from './contact-highlight.directive';
|
||||
import { ContactService } from './contact.service';
|
||||
|
||||
// #docregion class
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule
|
||||
],
|
||||
declarations: [
|
||||
AwesomePipe,
|
||||
ContactComponent,
|
||||
ContactHighlightDirective
|
||||
],
|
||||
// #docregion exports
|
||||
exports: [ ContactComponent ],
|
||||
// #enddocregion exports
|
||||
providers: [ ContactService ]
|
||||
})
|
||||
export class ContactModule { }
|
||||
// #enddocregion class
|
||||
// #enddocregion
|
@ -1,44 +0,0 @@
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { AwesomePipe } from './awesome.pipe';
|
||||
// #enddocregion
|
||||
import { ContactComponent } from './contact.component.3';
|
||||
/*
|
||||
// #docregion
|
||||
import { ContactComponent } from './contact.component';
|
||||
// #enddocregion
|
||||
*/
|
||||
// #docregion
|
||||
import { ContactHighlightDirective } from './contact-highlight.directive';
|
||||
import { ContactService } from './contact.service';
|
||||
|
||||
// #enddocregion
|
||||
import { ContactRoutingModule } from './contact-routing.module.3';
|
||||
/*
|
||||
// #docregion
|
||||
import { ContactRoutingModule } from './contact-routing.module';
|
||||
// #enddocregion
|
||||
*/
|
||||
// #docregion
|
||||
|
||||
// #docregion class
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
ContactRoutingModule
|
||||
],
|
||||
declarations: [
|
||||
AwesomePipe,
|
||||
ContactComponent,
|
||||
ContactHighlightDirective
|
||||
],
|
||||
providers: [ ContactService ]
|
||||
})
|
||||
export class ContactModule { }
|
||||
// #enddocregion class
|
||||
// #enddocregion
|
@ -1,19 +0,0 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
|
||||
import { ContactComponent } from './contact.component';
|
||||
import { ContactService } from './contact.service';
|
||||
import { ContactRoutingModule } from './contact-routing.module';
|
||||
|
||||
// #docregion class
|
||||
@NgModule({
|
||||
imports: [
|
||||
SharedModule,
|
||||
ContactRoutingModule
|
||||
],
|
||||
declarations: [ ContactComponent ],
|
||||
providers: [ ContactService ]
|
||||
})
|
||||
export class ContactModule { }
|
||||
// #enddocregion class
|
@ -1,37 +0,0 @@
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { Injectable, OnDestroy } from '@angular/core';
|
||||
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { delay } from 'rxjs/operators';
|
||||
|
||||
export class Contact {
|
||||
constructor(public id: number, public name: string) { }
|
||||
}
|
||||
|
||||
const CONTACTS: Contact[] = [
|
||||
new Contact(21, 'Sam Spade'),
|
||||
new Contact(22, 'Nick Danger'),
|
||||
new Contact(23, 'Nancy Drew')
|
||||
];
|
||||
|
||||
const FETCH_LATENCY = 500;
|
||||
|
||||
/** Simulate a data service that retrieves contacts from a server */
|
||||
@Injectable()
|
||||
export class ContactService implements OnDestroy {
|
||||
// #enddocregion
|
||||
constructor() { console.log('ContactService instance created.'); }
|
||||
ngOnDestroy() { console.log('ContactService instance destroyed.'); }
|
||||
|
||||
// #docregion
|
||||
getContacts(): Observable<Contact[]> {
|
||||
return of(CONTACTS).pipe(delay(FETCH_LATENCY));
|
||||
}
|
||||
|
||||
getContact(id: number | string): Observable<Contact> {
|
||||
return of(CONTACTS.find(contact => contact.id === +id))
|
||||
.pipe(delay(FETCH_LATENCY));
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
@ -1,48 +0,0 @@
|
||||
/* tslint:disable:member-ordering no-unused-variable */
|
||||
// #docplaster
|
||||
// #docregion
|
||||
// #docregion v4
|
||||
import {
|
||||
ModuleWithProviders, NgModule,
|
||||
Optional, SkipSelf } from '@angular/core';
|
||||
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { TitleComponent } from './title.component';
|
||||
import { UserService } from './user.service';
|
||||
// #enddocregion
|
||||
import { UserServiceConfig } from './user.service';
|
||||
|
||||
// #docregion v4
|
||||
@NgModule({
|
||||
imports: [ CommonModule ],
|
||||
declarations: [ TitleComponent ],
|
||||
exports: [ TitleComponent ],
|
||||
providers: [ UserService ]
|
||||
})
|
||||
export class CoreModule {
|
||||
// #enddocregion v4
|
||||
|
||||
// #docregion ctor
|
||||
constructor (@Optional() @SkipSelf() parentModule: CoreModule) {
|
||||
if (parentModule) {
|
||||
throw new Error(
|
||||
'CoreModule is already loaded. Import it in the AppModule only');
|
||||
}
|
||||
}
|
||||
// #enddocregion ctor
|
||||
|
||||
// #docregion for-root
|
||||
static forRoot(config: UserServiceConfig): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: CoreModule,
|
||||
providers: [
|
||||
{provide: UserServiceConfig, useValue: config }
|
||||
]
|
||||
};
|
||||
}
|
||||
// #enddocregion for-root
|
||||
// #docregion v4
|
||||
}
|
||||
// #enddocregion v4
|
||||
// #enddocregion
|
@ -1,6 +0,0 @@
|
||||
<!-- Exact copy from earlier app.component.html -->
|
||||
<h1 highlight>{{title}}</h1>
|
||||
<p *ngIf="user">
|
||||
<i>Welcome, {{user}}</i>
|
||||
<p>
|
||||
|
@ -1,16 +0,0 @@
|
||||
// Exact copy of app/title.component.ts except import UserService from shared
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { UserService } from '../core/user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-title',
|
||||
templateUrl: './title.component.html',
|
||||
})
|
||||
export class TitleComponent {
|
||||
title = 'Angular Modules';
|
||||
user = '';
|
||||
|
||||
constructor(userService: UserService) {
|
||||
this.user = userService.userName;
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// Crazy copy of the app/user.service
|
||||
// Proves that UserService is an app-wide singleton and only instantiated once
|
||||
// IFF shared.module follows the `forRoot` pattern
|
||||
//
|
||||
// If it didn't, a new instance of UserService would be created
|
||||
// after each lazy load and the userName would double up.
|
||||
|
||||
import { Injectable, Optional } from '@angular/core';
|
||||
|
||||
let nextId = 1;
|
||||
|
||||
export class UserServiceConfig {
|
||||
userName = 'Philip Marlowe';
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
id = nextId++;
|
||||
private _userName = 'Sherlock Holmes';
|
||||
|
||||
// #docregion ctor
|
||||
constructor(@Optional() config: UserServiceConfig) {
|
||||
if (config) { this._userName = config.userName; }
|
||||
}
|
||||
// #enddocregion ctor
|
||||
|
||||
get userName() {
|
||||
// Demo: add a suffix if this service has been created more than once
|
||||
const suffix = this.id > 1 ? ` times ${this.id}` : '';
|
||||
return this._userName + suffix;
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<h3 highlight>Crisis Detail</h3>
|
||||
<div>Crisis id: {{id}}</div>
|
||||
<br>
|
||||
<a routerLink="../list">Crisis List</a>
|
||||
`
|
||||
})
|
||||
export class CrisisDetailComponent implements OnInit {
|
||||
id: number;
|
||||
constructor(private route: ActivatedRoute) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.id = parseInt(this.route.snapshot.paramMap.get('id'), 10);
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { Crisis,
|
||||
CrisisService } from './crisis.service';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<h3 highlight>Crisis List</h3>
|
||||
<div *ngFor='let crisis of crises | async'>
|
||||
<a routerLink="{{'../' + crisis.id}}">{{crisis.id}} - {{crisis.name}}</a>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class CrisisListComponent {
|
||||
crises: Observable<Crisis[]>;
|
||||
|
||||
constructor(private crisisService: CrisisService) {
|
||||
this.crises = this.crisisService.getCrises();
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes,
|
||||
RouterModule } from '@angular/router';
|
||||
|
||||
import { CrisisListComponent } from './crisis-list.component';
|
||||
import { CrisisDetailComponent } from './crisis-detail.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: 'list', pathMatch: 'full'},
|
||||
{ path: 'list', component: CrisisListComponent },
|
||||
{ path: ':id', component: CrisisDetailComponent }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class CrisisRoutingModule {}
|
@ -1,14 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { CrisisListComponent } from './crisis-list.component';
|
||||
import { CrisisDetailComponent } from './crisis-detail.component';
|
||||
import { CrisisService } from './crisis.service';
|
||||
import { CrisisRoutingModule } from './crisis-routing.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [ CommonModule, CrisisRoutingModule ],
|
||||
declarations: [ CrisisDetailComponent, CrisisListComponent ],
|
||||
providers: [ CrisisService ]
|
||||
})
|
||||
export class CrisisModule {}
|
@ -1,33 +0,0 @@
|
||||
import { Injectable, OnDestroy } from '@angular/core';
|
||||
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { delay } from 'rxjs/operators';
|
||||
|
||||
export class Crisis {
|
||||
constructor(public id: number, public name: string) { }
|
||||
}
|
||||
|
||||
const CRISES: Crisis[] = [
|
||||
new Crisis(1, 'Dragon Burning Cities'),
|
||||
new Crisis(2, 'Sky Rains Great White Sharks'),
|
||||
new Crisis(3, 'Giant Asteroid Heading For Earth'),
|
||||
new Crisis(4, 'Procrastinators Meeting Delayed Again'),
|
||||
];
|
||||
|
||||
const FETCH_LATENCY = 500;
|
||||
|
||||
/** Simulate a data service that retrieves crises from a server */
|
||||
@Injectable()
|
||||
export class CrisisService implements OnDestroy {
|
||||
constructor() { console.log('CrisisService instance created.'); }
|
||||
ngOnDestroy() { console.log('CrisisService instance destroyed.'); }
|
||||
|
||||
getCrises(): Observable<Crisis[]> {
|
||||
return of(CRISES).pipe(delay(FETCH_LATENCY));
|
||||
}
|
||||
|
||||
getCrisis(id: number | string): Observable<Crisis> {
|
||||
return of(CRISES.find(crisis => crisis.id === +id))
|
||||
.pipe(delay(FETCH_LATENCY));
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { Hero,
|
||||
HeroService } from './hero.service';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<h3 highlight>Hero Detail</h3>
|
||||
<div *ngIf="hero">
|
||||
<div>Id: {{hero.id}}</div><br>
|
||||
<label>Name:
|
||||
<input [(ngModel)]="hero.name">
|
||||
</label>
|
||||
</div>
|
||||
<br>
|
||||
<a routerLink="../">Hero List</a>
|
||||
`
|
||||
})
|
||||
export class HeroDetailComponent implements OnInit {
|
||||
hero: Hero;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private heroService: HeroService) { }
|
||||
|
||||
ngOnInit() {
|
||||
let id = parseInt(this.route.snapshot.paramMap.get('id'), 10);
|
||||
this.heroService.getHero(id).subscribe(hero => this.hero = hero);
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { Hero,
|
||||
HeroService } from './hero.service';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<h3 highlight>Hero List</h3>
|
||||
<div *ngFor='let hero of heroes | async'>
|
||||
<a routerLink="{{hero.id}}">{{hero.id}} - {{hero.name}}</a>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class HeroListComponent {
|
||||
heroes: Observable<Hero[]>;
|
||||
constructor(private heroService: HeroService) {
|
||||
this.heroes = this.heroService.getHeroes();
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes,
|
||||
RouterModule } from '@angular/router';
|
||||
|
||||
import { HeroComponent } from './hero.component.3';
|
||||
import { HeroListComponent } from './hero-list.component';
|
||||
import { HeroDetailComponent } from './hero-detail.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '',
|
||||
component: HeroComponent,
|
||||
children: [
|
||||
{ path: '', component: HeroListComponent },
|
||||
{ path: ':id', component: HeroDetailComponent }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class HeroRoutingModule {}
|
@ -1,23 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes,
|
||||
RouterModule } from '@angular/router';
|
||||
|
||||
import { HeroComponent } from './hero.component';
|
||||
import { HeroListComponent } from './hero-list.component';
|
||||
import { HeroDetailComponent } from './hero-detail.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '',
|
||||
component: HeroComponent,
|
||||
children: [
|
||||
{ path: '', component: HeroListComponent },
|
||||
{ path: ':id', component: HeroDetailComponent }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class HeroRoutingModule {}
|
@ -1,18 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { HeroService } from './hero.service';
|
||||
import { UserService } from '../user.service';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<h2>Heroes of {{userName}}</h2>
|
||||
<router-outlet></router-outlet>
|
||||
`,
|
||||
providers: [ HeroService ]
|
||||
})
|
||||
export class HeroComponent {
|
||||
userName = '';
|
||||
constructor(userService: UserService) {
|
||||
this.userName = userService.userName;
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
// Exact copy except import UserService from core
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { HeroService } from './hero.service';
|
||||
import { UserService } from '../core/user.service';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<h2>Heroes of {{userName}}</h2>
|
||||
<router-outlet></router-outlet>
|
||||
`,
|
||||
providers: [ HeroService ]
|
||||
})
|
||||
export class HeroComponent {
|
||||
userName = '';
|
||||
constructor(userService: UserService) {
|
||||
this.userName = userService.userName;
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { HeroComponent } from './hero.component.3';
|
||||
import { HeroDetailComponent } from './hero-detail.component';
|
||||
import { HeroListComponent } from './hero-list.component';
|
||||
import { HeroRoutingModule } from './hero-routing.module.3';
|
||||
|
||||
import { HighlightDirective } from './highlight.directive';
|
||||
|
||||
// #docregion class
|
||||
@NgModule({
|
||||
imports: [ CommonModule, FormsModule, HeroRoutingModule ],
|
||||
declarations: [
|
||||
HeroComponent, HeroDetailComponent, HeroListComponent,
|
||||
HighlightDirective
|
||||
]
|
||||
})
|
||||
export class HeroModule { }
|
||||
// #enddocregion class
|
@ -1,16 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
|
||||
import { HeroComponent } from './hero.component';
|
||||
import { HeroDetailComponent } from './hero-detail.component';
|
||||
import { HeroListComponent } from './hero-list.component';
|
||||
import { HeroRoutingModule } from './hero-routing.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [ SharedModule, HeroRoutingModule ],
|
||||
declarations: [
|
||||
HeroComponent, HeroDetailComponent, HeroListComponent,
|
||||
]
|
||||
})
|
||||
export class HeroModule { }
|
@ -1,36 +0,0 @@
|
||||
import { Injectable, OnDestroy } from '@angular/core';
|
||||
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { delay } from 'rxjs/operators';
|
||||
|
||||
export class Hero {
|
||||
constructor(public id: number, public name: string) { }
|
||||
}
|
||||
|
||||
const HEROES: Hero[] = [
|
||||
new Hero(11, 'Mr. Nice'),
|
||||
new Hero(12, 'Narco'),
|
||||
new Hero(13, 'Bombasto'),
|
||||
new Hero(14, 'Celeritas'),
|
||||
new Hero(15, 'Magneta'),
|
||||
new Hero(16, 'RubberMan')
|
||||
];
|
||||
|
||||
const FETCH_LATENCY = 500;
|
||||
|
||||
/** Simulate a data service that retrieves heroes from a server */
|
||||
@Injectable()
|
||||
export class HeroService implements OnDestroy {
|
||||
|
||||
constructor() { console.log('HeroService instance created.'); }
|
||||
ngOnDestroy() { console.log('HeroService instance destroyed.'); }
|
||||
|
||||
getHeroes(): Observable<Hero[]> {
|
||||
return of(HEROES).pipe(delay(FETCH_LATENCY));
|
||||
}
|
||||
|
||||
getHero(id: number | string): Observable<Hero> {
|
||||
return of(HEROES.find(hero => hero.id === +id))
|
||||
.pipe(delay(FETCH_LATENCY));
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
// Exact copy of contact.awesome.pipe
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({ name: 'awesome' })
|
||||
/** Precede the input string with the word "Awesome " */
|
||||
export class AwesomePipe implements PipeTransform {
|
||||
transform(phrase: string) {
|
||||
return phrase ? 'Awesome ' + phrase : '';
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
// Exact copy of contact/highlight.directive except for color and message
|
||||
import { Directive, ElementRef } from '@angular/core';
|
||||
|
||||
@Directive({ selector: '[highlight], input' })
|
||||
// Highlight the host element or any InputElement in gray
|
||||
export class HighlightDirective {
|
||||
constructor(el: ElementRef) {
|
||||
el.nativeElement.style.backgroundColor = 'lightgray';
|
||||
console.log(
|
||||
`* Shared highlight called for ${el.nativeElement.tagName}`);
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { AwesomePipe } from './awesome.pipe';
|
||||
import { HighlightDirective } from './highlight.directive';
|
||||
|
||||
// #docregion module
|
||||
@NgModule({
|
||||
imports: [ CommonModule ],
|
||||
declarations: [ AwesomePipe, HighlightDirective ],
|
||||
exports: [ AwesomePipe, HighlightDirective,
|
||||
CommonModule, FormsModule ]
|
||||
})
|
||||
export class SharedModule { }
|
||||
// #enddocregion module
|
||||
// #enddocregion
|
@ -1,8 +0,0 @@
|
||||
// #docregion
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
/** Dummy version of an authenticated user service */
|
||||
export class UserService {
|
||||
userName = 'Sherlock Holmes';
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<base href="/">
|
||||
<title>NgModule Minimal</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<base href="/">
|
||||
<title>NgModule Minimal</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<base href="/">
|
||||
<title>NgModule Minimal</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<base href="/">
|
||||
<title>NgModule Minimal</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<base href="/">
|
||||
<title>NgModule Deluxe</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
@ -1,13 +0,0 @@
|
||||
// #docplaster
|
||||
/*
|
||||
// #docregion
|
||||
// The browser platform without a compiler
|
||||
import { platformBrowser } from '@angular/platform-browser';
|
||||
|
||||
// The app module factory produced by the static offline compiler
|
||||
import { AppModuleNgFactory } from './app/app.module.ngfactory';
|
||||
|
||||
// Launch with the app module factory.
|
||||
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
|
||||
// #enddocregion
|
||||
*/
|
@ -1,11 +0,0 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module.0';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
@ -1,11 +0,0 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module.1';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
@ -1,11 +0,0 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module.1b';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
@ -1,11 +0,0 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module.2';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
@ -1,11 +0,0 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module.3';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
@ -1,40 +0,0 @@
|
||||
{
|
||||
"description": "NgModule Final",
|
||||
"files": [
|
||||
"src/app/app.component.ts",
|
||||
"src/app/app.module.ts",
|
||||
"src/app/app-routing.module.ts",
|
||||
|
||||
"src/app/contact/contact.component.css",
|
||||
"src/app/contact/contact.component.html",
|
||||
"src/app/contact/contact.service.ts",
|
||||
|
||||
"src/app/contact/contact.component.ts",
|
||||
"src/app/contact/contact.module.ts",
|
||||
"src/app/contact/contact-routing.module.ts",
|
||||
|
||||
"src/app/crisis/*.ts",
|
||||
|
||||
"src/app/hero/hero-detail.component.ts",
|
||||
"src/app/hero/hero-list.component.ts",
|
||||
"src/app/hero/hero.service.ts",
|
||||
|
||||
"src/app/hero/hero.component.ts",
|
||||
"src/app/hero/hero.module.ts",
|
||||
"src/app/hero/hero-routing.module.ts",
|
||||
|
||||
"src/app/core/*.css",
|
||||
"src/app/core/*.html",
|
||||
"src/app/core/*.ts",
|
||||
|
||||
"src/app/shared/*.css",
|
||||
"src/app/shared/*.html",
|
||||
"src/app/shared/*.ts",
|
||||
|
||||
"src/main.ts",
|
||||
"src/styles.css",
|
||||
"src/index.html"
|
||||
],
|
||||
"main": "src/index.html",
|
||||
"tags": ["NgModule"]
|
||||
}
|
@ -5,8 +5,6 @@ import { browser, element, by } from 'protractor';
|
||||
describe('NgModule-example', function () {
|
||||
|
||||
// helpers
|
||||
const gold = 'rgba(255, 215, 0, 1)';
|
||||
const powderblue = 'rgba(176, 224, 230, 1)';
|
||||
const lightgray = 'rgba(239, 238, 237, 1)';
|
||||
const white = 'rgba(0, 0, 0, 0)';
|
||||
|
||||
@ -15,7 +13,7 @@ describe('NgModule-example', function () {
|
||||
|
||||
return {
|
||||
title: element.all(by.tagName('h1')).get(0),
|
||||
subtitle: element.all(by.css('app-title p i')).get(0),
|
||||
subtitle: element.all(by.css('app-root p i')).get(0),
|
||||
contactButton: buttons.get(0),
|
||||
itemButton: buttons.get(1),
|
||||
customersButton: buttons.get(2)
|
||||
@ -67,7 +65,7 @@ describe('NgModule-example', function () {
|
||||
|
||||
it('should welcome us', function () {
|
||||
const commons = getCommonsSectionStruct();
|
||||
expect(commons.subtitle.getText()).toBe('Welcome, ' + (name || 'Sherlock Holmes'));
|
||||
expect(commons.subtitle.getText()).toBe('Welcome, ' + (name || 'Miss Marple'));
|
||||
});
|
||||
};
|
||||
}
|
||||
@ -76,7 +74,7 @@ describe('NgModule-example', function () {
|
||||
return function() {
|
||||
it('shows the contact\'s owner', function() {
|
||||
const contacts = getContactSectionStruct();
|
||||
expect(contacts.header.getText()).toBe('Contact of ' + (name || 'Sherlock Holmes'));
|
||||
expect(contacts.header.getText()).toBe((name || 'Miss Marple') + '\'s Contacts');
|
||||
});
|
||||
|
||||
it('can cycle between contacts', function () {
|
||||
@ -92,21 +90,22 @@ describe('NgModule-example', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('can change an existing contact', function () {
|
||||
const contacts = getContactSectionStruct();
|
||||
contacts.input.sendKeys('a');
|
||||
expect(contacts.input.getCssValue('backgroundColor')).toBe(color);
|
||||
expect(contacts.contactNameHeader.getText()).toBe('Awesome Yashaa');
|
||||
});
|
||||
|
||||
it('can create a new contact', function () {
|
||||
const contacts = getContactSectionStruct();
|
||||
const newContactButton = contacts.newContactButton;
|
||||
const nextButton = contacts.nextContactButton;
|
||||
const input = contacts.input;
|
||||
const saveButton = contacts.saveButton;
|
||||
|
||||
newContactButton.click().then(function () {
|
||||
expect(contacts.validationError.getText()).toBe('Name is required');
|
||||
contacts.input.sendKeys('John Doe');
|
||||
expect(contacts.contactNameHeader.getText()).toBe('Awesome John Doe');
|
||||
expect(contacts.validationError.getText()).toBe('');
|
||||
input.click();
|
||||
nextButton.click()
|
||||
expect(contacts.validationError.getText()).toBe('Name is required.');
|
||||
input.click();
|
||||
contacts.input.sendKeys('Watson');
|
||||
saveButton.click()
|
||||
expect(contacts.contactNameHeader.getText()).toBe('Awesome Watson');
|
||||
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -3,7 +3,7 @@ import { Component } from '@angular/core';
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<app-title></app-title>
|
||||
<app-greeting></app-greeting>
|
||||
<nav>
|
||||
<a routerLink="contact" routerLinkActive="active">Contact</a>
|
||||
<a routerLink="items" routerLinkActive="active">Items</a>
|
||||
|
@ -1,3 +1,5 @@
|
||||
// #docplaster
|
||||
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
@ -7,28 +9,30 @@ import { AppComponent } from './app.component';
|
||||
/* Feature Modules */
|
||||
import { ContactModule } from './contact/contact.module';
|
||||
// #docregion import-for-root
|
||||
import { CoreModule } from './core/core.module';
|
||||
import { GreetingModule } from './greeting/greeting.module';
|
||||
// #enddocregion import-for-root
|
||||
|
||||
/* Routing Module */
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
|
||||
|
||||
// #docregion import-for-root
|
||||
@NgModule({
|
||||
imports: [
|
||||
// #enddocregion import-for-root
|
||||
BrowserModule,
|
||||
ContactModule,
|
||||
CoreModule.forRoot({userName: 'Miss Marple'}),
|
||||
// #docregion import-for-root
|
||||
GreetingModule.forRoot({userName: 'Miss Marple'}),
|
||||
// #enddocregion import-for-root
|
||||
AppRoutingModule
|
||||
// #docregion import-for-root
|
||||
],
|
||||
// #enddocregion import-for-root
|
||||
providers: [],
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
// #docregion import-for-root
|
||||
})
|
||||
export class AppModule { }
|
||||
// #enddocregion import-for-root
|
||||
export class AppModule { }
|
||||
|
@ -0,0 +1,17 @@
|
||||
.button-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
button {
|
||||
margin: 1rem 1rem 0 0;
|
||||
}
|
||||
|
||||
input {
|
||||
padding: .5rem;
|
||||
margin-left: .5rem;
|
||||
}
|
||||
|
||||
.alert {
|
||||
color: red;
|
||||
font-style: italic;
|
||||
}
|
||||
|
@ -1,32 +1,30 @@
|
||||
|
||||
<h2>Contact of {{userName}}</h2>
|
||||
<h2>{{userName}}'s Contacts</h2>
|
||||
<div *ngIf="msg" class="msg">{{msg}}</div>
|
||||
|
||||
<form *ngIf="contacts" (ngSubmit)="onSubmit()" #contactForm="ngForm">
|
||||
<form *ngIf="contacts" (ngSubmit)="onSubmit()" [formGroup]="contactForm">
|
||||
<h3 highlight>{{ contact.name | awesome }}</h3>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">Name</label>
|
||||
|
||||
<input type="text" class="form-control" required
|
||||
[(ngModel)]="contact.name"
|
||||
name="name" #name="ngModel" >
|
||||
|
||||
<div [hidden]="name.valid" class="alert alert-danger">
|
||||
Name is required
|
||||
<input type="text" formControlName="name" required>
|
||||
<div *ngIf="!contactForm.controls['name'].valid && contactForm.controls['name'].touched" class="alert">
|
||||
Name is required.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button type="submit" class="btn btn-default"
|
||||
[disabled]="!contactForm.form.valid">
|
||||
[disabled]="!contactForm.valid">
|
||||
Save</button>
|
||||
|
||||
<button type="button" class="btn" (click)="next()"
|
||||
[disabled]="!contactForm.form.valid">
|
||||
[disabled]="!contactForm.valid && contactForm.touched">
|
||||
Next Contact</button>
|
||||
|
||||
<button type="button" class="btn" (click)="newContact()">
|
||||
New Contact</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
// Exact copy except import UserService from core
|
||||
// Exact copy except import UserService from greeting
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, Validators } from '@angular/forms';
|
||||
|
||||
import { Contact, ContactService } from './contact.service';
|
||||
import { UserService } from '../core/user.service';
|
||||
import { UserService } from '../greeting/user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-contact',
|
||||
@ -16,15 +17,24 @@ export class ContactComponent implements OnInit {
|
||||
msg = 'Loading contacts ...';
|
||||
userName = '';
|
||||
|
||||
constructor(private contactService: ContactService, userService: UserService) {
|
||||
contactForm = this.fb.group({
|
||||
name: ['', Validators.required]
|
||||
});
|
||||
|
||||
constructor(private contactService: ContactService, userService: UserService, private fb: FormBuilder) {
|
||||
this.userName = userService.userName;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.setupForm();
|
||||
}
|
||||
|
||||
setupForm() {
|
||||
this.contactService.getContacts().subscribe(contacts => {
|
||||
this.msg = '';
|
||||
this.contacts = contacts;
|
||||
this.contact = contacts[0];
|
||||
this.contactForm.get('name').setValue(this.contact.name);
|
||||
});
|
||||
}
|
||||
|
||||
@ -32,15 +42,18 @@ export class ContactComponent implements OnInit {
|
||||
let ix = 1 + this.contacts.indexOf(this.contact);
|
||||
if (ix >= this.contacts.length) { ix = 0; }
|
||||
this.contact = this.contacts[ix];
|
||||
console.log(this.contacts[ix]);
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
// POST-DEMO TODO: do something like save it
|
||||
this.displayMessage('Saved ' + this.contact.name);
|
||||
let newName = this.contactForm.get('name').value;
|
||||
this.displayMessage('Saved ' + newName);
|
||||
this.contact.name = newName;
|
||||
}
|
||||
|
||||
newContact() {
|
||||
this.displayMessage('New contact');
|
||||
this.contactForm.get('name').setValue('');
|
||||
this.contact = {id: 42, name: ''};
|
||||
this.contacts.push(this.contact);
|
||||
}
|
||||
@ -51,4 +64,3 @@ export class ContactComponent implements OnInit {
|
||||
setTimeout(() => this.msg = '', 1500);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { ContactComponent } from './contact.component';
|
||||
import { ContactService } from './contact.service';
|
||||
@ -8,7 +9,8 @@ import { ContactRoutingModule } from './contact-routing.module';
|
||||
@NgModule({
|
||||
imports: [
|
||||
SharedModule,
|
||||
ContactRoutingModule
|
||||
ContactRoutingModule,
|
||||
ReactiveFormsModule
|
||||
],
|
||||
declarations: [ ContactComponent ],
|
||||
providers: [ ContactService ]
|
||||
|
@ -1,46 +0,0 @@
|
||||
// #docregion whole-core-module
|
||||
import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
|
||||
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { TitleComponent } from './title.component';
|
||||
// #docregion user-service
|
||||
import { UserService } from './user.service';
|
||||
// #enddocregion user-service
|
||||
import { UserServiceConfig } from './user.service';
|
||||
|
||||
|
||||
// #docregion user-service
|
||||
@NgModule({
|
||||
// #enddocregion user-service
|
||||
imports: [ CommonModule ],
|
||||
declarations: [ TitleComponent ],
|
||||
exports: [ TitleComponent ],
|
||||
// #docregion user-service
|
||||
providers: [ UserService ]
|
||||
})
|
||||
export class CoreModule {
|
||||
// #enddocregion user-service
|
||||
// #docregion ctor
|
||||
constructor (@Optional() @SkipSelf() parentModule: CoreModule) {
|
||||
if (parentModule) {
|
||||
throw new Error(
|
||||
'CoreModule is already loaded. Import it in the AppModule only');
|
||||
}
|
||||
}
|
||||
// #enddocregion ctor
|
||||
|
||||
// #docregion for-root
|
||||
static forRoot(config: UserServiceConfig): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: CoreModule,
|
||||
providers: [
|
||||
{provide: UserServiceConfig, useValue: config }
|
||||
]
|
||||
};
|
||||
}
|
||||
// #enddocregion for-root
|
||||
// #docregion user-service
|
||||
}
|
||||
// #enddocregion user-service
|
||||
// #enddocregion whole-core-module
|
@ -1,7 +1,7 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { CustomersService } from './customers.service';
|
||||
import { UserService } from '../core/user.service';
|
||||
import { UserService } from '../greeting/user.service';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { UserService } from '../core/user.service';
|
||||
import { UserService } from '../greeting/user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-title',
|
||||
templateUrl: './title.component.html',
|
||||
selector: 'app-greeting',
|
||||
templateUrl: './greeting.component.html',
|
||||
})
|
||||
export class TitleComponent {
|
||||
export class GreetingComponent {
|
||||
title = 'NgModules';
|
||||
user = '';
|
||||
|
@ -0,0 +1,36 @@
|
||||
// #docregion whole-greeting-module
|
||||
import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
|
||||
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { GreetingComponent } from './greeting.component';
|
||||
import { UserServiceConfig } from './user.service';
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [ CommonModule ],
|
||||
declarations: [ GreetingComponent ],
|
||||
exports: [ GreetingComponent ]
|
||||
})
|
||||
export class GreetingModule {
|
||||
// #docregion ctor
|
||||
constructor (@Optional() @SkipSelf() parentModule: GreetingModule) {
|
||||
if (parentModule) {
|
||||
throw new Error(
|
||||
'GreetingModule is already loaded. Import it in the AppModule only');
|
||||
}
|
||||
}
|
||||
// #enddocregion ctor
|
||||
|
||||
// #docregion for-root
|
||||
static forRoot(config: UserServiceConfig): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: GreetingModule,
|
||||
providers: [
|
||||
{provide: UserServiceConfig, useValue: config }
|
||||
]
|
||||
};
|
||||
}
|
||||
// #enddocregion for-root
|
||||
}
|
||||
// #enddocregion whole-greeting-module
|
@ -1,8 +1,3 @@
|
||||
// Proves that UserService is an app-wide singleton and only instantiated once
|
||||
// IFF shared.module follows the `forRoot` pattern.
|
||||
//
|
||||
// If it didn't, a new instance of UserService would be created
|
||||
// after each lazy load and the userName would double up.
|
||||
|
||||
import { Injectable, Optional } from '@angular/core';
|
||||
|
||||
@ -12,7 +7,9 @@ export class UserServiceConfig {
|
||||
userName = 'Philip Marlowe';
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UserService {
|
||||
id = nextId++;
|
||||
private _userName = 'Sherlock Holmes';
|
@ -3,7 +3,9 @@
|
||||
<ul class="items">
|
||||
<li *ngFor="let hero of heroes$ | async">
|
||||
<!-- #docregion nav-to-detail -->
|
||||
<!-- #docregion link-parameters-array -->
|
||||
<a [routerLink]="['/hero', hero.id]">
|
||||
<!-- #enddocregion link-parameters-array -->
|
||||
<span class="badge">{{ hero.id }}</span>{{ hero.name }}
|
||||
</a>
|
||||
<!-- #enddocregion nav-to-detail -->
|
||||
|
@ -28,9 +28,3 @@ export class HeroListComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
/* A link parameters array
|
||||
// #docregion link-parameters-array
|
||||
['/hero', hero.id] // { 15 }
|
||||
// #enddocregion link-parameters-array
|
||||
*/
|
||||
|
@ -15,7 +15,7 @@ const squareOddVals = pipe(
|
||||
// Create an Observable that will run the filter and map functions
|
||||
const squareOdd = squareOddVals(nums);
|
||||
|
||||
// Suscribe to run the combined functions
|
||||
// Subscribe to run the combined functions
|
||||
squareOdd.subscribe(x => console.log(x));
|
||||
|
||||
// #enddocregion
|
||||
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"projectType": "schematics"
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../dist/my-lib",
|
||||
"lib": {
|
||||
"entryFile": "src/public_api.ts"
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
// #docplaster
|
||||
// #docregion collection
|
||||
{
|
||||
"name": "my-lib",
|
||||
"version": "0.0.1",
|
||||
// #enddocregion collection
|
||||
"scripts": {
|
||||
"build": "../../node_modules/.bin/tsc -p tsconfig.schematics.json",
|
||||
"copy:schemas": "cp --parents schematics/*/schema.json ../../dist/my-lib/",
|
||||
"copy:files": "cp --parents -p schematics/*/files/** ../../dist/my-lib/",
|
||||
"copy:collection": "cp schematics/collection.json ../../dist/my-lib/schematics/collection.json",
|
||||
"postbuild": "npm run copy:schemas && npm run copy:files && npm run copy:collection"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^7.2.0",
|
||||
"@angular/core": "^7.2.0"
|
||||
},
|
||||
// #docregion collection
|
||||
"schematics": "./schematics/collection.json"
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/@angular-devkit/schematics/collection-schema.json",
|
||||
"schematics": {
|
||||
"ng-add": {
|
||||
"description": "Add my library to the project.",
|
||||
"factory": "./ng-add/index#ngAdd"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/@angular-devkit/schematics/collection-schema.json",
|
||||
"schematics": {
|
||||
"ng-add": {
|
||||
"description": "Add my library to the project.",
|
||||
"factory": "./ng-add/index#ngAdd"
|
||||
},
|
||||
"my-service": {
|
||||
"description": "Generate a service in the project.",
|
||||
"factory": "./my-service/index#myService",
|
||||
"schema": "./my-service/schema.json"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
// #docregion template
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class <%= classify(name) %>Service {
|
||||
constructor(private http: HttpClient) { }
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user