Compare commits
101 Commits
8.0.0-rc.4
...
4.3.3
Author | SHA1 | Date | |
---|---|---|---|
24db1ed938 | |||
82798e9d04 | |||
da8bb1b45b | |||
f5cbc2ee25 | |||
cbc1986c6f | |||
0982f993cb | |||
a5a29b0591 | |||
a8f3197f24 | |||
e6f37120fe | |||
6840b7bda9 | |||
68f458909a | |||
12acecf756 | |||
cfbed40ab6 | |||
fe1a6b8e42 | |||
13e29c4e89 | |||
fd52b178ed | |||
ca1f071b2e | |||
296adbbb72 | |||
c795ee1176 | |||
b550618afd | |||
d08d6eebff | |||
e9789abd05 | |||
f2ec2cbb99 | |||
8de2ace80a | |||
c977994864 | |||
12b8e1af55 | |||
9a188485f5 | |||
45a10419bc | |||
2245748c14 | |||
bcea196530 | |||
b9e32c833a | |||
be49e0ee93 | |||
bf95655a1a | |||
6bf5b84fa4 | |||
4836565ca7 | |||
750e4e8156 | |||
a0846194b7 | |||
bcf6b90c95 | |||
3ca2a0aa37 | |||
b4be96c65d | |||
434ff5fecb | |||
a1bb9c2d42 | |||
7e626bef0a | |||
a1e83a8ed2 | |||
cbeb197aa5 | |||
0330fa6b82 | |||
97135e8fd5 | |||
35bd07fc7b | |||
a8ac77b645 | |||
9ecd377a51 | |||
76171bd8b4 | |||
1f106d75bc | |||
a4fae8c405 | |||
33c07b3394 | |||
c9d06e676f | |||
c7c65d9fda | |||
257a9e3e6f | |||
c7c0a1688e | |||
7e95e2b0ba | |||
ddc286f4b5 | |||
3d17a3672e | |||
61d253f5fd | |||
54be25a7a1 | |||
b1757037fb | |||
f0476fcff0 | |||
a5c4bb5b96 | |||
4c1f32b0db | |||
383d8969ab | |||
333ffd8d32 | |||
d4679a0bc2 | |||
4ce29f3a5b | |||
17b7bc3e06 | |||
f19bd5f4f3 | |||
d503d25f29 | |||
5d275e994a | |||
d8c8b13bb8 | |||
4671168635 | |||
1ac78bfd5d | |||
4340beacea | |||
ec89f378fc | |||
4dd6863bc2 | |||
37c626e673 | |||
f0a110928b | |||
c39e7d1eb2 | |||
799bffb431 | |||
fda607cc2f | |||
cc3aa68123 | |||
306621d2d6 | |||
d204f7aa2a | |||
a94f5e8cbb | |||
1390afef23 | |||
b0346a6e45 | |||
e5da059994 | |||
ac92c3bb26 | |||
87157d7089 | |||
611dd12f0f | |||
969ce9dc2b | |||
34834a9e79 | |||
6e2ddccc2c | |||
55742e4737 | |||
0091b1e8db |
@ -41,7 +41,7 @@ jobs:
|
|||||||
- restore_cache:
|
- restore_cache:
|
||||||
key: angular-{{ .Branch }}-{{ checksum "npm-shrinkwrap.json" }}
|
key: angular-{{ .Branch }}-{{ checksum "npm-shrinkwrap.json" }}
|
||||||
|
|
||||||
- run: bazel run @io_bazel_rules_typescript_node//:bin/npm install
|
- run: bazel run @build_bazel_rules_typescript_node//:bin/npm install
|
||||||
- run: bazel build ...
|
- run: bazel build ...
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: angular-{{ .Branch }}-{{ checksum "npm-shrinkwrap.json" }}
|
key: angular-{{ .Branch }}-{{ checksum "npm-shrinkwrap.json" }}
|
||||||
|
@ -256,6 +256,8 @@ groups:
|
|||||||
files:
|
files:
|
||||||
include:
|
include:
|
||||||
- "aio/*"
|
- "aio/*"
|
||||||
|
exclude:
|
||||||
|
- "aio/content/*"
|
||||||
users:
|
users:
|
||||||
- petebacondarwin #primary
|
- petebacondarwin #primary
|
||||||
- IgorMinar
|
- IgorMinar
|
||||||
@ -276,6 +278,8 @@ groups:
|
|||||||
- Foxandxss
|
- Foxandxss
|
||||||
- stephenfluin
|
- stephenfluin
|
||||||
- wardbell
|
- wardbell
|
||||||
|
- petebacondarwin
|
||||||
|
- gkalpak
|
||||||
- IgorMinar #fallback
|
- IgorMinar #fallback
|
||||||
- mhevery #fallback
|
- mhevery #fallback
|
||||||
|
|
||||||
@ -289,5 +293,7 @@ groups:
|
|||||||
users:
|
users:
|
||||||
- juleskremer #primary
|
- juleskremer #primary
|
||||||
- stephenfluin
|
- stephenfluin
|
||||||
|
- petebacondarwin
|
||||||
|
- gkalpak
|
||||||
- IgorMinar #fallback
|
- IgorMinar #fallback
|
||||||
- mhevery #fallback
|
- mhevery #fallback
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
sudo: false
|
sudo: false
|
||||||
|
# force trusty as Google Chrome addon is not supported on Precise
|
||||||
|
dist: trusty
|
||||||
node_js:
|
node_js:
|
||||||
- '6.9.5'
|
- '6.9.5'
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
|
chrome: stable
|
||||||
# firefox: "38.0"
|
# firefox: "38.0"
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@ -52,14 +55,15 @@ env:
|
|||||||
- CI_MODE=browserstack_optional
|
- CI_MODE=browserstack_optional
|
||||||
- CI_MODE=docs_test
|
- CI_MODE=docs_test
|
||||||
- CI_MODE=aio
|
- CI_MODE=aio
|
||||||
- CI_MODE=aio_e2e
|
- CI_MODE=aio_e2e AIO_SHARD=0
|
||||||
|
- CI_MODE=aio_e2e AIO_SHARD=1
|
||||||
|
- CI_MODE=bazel
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- env: "CI_MODE=saucelabs_optional"
|
- env: "CI_MODE=saucelabs_optional"
|
||||||
- env: "CI_MODE=browserstack_optional"
|
- env: "CI_MODE=browserstack_optional"
|
||||||
- env: "CI_MODE=aio_e2e"
|
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
# source the env.sh script so that the exported variables are available to other scripts later on
|
# source the env.sh script so that the exported variables are available to other scripts later on
|
||||||
|
@ -11,8 +11,15 @@ filegroup(
|
|||||||
# This won't scale in the general case.
|
# This won't scale in the general case.
|
||||||
# TODO(alexeagle): figure out what to do
|
# TODO(alexeagle): figure out what to do
|
||||||
"node_modules/typescript/**",
|
"node_modules/typescript/**",
|
||||||
"node_modules/zone.js/**/*.d.ts",
|
"node_modules/zone.js/**",
|
||||||
"node_modules/rxjs/**/*.d.ts",
|
"node_modules/rxjs/**/*.d.ts",
|
||||||
|
"node_modules/rxjs/**/*.js",
|
||||||
"node_modules/@types/**/*.d.ts",
|
"node_modules/@types/**/*.d.ts",
|
||||||
|
"node_modules/tsickle/**",
|
||||||
|
"node_modules/hammerjs/**/*.d.ts",
|
||||||
|
"node_modules/protobufjs/**",
|
||||||
|
"node_modules/bytebuffer/**",
|
||||||
|
"node_modules/reflect-metadata/**",
|
||||||
|
"node_modules/minimist/**/*.js",
|
||||||
]),
|
]),
|
||||||
)
|
)
|
48
CHANGELOG.md
@ -1,3 +1,51 @@
|
|||||||
|
<a name="4.3.3"></a>
|
||||||
|
## [4.3.3](https://github.com/angular/angular/compare/4.3.2...4.3.3) (2017-08-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** fix for element needing implicit parent placed in top-level ng-container ([f5cbc2e](https://github.com/angular/angular/commit/f5cbc2e)), closes [#18314](https://github.com/angular/angular/issues/18314)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="4.3.2"></a>
|
||||||
|
## [4.3.2](https://github.com/angular/angular/compare/4.3.1...4.3.2) (2017-07-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **animations:** export BrowserModule as apart of BrowserAnimationsModule ([#18263](https://github.com/angular/angular/issues/18263)) ([cbeb197](https://github.com/angular/angular/commit/cbeb197))
|
||||||
|
* **compiler:** add equiv & disp attributes to Xliff2 ICU placeholders ([#18283](https://github.com/angular/angular/issues/18283)) ([a084619](https://github.com/angular/angular/commit/a084619)), closes [#17344](https://github.com/angular/angular/issues/17344)
|
||||||
|
* **compiler:** allow numbers for ICU message cases in lexer ([#18095](https://github.com/angular/angular/issues/18095)) ([a8ac77b](https://github.com/angular/angular/commit/a8ac77b)), closes [#17799](https://github.com/angular/angular/issues/17799)
|
||||||
|
* **core:** invoke error handler outside of the Angular Zone ([#18269](https://github.com/angular/angular/issues/18269)) ([a1bb9c2](https://github.com/angular/angular/commit/a1bb9c2)), closes [#17073](https://github.com/angular/angular/issues/17073) [#7774](https://github.com/angular/angular/issues/7774)
|
||||||
|
* **platform-server:** don't clobber parse5 properties when setting ([#18237](https://github.com/angular/angular/issues/18237)) ([97135e8](https://github.com/angular/angular/commit/97135e8)), closes [#17050](https://github.com/angular/angular/issues/17050)
|
||||||
|
* **router:** child CanActivate guard should wait for parent to complete ([#18110](https://github.com/angular/angular/issues/18110)) ([b9e32c8](https://github.com/angular/angular/commit/b9e32c8)), closes [#15670](https://github.com/angular/angular/issues/15670)
|
||||||
|
* **router:** should throw when lazy loaded module doesn't define any routes ([#15001](https://github.com/angular/angular/issues/15001)) ([be49e0e](https://github.com/angular/angular/commit/be49e0e)), closes [#14596](https://github.com/angular/angular/issues/14596)
|
||||||
|
* **upgrade:** throw error if trying to get injector before setting ([#18209](https://github.com/angular/angular/issues/18209)) ([1f106d7](https://github.com/angular/angular/commit/1f106d7))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="4.3.1"></a>
|
||||||
|
## [4.3.1](https://github.com/angular/angular/compare/4.3.0...4.3.1) (2017-07-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **animations:** always camelcase style property names that contain auto styles ([383d896](https://github.com/angular/angular/commit/383d896)), closes [#17938](https://github.com/angular/angular/issues/17938)
|
||||||
|
* **animations:** capture cancelled animation styles within grouped animations ([333ffd8](https://github.com/angular/angular/commit/333ffd8)), closes [#17170](https://github.com/angular/angular/issues/17170)
|
||||||
|
* **animations:** do not crash animations if a nested component fires CD during CD ([4c1f32b](https://github.com/angular/angular/commit/4c1f32b)), closes [#18193](https://github.com/angular/angular/issues/18193)
|
||||||
|
* **animations:** make sure @.disabled works in non-animation components ([a5c4bb5](https://github.com/angular/angular/commit/a5c4bb5))
|
||||||
|
* **common:** send flushed body as error instead of null ([17b7bc3](https://github.com/angular/angular/commit/17b7bc3)), closes [#18181](https://github.com/angular/angular/issues/18181)
|
||||||
|
* **compiler:** ensure jit external id arguments names are unique ([4671168](https://github.com/angular/angular/commit/4671168))
|
||||||
|
* **compiler-cli:** don't generate empty `<target/>` when extracting xliff ([f0476fc](https://github.com/angular/angular/commit/f0476fc)), closes [#15754](https://github.com/angular/angular/issues/15754)
|
||||||
|
* **platform-server:** provide XhrFactory for HttpClient ([4ce29f3](https://github.com/angular/angular/commit/4ce29f3))
|
||||||
|
* **router:** canDeactivate guards should run from bottom to top ([1ac78bf](https://github.com/angular/angular/commit/1ac78bf)), closes [#15657](https://github.com/angular/angular/issues/15657)
|
||||||
|
* **router:** should navigate to the same url when config changes ([4340bea](https://github.com/angular/angular/commit/4340bea)), closes [#15535](https://github.com/angular/angular/issues/15535)
|
||||||
|
* **router:** should run resolvers for the same route concurrently ([ec89f37](https://github.com/angular/angular/commit/ec89f37)), closes [#14279](https://github.com/angular/angular/issues/14279)
|
||||||
|
* **router:** terminal route in custom matcher ([5d275e9](https://github.com/angular/angular/commit/5d275e9))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="4.3.0"></a>
|
<a name="4.3.0"></a>
|
||||||
# [4.3.0](https://github.com/angular/angular/compare/4.3.0-rc.0...4.3.0) (2017-07-14)
|
# [4.3.0](https://github.com/angular/angular/compare/4.3.0-rc.0...4.3.0) (2017-07-14)
|
||||||
|
|
||||||
|
12
WORKSPACE
@ -1,11 +1,17 @@
|
|||||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||||
|
|
||||||
git_repository(
|
git_repository(
|
||||||
name = "io_bazel_rules_typescript",
|
name = "build_bazel_rules_typescript",
|
||||||
remote = "https://github.com/bazelbuild/rules_typescript.git",
|
remote = "https://github.com/bazelbuild/rules_typescript.git",
|
||||||
commit = "3a8404d",
|
tag = "0.0.5",
|
||||||
)
|
)
|
||||||
|
|
||||||
load("@io_bazel_rules_typescript//:defs.bzl", "node_repositories")
|
load("@build_bazel_rules_typescript//:defs.bzl", "node_repositories")
|
||||||
|
|
||||||
node_repositories(package_json = "//:package.json")
|
node_repositories(package_json = "//:package.json")
|
||||||
|
|
||||||
|
git_repository(
|
||||||
|
name = "build_bazel_rules_angular",
|
||||||
|
remote = "https://github.com/bazelbuild/rules_angular.git",
|
||||||
|
tag = "0.0.1",
|
||||||
|
)
|
10
aio/content/examples/.gitignore
vendored
@ -43,13 +43,9 @@ dist/
|
|||||||
**/app/**/*.ajs.js
|
**/app/**/*.ajs.js
|
||||||
|
|
||||||
# aot
|
# aot
|
||||||
**/*.ngfactory.ts
|
*/aot/**/*
|
||||||
**/*.ngsummary.json
|
!*/aot/bs-config.json
|
||||||
**/*.ngsummary.ts
|
!*/aot/index.html
|
||||||
**/*.shim.ngstyle.ts
|
|
||||||
**/*.metadata.json
|
|
||||||
!aot/bs-config.json
|
|
||||||
!aot/index.html
|
|
||||||
!rollup-config.js
|
!rollup-config.js
|
||||||
|
|
||||||
# i18n
|
# i18n
|
||||||
|
@ -9,7 +9,7 @@ export class AppComponent {
|
|||||||
wolves = 0;
|
wolves = 0;
|
||||||
gender = 'f';
|
gender = 'f';
|
||||||
fly = true;
|
fly = true;
|
||||||
logo = 'https://angular.io/resources/images/logos/angular/angular.png';
|
logo = 'https://angular.io/assets/images/logos/angular/angular.png';
|
||||||
count = 3;
|
count = 3;
|
||||||
heroes: string[] = ['Magneta', 'Celeritas', 'Dynama'];
|
heroes: string[] = ['Magneta', 'Celeritas', 'Dynama'];
|
||||||
inc(i: number) {
|
inc(i: number) {
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
/* #docregion , quickstart, toh */
|
|
||||||
/* Master Styles */
|
|
||||||
h1 {
|
|
||||||
color: #369;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
font-size: 250%;
|
|
||||||
}
|
|
||||||
h2, h3 {
|
|
||||||
color: #444;
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
font-weight: lighter;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
margin: 2em;
|
|
||||||
}
|
|
||||||
/* #enddocregion quickstart */
|
|
||||||
body, input[text], button {
|
|
||||||
color: #888;
|
|
||||||
font-family: Cambria, Georgia;
|
|
||||||
}
|
|
||||||
/* #enddocregion toh */
|
|
||||||
a {
|
|
||||||
cursor: pointer;
|
|
||||||
cursor: hand;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
font-family: Arial;
|
|
||||||
background-color: #eee;
|
|
||||||
border: none;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
cursor: hand;
|
|
||||||
}
|
|
||||||
button:hover {
|
|
||||||
background-color: #cfd8dc;
|
|
||||||
}
|
|
||||||
button:disabled {
|
|
||||||
background-color: #eee;
|
|
||||||
color: #aaa;
|
|
||||||
cursor: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Navigation link styles */
|
|
||||||
nav a {
|
|
||||||
padding: 5px 10px;
|
|
||||||
text-decoration: none;
|
|
||||||
margin-right: 10px;
|
|
||||||
margin-top: 10px;
|
|
||||||
display: inline-block;
|
|
||||||
background-color: #eee;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
nav a:visited, a:link {
|
|
||||||
color: #607D8B;
|
|
||||||
}
|
|
||||||
nav a:hover {
|
|
||||||
color: #039be5;
|
|
||||||
background-color: #CFD8DC;
|
|
||||||
}
|
|
||||||
nav a.active {
|
|
||||||
color: #039be5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* items class */
|
|
||||||
.items {
|
|
||||||
margin: 0 0 2em 0;
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
width: 24em;
|
|
||||||
}
|
|
||||||
.items li {
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
left: 0;
|
|
||||||
background-color: #EEE;
|
|
||||||
margin: .5em;
|
|
||||||
padding: .3em 0;
|
|
||||||
height: 1.6em;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
.items li:hover {
|
|
||||||
color: #607D8B;
|
|
||||||
background-color: #DDD;
|
|
||||||
left: .1em;
|
|
||||||
}
|
|
||||||
.items li.selected {
|
|
||||||
background-color: #CFD8DC;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.items li.selected:hover {
|
|
||||||
background-color: #BBD8DC;
|
|
||||||
}
|
|
||||||
.items .text {
|
|
||||||
position: relative;
|
|
||||||
top: -3px;
|
|
||||||
}
|
|
||||||
.items .badge {
|
|
||||||
display: inline-block;
|
|
||||||
font-size: small;
|
|
||||||
color: white;
|
|
||||||
padding: 0.8em 0.7em 0 0.7em;
|
|
||||||
background-color: #607D8B;
|
|
||||||
line-height: 1em;
|
|
||||||
position: relative;
|
|
||||||
left: -1px;
|
|
||||||
top: -4px;
|
|
||||||
height: 1.8em;
|
|
||||||
margin-right: .8em;
|
|
||||||
border-radius: 4px 0 0 4px;
|
|
||||||
}
|
|
||||||
/* #docregion toh */
|
|
||||||
/* everywhere else */
|
|
||||||
* {
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
}
|
|
@ -9,7 +9,8 @@ describe('PhoneCat Application', function() {
|
|||||||
|
|
||||||
it('should redirect `index.html` to `index.html#!/phones', function() {
|
it('should redirect `index.html` to `index.html#!/phones', function() {
|
||||||
browser.get('index.html');
|
browser.get('index.html');
|
||||||
expect(browser.getLocationAbsUrl()).toBe('/phones');
|
browser.sleep(1000); // Not sure why this is needed but it is. The route change works fine.
|
||||||
|
expect(browser.getCurrentUrl()).toMatch(/\/phones$/);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('View: Phone list', function() {
|
describe('View: Phone list', function() {
|
||||||
@ -65,7 +66,7 @@ describe('PhoneCat Application', function() {
|
|||||||
|
|
||||||
element.all(by.css('.phones li a')).first().click();
|
element.all(by.css('.phones li a')).first().click();
|
||||||
browser.sleep(1000); // Not sure why this is needed but it is. The route change works fine.
|
browser.sleep(1000); // Not sure why this is needed but it is. The route change works fine.
|
||||||
expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s');
|
expect(browser.getCurrentUrl()).toMatch(/\/phones\/nexus-s$/);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -124,7 +124,7 @@ For example, import Angular's `Component` decorator from the `@angular/core` lib
|
|||||||
|
|
||||||
<code-example path="architecture/src/app/app.component.ts" region="import" linenums="false"></code-example>
|
<code-example path="architecture/src/app/app.component.ts" region="import" linenums="false"></code-example>
|
||||||
|
|
||||||
You also import NgModules_ from Angular _libraries_ using JavaScript import statements:
|
You also import NgModules from Angular _libraries_ using JavaScript import statements:
|
||||||
|
|
||||||
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module" linenums="false"></code-example>
|
<code-example path="architecture/src/app/mini-app.ts" region="import-browser-module" linenums="false"></code-example>
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
# Bootstrapping
|
# Bootstrapping
|
||||||
|
|
||||||
An NgModule class describes how the application parts fit together.
|
An NgModule class describes how the application parts fit together.
|
||||||
Every application has at least one NgModule, the _root_ module
|
Every application has at least one NgModule, the _root_ module
|
||||||
that you [bootstrap](guide/appmodule#main) to launch the application.
|
that you [bootstrap](#main) to launch the application.
|
||||||
You can call it anything you want. The conventional name is `AppModule`.
|
You can call it anything you want. The conventional name is `AppModule`.
|
||||||
|
|
||||||
The [setup](guide/setup) instructions produce a new project with the following minimal `AppModule`.
|
The [setup](guide/setup) instructions produce a new project with the following minimal `AppModule`.
|
||||||
@ -25,7 +25,7 @@ The `@NgModule` decorator identifies `AppModule` as an `NgModule` class.
|
|||||||
* **_bootstrap_** — the _root_ component that Angular creates and inserts into the `index.html` host web page.
|
* **_bootstrap_** — the _root_ component that Angular creates and inserts into the `index.html` host web page.
|
||||||
|
|
||||||
The [NgModules](guide/ngmodule) guide dives deeply into the details of NgModules.
|
The [NgModules](guide/ngmodule) guide dives deeply into the details of NgModules.
|
||||||
All you need to know at the moment is a few basics about these three properties.
|
All you need to know at the moment is a few basics about these three properties.
|
||||||
|
|
||||||
|
|
||||||
{@a imports}
|
{@a imports}
|
||||||
@ -34,7 +34,7 @@ All you need to know at the moment is a few basics about these three properties.
|
|||||||
### The _imports_ array
|
### The _imports_ array
|
||||||
|
|
||||||
NgModules are a way to consolidate features that belong together into discrete units.
|
NgModules are a way to consolidate features that belong together into discrete units.
|
||||||
Many features of Angular itself are organized as NgModules.
|
Many features of Angular itself are organized as NgModules.
|
||||||
HTTP services are in the `HttpModule`. The router is in the `RouterModule`.
|
HTTP services are in the `HttpModule`. The router is in the `RouterModule`.
|
||||||
Eventually you may create a feature module.
|
Eventually you may create a feature module.
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ You add `import` statements to almost every application file.
|
|||||||
They have nothing to do with Angular and Angular knows nothing about them.
|
They have nothing to do with Angular and Angular knows nothing about them.
|
||||||
|
|
||||||
The _module's_ `imports` array appears _exclusively_ in the `@NgModule` metadata object.
|
The _module's_ `imports` array appears _exclusively_ in the `@NgModule` metadata object.
|
||||||
It tells Angular about specific _other_ NgModules—all of them classes decorated
|
It tells Angular about specific _other_ NgModules—all of them classes decorated
|
||||||
with `@NgModule`—that the application needs to function properly.
|
with `@NgModule`—that the application needs to function properly.
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -110,7 +110,7 @@ Do not put any other kind of class in `declarations`; _not_ `NgModule` classes,
|
|||||||
|
|
||||||
### The _bootstrap_ array
|
### The _bootstrap_ array
|
||||||
|
|
||||||
You launch the application by [_bootstrapping_](guide/bootstrapping#main) the root `AppModule`.
|
You launch the application by [_bootstrapping_](#main) the root `AppModule`.
|
||||||
Among other things, the _bootstrapping_ process creates the component(s) listed in the `bootstrap` array
|
Among other things, the _bootstrapping_ process creates the component(s) listed in the `bootstrap` array
|
||||||
and inserts each one into the browser DOM.
|
and inserts each one into the browser DOM.
|
||||||
|
|
||||||
@ -127,13 +127,6 @@ Which brings us to the _bootstrapping_ process itself.
|
|||||||
|
|
||||||
{@a main}
|
{@a main}
|
||||||
|
|
||||||
|
|
||||||
<l-main-section>
|
|
||||||
|
|
||||||
</l-main-section>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Bootstrap in _main.ts_
|
## Bootstrap in _main.ts_
|
||||||
|
|
||||||
There are many ways to bootstrap an application.
|
There are many ways to bootstrap an application.
|
||||||
|
@ -193,8 +193,8 @@ Angular supports most recent browsers. This includes the following specific vers
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Angular's continuous integration process runs unit tests of the framework on all of these browsers for every pull request,
|
Angular's continuous integration process runs unit tests of the framework on all of these browsers for every pull request,
|
||||||
using <a href="https://saucelabs.com/">SauceLabs</a> and
|
using <a href="https://saucelabs.com/">SauceLabs</a> and
|
||||||
<a href="https://www.browserstack.com">Browserstack</a>.
|
<a href="https://www.browserstack.com">Browserstack</a>.
|
||||||
|
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ that implement missing features in JavaScript.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
A particular browser may require at least one polyfill to run _any_ Angular application.
|
A particular browser may require at least one polyfill to run _any_ Angular application.
|
||||||
You may need additional polyfills for specific features.
|
You may need additional polyfills for specific features.
|
||||||
|
|
||||||
The tables below can help you determine which polyfills to load, depending on the browsers you target and the features you use.
|
The tables below can help you determine which polyfills to load, depending on the browsers you target and the features you use.
|
||||||
@ -241,7 +241,7 @@ These are the polyfills required to run an Angular application on each supported
|
|||||||
<table>
|
<table>
|
||||||
|
|
||||||
<tr style="vertical-align: top">
|
<tr style="vertical-align: top">
|
||||||
|
|
||||||
<th>
|
<th>
|
||||||
Browsers (Desktop & Mobile)
|
Browsers (Desktop & Mobile)
|
||||||
</th>
|
</th>
|
||||||
@ -253,7 +253,7 @@ These are the polyfills required to run an Angular application on each supported
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr style="vertical-align: top">
|
<tr style="vertical-align: top">
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
Chrome, Firefox, Edge, Safari 9+
|
Chrome, Firefox, Edge, Safari 9+
|
||||||
</td>
|
</td>
|
||||||
@ -265,7 +265,7 @@ These are the polyfills required to run an Angular application on each supported
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr style="vertical-align: top">
|
<tr style="vertical-align: top">
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
Safari 7 & 8, IE10 & 11, Android 4.1+
|
Safari 7 & 8, IE10 & 11, Android 4.1+
|
||||||
</td>
|
</td>
|
||||||
@ -279,7 +279,7 @@ These are the polyfills required to run an Angular application on each supported
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr style="vertical-align: top">
|
<tr style="vertical-align: top">
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
IE9
|
IE9
|
||||||
</td>
|
</td>
|
||||||
@ -309,7 +309,7 @@ Here are the features which may require additional polyfills:
|
|||||||
<table>
|
<table>
|
||||||
|
|
||||||
<tr style="vertical-align: top">
|
<tr style="vertical-align: top">
|
||||||
|
|
||||||
<th>
|
<th>
|
||||||
Feature
|
Feature
|
||||||
</th>
|
</th>
|
||||||
@ -325,7 +325,7 @@ Here are the features which may require additional polyfills:
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr style="vertical-align: top">
|
<tr style="vertical-align: top">
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
[Animations](guide/animations)
|
[Animations](guide/animations)
|
||||||
@ -363,14 +363,14 @@ Here are the features which may require additional polyfills:
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr style="vertical-align: top">
|
<tr style="vertical-align: top">
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
[NgClass](api/common/NgClass) on SVG elements
|
[NgClass](api/common/NgClass) on SVG elements
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
|
|
||||||
[classList](guide/browser-support#classlist)
|
[classList](guide/browser-support#classlist)
|
||||||
</td>
|
</td>
|
||||||
@ -382,16 +382,17 @@ Here are the features which may require additional polyfills:
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr style="vertical-align: top">
|
<tr style="vertical-align: top">
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
[Http](guide/http) when sending and receiving binary data
|
[Http](guide/http) when sending and receiving binary data
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
|
|
||||||
[Typed Array](guide/browser-support#typedarray) <br>[Blob](guide/browser-support#blob)<br>[FormData](guide/browser-support#formdata)
|
[Typed Array](guide/browser-support#typedarray)<br>
|
||||||
|
[Blob](guide/browser-support#blob)<br>
|
||||||
|
[FormData](guide/browser-support#formdata)
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
@ -405,7 +406,7 @@ Here are the features which may require additional polyfills:
|
|||||||
|
|
||||||
|
|
||||||
### Suggested polyfills ##
|
### Suggested polyfills ##
|
||||||
Below are the polyfills which are used to test the framework itself. They are a good starting point for an application.
|
Below are the polyfills which are used to test the framework itself. They are a good starting point for an application.
|
||||||
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
@ -542,5 +543,5 @@ Below are the polyfills which are used to test the framework itself. They are a
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
\* Figures are for minified and gzipped code,
|
\* Figures are for minified and gzipped code,
|
||||||
computed with the <a href="http://closure-compiler.appspot.com/home">closure compiler</a>.
|
computed with the <a href="http://closure-compiler.appspot.com/home">closure compiler</a>.
|
||||||
|
@ -27,12 +27,12 @@ Revised samples are more clear and cover all topics discussed.
|
|||||||
## NEW: Samples re-structured with `src/` folder (2017-02-02)
|
## NEW: Samples re-structured with `src/` folder (2017-02-02)
|
||||||
All documentation samples have been realigned with the default folder structure of the Angular CLI.
|
All documentation samples have been realigned with the default folder structure of the Angular CLI.
|
||||||
That's a step along the road to basing the sample in the Angular CLI.
|
That's a step along the road to basing the sample in the Angular CLI.
|
||||||
But it's also good in its own right.
|
But it's also good in its own right.
|
||||||
It helps clearly separate app code from setup and configuration files.
|
It helps clearly separate app code from setup and configuration files.
|
||||||
|
|
||||||
All samples now have a `src/` folder at the project root.
|
All samples now have a `src/` folder at the project root.
|
||||||
The former `app/` folder moves under `src/`.
|
The former `app/` folder moves under `src/`.
|
||||||
Read about moving your existing project to this structure in
|
Read about moving your existing project to this structure in
|
||||||
<a href="https://github.com/angular/quickstart#updating-to-a-newer-version-of-the-quickstart-repo" target="Migrating samples/quickstart app to the src folder">
|
<a href="https://github.com/angular/quickstart#updating-to-a-newer-version-of-the-quickstart-repo" target="Migrating samples/quickstart app to the src folder">
|
||||||
the QuickStart repo update instructions</a>.
|
the QuickStart repo update instructions</a>.
|
||||||
|
|
||||||
@ -48,8 +48,8 @@ Notably:
|
|||||||
The new [**Reactive Forms**](guide/reactive-forms) guide explains how and why to build a "reactive form".
|
The new [**Reactive Forms**](guide/reactive-forms) guide explains how and why to build a "reactive form".
|
||||||
"Reactive Forms" are the code-based counterpart to the declarative "Template Driven" forms approach
|
"Reactive Forms" are the code-based counterpart to the declarative "Template Driven" forms approach
|
||||||
introduced in the [Forms](guide/forms) guide.
|
introduced in the [Forms](guide/forms) guide.
|
||||||
Check it out before you decide how to add forms to your app.
|
Check it out before you decide how to add forms to your app.
|
||||||
Remember also that you can use both techniques in the same app,
|
Remember also that you can use both techniques in the same app,
|
||||||
choosing the approach that best fits each scenario.
|
choosing the approach that best fits each scenario.
|
||||||
|
|
||||||
## NEW: Deployment guide (2017-01-30)
|
## NEW: Deployment guide (2017-01-30)
|
||||||
@ -65,25 +65,25 @@ Revised samples are clearer and cover all topics discussed.
|
|||||||
|
|
||||||
## Miscellaneous (2017-01-05)
|
## Miscellaneous (2017-01-05)
|
||||||
|
|
||||||
* [Setup](guide/setup) guide:
|
* [Setup](guide/setup) guide:
|
||||||
added (optional) instructions on how to remove _non-essential_ files.
|
added (optional) instructions on how to remove _non-essential_ files.
|
||||||
* No longer consolidate RxJS operator imports in `rxjs-extensions` file; each file should import what it needs.
|
* No longer consolidate RxJS operator imports in `rxjs-extensions` file; each file should import what it needs.
|
||||||
* All samples prepend template/style URLs with `./` as a best practice.
|
* All samples prepend template/style URLs with `./` as a best practice.
|
||||||
* [Style Guide](guide/styleguide): copy edits and revised rules.
|
* [Style Guide](guide/styleguide): copy edits and revised rules.
|
||||||
|
|
||||||
## Router: more detail (2016-12-21)
|
## Router: more detail (2016-12-21)
|
||||||
|
|
||||||
Added more information to the [Router](guide/router) guide
|
Added more information to the [Router](guide/router) guide
|
||||||
including sections named outlets, wildcard routes, and preload strategies.
|
including sections named outlets, wildcard routes, and preload strategies.
|
||||||
|
|
||||||
## HTTP: how to set default request headers (and other request options) (2016-12-14)
|
## HTTP: how to set default request headers (and other request options) (2016-12-14)
|
||||||
|
|
||||||
Added section on how to set default request headers (and other request options) to
|
Added section on how to set default request headers (and other request options) to
|
||||||
[HTTP](guide/http#override-default-request-options) guide.
|
HTTP guide.
|
||||||
|
|
||||||
## Testing: added component test plunkers (2016-12-02)
|
## Testing: added component test plunkers (2016-12-02)
|
||||||
|
|
||||||
Added two plunkers that each test _one simple component_ so you can write a component test plunker of your own: <live-example name="setup" plnkr="quickstart-specs">one</live-example> for the QuickStart seed's `AppComponent` and <live-example name="testing" plnkr="banner-specs">another</live-example> for the Testing guide's `BannerComponent`.
|
Added two plunkers that each test _one simple component_ so you can write a component test plunker of your own: <live-example name="setup" plnkr="quickstart-specs">one</live-example> for the QuickStart seed's `AppComponent` and <live-example name="testing" plnkr="banner-specs">another</live-example> for the Testing guide's `BannerComponent`.
|
||||||
Linked to these plunkers in [Testing](guide/testing#live-examples) and [Setup anatomy](guide/setup-systemjs-anatomy) guides.
|
Linked to these plunkers in [Testing](guide/testing#live-examples) and [Setup anatomy](guide/setup-systemjs-anatomy) guides.
|
||||||
|
|
||||||
## Internationalization: pluralization and _select_ (2016-11-30)
|
## Internationalization: pluralization and _select_ (2016-11-30)
|
||||||
@ -112,15 +112,15 @@ Docs and code samples updated and tested with Angular v.2.2.0.
|
|||||||
|
|
||||||
## UPDATE: NgUpgrade Guide for the AOT friendly _upgrade/static_ module (2016-11-14)
|
## UPDATE: NgUpgrade Guide for the AOT friendly _upgrade/static_ module (2016-11-14)
|
||||||
|
|
||||||
The updated [NgUpgrade Guide](guide/upgrade) guide covers the
|
The updated [NgUpgrade Guide](guide/upgrade) guide covers the
|
||||||
new AOT friendly `upgrade/static` module
|
new AOT friendly `upgrade/static` module
|
||||||
released in v.2.2.0, which is the recommended
|
released in v.2.2.0, which is the recommended
|
||||||
facility for migrating from AngularJS to Angular.
|
facility for migrating from AngularJS to Angular.
|
||||||
The documentation for the version prior to v.2.2.0 has been removed.
|
The documentation for the version prior to v.2.2.0 has been removed.
|
||||||
|
|
||||||
## ES6 described in "TypeScript to JavaScript" (2016-11-14)
|
## ES6 described in "TypeScript to JavaScript" (2016-11-14)
|
||||||
|
|
||||||
The updated [TypeScript to JavaScript](guide/ts-to-js) guide
|
The updated [TypeScript to JavaScript](guide/ts-to-js) guide
|
||||||
now explains how to write apps in ES6/7
|
now explains how to write apps in ES6/7
|
||||||
by translating the common idioms in the TypeScript documentation examples
|
by translating the common idioms in the TypeScript documentation examples
|
||||||
(and elsewhere on the web) to ES6/7 and ES5.
|
(and elsewhere on the web) to ES6/7 and ES5.
|
||||||
@ -156,7 +156,7 @@ in the `in-memory-web-api` repo.
|
|||||||
The router can lazily _preload_ modules _after_ the app starts and
|
The router can lazily _preload_ modules _after_ the app starts and
|
||||||
_before_ the user navigates to them for improved perceived performance.
|
_before_ the user navigates to them for improved perceived performance.
|
||||||
|
|
||||||
New `:enter` and `:leave` aliases make animation more natural.
|
New `:enter` and `:leave` aliases make animation more natural.
|
||||||
|
|
||||||
## Sync with Angular v.2.1.0 (2016-10-12)
|
## Sync with Angular v.2.1.0 (2016-10-12)
|
||||||
|
|
||||||
@ -176,11 +176,11 @@ Docs and code samples updated and tested with Angular v.2.0.2.
|
|||||||
## "Routing and Navigation" guide with the _Router Module_ (2016-10-5)
|
## "Routing and Navigation" guide with the _Router Module_ (2016-10-5)
|
||||||
|
|
||||||
The [Routing and Navigation](guide/router) guide now locates route configuration
|
The [Routing and Navigation](guide/router) guide now locates route configuration
|
||||||
in a _Routing Module_.
|
in a _Routing Module_.
|
||||||
The _Routing Module_ replaces the previous _routing object_ involving the `ModuleWithProviders`.
|
The _Routing Module_ replaces the previous _routing object_ involving the `ModuleWithProviders`.
|
||||||
|
|
||||||
All guided samples with routing use the _Routing Module_ and prose content has been updated,
|
All guided samples with routing use the _Routing Module_ and prose content has been updated,
|
||||||
most conspicuously in the
|
most conspicuously in the
|
||||||
[NgModule](guide/ngmodule) guide and [NgModule FAQ](guide/ngmodule-faq) guide.
|
[NgModule](guide/ngmodule) guide and [NgModule FAQ](guide/ngmodule-faq) guide.
|
||||||
|
|
||||||
## New "Internationalization" guide (2016-09-30)
|
## New "Internationalization" guide (2016-09-30)
|
||||||
@ -194,7 +194,7 @@ Many samples use the `angular-in-memory-web-api` to simulate a remote server.
|
|||||||
This library is also useful to you during early development before you have a server to talk to.
|
This library is also useful to you during early development before you have a server to talk to.
|
||||||
|
|
||||||
The package name was changed from "angular2-in-memory-web-api" which is still frozen-in-time on npm.
|
The package name was changed from "angular2-in-memory-web-api" which is still frozen-in-time on npm.
|
||||||
The new "angular-in-memory-web-api" has new features.
|
The new "angular-in-memory-web-api" has new features.
|
||||||
<a href="https://github.com/angular/in-memory-web-api/blob/master/README.md">Read about them on github</a>.
|
<a href="https://github.com/angular/in-memory-web-api/blob/master/README.md">Read about them on github</a>.
|
||||||
|
|
||||||
## "Style Guide" with _NgModules_ (2016-09-27)
|
## "Style Guide" with _NgModules_ (2016-09-27)
|
||||||
@ -215,5 +215,5 @@ modules with SystemJS as the samples currently do.
|
|||||||
|
|
||||||
## "Lifecycle Hooks" guide simplified (2016-09-24)
|
## "Lifecycle Hooks" guide simplified (2016-09-24)
|
||||||
|
|
||||||
The [Lifecycle Hooks](guide/lifecycle-hooks) guide is shorter, simpler, and
|
The [Lifecycle Hooks](guide/lifecycle-hooks) guide is shorter, simpler, and
|
||||||
draws more attention to the order in which Angular calls the hooks.
|
draws more attention to the order in which Angular calls the hooks.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Cheat Sheet
|
<h1 class="no-toc">Cheat Sheet</h1>
|
||||||
|
|
||||||
<div id="cheatsheet">
|
<div id="cheatsheet">
|
||||||
<table class="is-full-width is-fixed-layout">
|
<table class="is-full-width is-fixed-layout">
|
||||||
@ -23,28 +23,28 @@
|
|||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>@<b>NgModule</b>({ declarations: ..., imports: ...,<br> exports: ..., providers: ..., bootstrap: ...})<br>class MyModule {}</code></td>
|
<td><code>@<b>NgModule</b>({ declarations: ..., imports: ...,<br> exports: ..., providers: ..., bootstrap: ...})<br>class MyModule {}</code></td>
|
||||||
<td><p>Defines a module that contains components, directives, pipes, and providers.</p>
|
<td><p>Defines a module that contains components, directives, pipes, and providers.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>declarations:</b> [MyRedComponent, MyBlueComponent, MyDatePipe]</code></td>
|
<td><code><b>declarations:</b> [MyRedComponent, MyBlueComponent, MyDatePipe]</code></td>
|
||||||
<td><p>List of components, directives, and pipes that belong to this module.</p>
|
<td><p>List of components, directives, and pipes that belong to this module.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>imports:</b> [BrowserModule, SomeOtherModule]</code></td>
|
<td><code><b>imports:</b> [BrowserModule, SomeOtherModule]</code></td>
|
||||||
<td><p>List of modules to import into this module. Everything from the imported modules
|
<td><p>List of modules to import into this module. Everything from the imported modules
|
||||||
is available to <code>declarations</code> of this module.</p>
|
is available to <code>declarations</code> of this module.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>exports:</b> [MyRedComponent, MyDatePipe]</code></td>
|
<td><code><b>exports:</b> [MyRedComponent, MyDatePipe]</code></td>
|
||||||
<td><p>List of components, directives, and pipes visible to modules that import this module.</p>
|
<td><p>List of components, directives, and pipes visible to modules that import this module.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>providers:</b> [MyService, { provide: ... }]</code></td>
|
<td><code><b>providers:</b> [MyService, { provide: ... }]</code></td>
|
||||||
<td><p>List of dependency injection providers visible both to the contents of this module and to importers of this module.</p>
|
<td><p>List of dependency injection providers visible both to the contents of this module and to importers of this module.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>bootstrap:</b> [MyAppComponent]</code></td>
|
<td><code><b>bootstrap:</b> [MyAppComponent]</code></td>
|
||||||
<td><p>List of components to bootstrap when this module is bootstrapped.</p>
|
<td><p>List of components to bootstrap when this module is bootstrapped.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -56,61 +56,61 @@ is available to <code>declarations</code> of this module.</p>
|
|||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code><input <b>[value]</b>="firstName"></code></td>
|
<td><code><input <b>[value]</b>="firstName"></code></td>
|
||||||
<td><p>Binds property <code>value</code> to the result of expression <code>firstName</code>.</p>
|
<td><p>Binds property <code>value</code> to the result of expression <code>firstName</code>.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><div <b>[attr.role]</b>="myAriaRole"></code></td>
|
<td><code><div <b>[attr.role]</b>="myAriaRole"></code></td>
|
||||||
<td><p>Binds attribute <code>role</code> to the result of expression <code>myAriaRole</code>.</p>
|
<td><p>Binds attribute <code>role</code> to the result of expression <code>myAriaRole</code>.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><div <b>[class.extra-sparkle]</b>="isDelightful"></code></td>
|
<td><code><div <b>[class.extra-sparkle]</b>="isDelightful"></code></td>
|
||||||
<td><p>Binds the presence of the CSS class <code>extra-sparkle</code> on the element to the truthiness of the expression <code>isDelightful</code>.</p>
|
<td><p>Binds the presence of the CSS class <code>extra-sparkle</code> on the element to the truthiness of the expression <code>isDelightful</code>.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><div <b>[style.width.px]</b>="mySize"></code></td>
|
<td><code><div <b>[style.width.px]</b>="mySize"></code></td>
|
||||||
<td><p>Binds style property <code>width</code> to the result of expression <code>mySize</code> in pixels. Units are optional.</p>
|
<td><p>Binds style property <code>width</code> to the result of expression <code>mySize</code> in pixels. Units are optional.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><button <b>(click)</b>="readRainbow($event)"></code></td>
|
<td><code><button <b>(click)</b>="readRainbow($event)"></code></td>
|
||||||
<td><p>Calls method <code>readRainbow</code> when a click event is triggered on this button element (or its children) and passes in the event object.</p>
|
<td><p>Calls method <code>readRainbow</code> when a click event is triggered on this button element (or its children) and passes in the event object.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><div title="Hello <b>{{ponyName}}</b>"></code></td>
|
<td><code><div title="Hello <b>{{ponyName}}</b>"></code></td>
|
||||||
<td><p>Binds a property to an interpolated string, for example, "Hello Seabiscuit". Equivalent to:
|
<td><p>Binds a property to an interpolated string, for example, "Hello Seabiscuit". Equivalent to:
|
||||||
<code><div [title]="'Hello ' + ponyName"></code></p>
|
<code><div [title]="'Hello ' + ponyName"></code></p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><p>Hello <b>{{ponyName}}</b></p></code></td>
|
<td><code><p>Hello <b>{{ponyName}}</b></p></code></td>
|
||||||
<td><p>Binds text content to an interpolated string, for example, "Hello Seabiscuit".</p>
|
<td><p>Binds text content to an interpolated string, for example, "Hello Seabiscuit".</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><my-cmp <b>[(title)]</b>="name"></code></td>
|
<td><code><my-cmp <b>[(title)]</b>="name"></code></td>
|
||||||
<td><p>Sets up two-way data binding. Equivalent to: <code><my-cmp [title]="name" (titleChange)="name=$event"></code></p>
|
<td><p>Sets up two-way data binding. Equivalent to: <code><my-cmp [title]="name" (titleChange)="name=$event"></code></p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><video <b>#movieplayer</b> ...><br> <button <b>(click)</b>="movieplayer.play()"><br></video></code></td>
|
<td><code><video <b>#movieplayer</b> ...><br> <button <b>(click)</b>="movieplayer.play()"><br></video></code></td>
|
||||||
<td><p>Creates a local variable <code>movieplayer</code> that provides access to the <code>video</code> element instance in data-binding and event-binding expressions in the current template.</p>
|
<td><p>Creates a local variable <code>movieplayer</code> that provides access to the <code>video</code> element instance in data-binding and event-binding expressions in the current template.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><p <b>*myUnless</b>="myExpression">...</p></code></td>
|
<td><code><p <b>*myUnless</b>="myExpression">...</p></code></td>
|
||||||
<td><p>The <code>*</code> symbol turns the current element into an embedded template. Equivalent to:
|
<td><p>The <code>*</code> symbol turns the current element into an embedded template. Equivalent to:
|
||||||
<code><ng-template [myUnless]="myExpression"><p>...</p></ng-template></code></p>
|
<code><ng-template [myUnless]="myExpression"><p>...</p></ng-template></code></p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><p>Card No.: <b>{{cardNumber | myCardNumberFormatter}}</b></p></code></td>
|
<td><code><p>Card No.: <b>{{cardNumber | myCardNumberFormatter}}</b></p></code></td>
|
||||||
<td><p>Transforms the current value of expression <code>cardNumber</code> via the pipe called <code>myCardNumberFormatter</code>.</p>
|
<td><p>Transforms the current value of expression <code>cardNumber</code> via the pipe called <code>myCardNumberFormatter</code>.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><p>Employer: <b>{{employer?.companyName}}</b></p></code></td>
|
<td><code><p>Employer: <b>{{employer?.companyName}}</b></p></code></td>
|
||||||
<td><p>The safe navigation operator (<code>?</code>) means that the <code>employer</code> field is optional and if <code>undefined</code>, the rest of the expression should be ignored.</p>
|
<td><p>The safe navigation operator (<code>?</code>) means that the <code>employer</code> field is optional and if <code>undefined</code>, the rest of the expression should be ignored.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><<b>svg:</b>rect x="0" y="0" width="100" height="100"/></code></td>
|
<td><code><<b>svg:</b>rect x="0" y="0" width="100" height="100"/></code></td>
|
||||||
<td><p>An SVG snippet template needs an <code>svg:</code> prefix on its root element to disambiguate the SVG element from an HTML component.</p>
|
<td><p>An SVG snippet template needs an <code>svg:</code> prefix on its root element to disambiguate the SVG element from an HTML component.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><<b>svg</b>><br> <rect x="0" y="0" width="100" height="100"/><br></<b>svg</b>></code></td>
|
<td><code><<b>svg</b>><br> <rect x="0" y="0" width="100" height="100"/><br></<b>svg</b>></code></td>
|
||||||
<td><p>An <code><svg></code> root element is detected as an SVG element automatically, without the prefix.</p>
|
<td><p>An <code><svg></code> root element is detected as an SVG element automatically, without the prefix.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -124,19 +124,19 @@ is available to <code>declarations</code> of this module.</p>
|
|||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code><section <b>*ngIf</b>="showSection"></code></td>
|
<td><code><section <b>*ngIf</b>="showSection"></code></td>
|
||||||
<td><p>Removes or recreates a portion of the DOM tree based on the <code>showSection</code> expression.</p>
|
<td><p>Removes or recreates a portion of the DOM tree based on the <code>showSection</code> expression.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><li <b>*ngFor</b>="let item of list"></code></td>
|
<td><code><li <b>*ngFor</b>="let item of list"></code></td>
|
||||||
<td><p>Turns the li element and its contents into a template, and uses that to instantiate a view for each item in list.</p>
|
<td><p>Turns the li element and its contents into a template, and uses that to instantiate a view for each item in list.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><div <b>[ngSwitch]</b>="conditionExpression"><br> <ng-template <b>[<b>ngSwitchCase</b>]</b>="case1Exp">...</ng-template><br> <ng-template <b>ngSwitchCase</b>="case2LiteralString">...</ng-template><br> <ng-template <b>ngSwitchDefault</b>>...</ng-template><br></div></code></td>
|
<td><code><div <b>[ngSwitch]</b>="conditionExpression"><br> <ng-template <b>[<b>ngSwitchCase</b>]</b>="case1Exp">...</ng-template><br> <ng-template <b>ngSwitchCase</b>="case2LiteralString">...</ng-template><br> <ng-template <b>ngSwitchDefault</b>>...</ng-template><br></div></code></td>
|
||||||
<td><p>Conditionally swaps the contents of the div by selecting one of the embedded templates based on the current value of <code>conditionExpression</code>.</p>
|
<td><p>Conditionally swaps the contents of the div by selecting one of the embedded templates based on the current value of <code>conditionExpression</code>.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><div <b>[ngClass]</b>="{'active': isActive, 'disabled': isDisabled}"></code></td>
|
<td><code><div <b>[ngClass]</b>="{'active': isActive, 'disabled': isDisabled}"></code></td>
|
||||||
<td><p>Binds the presence of CSS classes on the element to the truthiness of the associated map values. The right-hand expression should return {class-name: true/false} map.</p>
|
<td><p>Binds the presence of CSS classes on the element to the truthiness of the associated map values. The right-hand expression should return {class-name: true/false} map.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -150,7 +150,7 @@ is available to <code>declarations</code> of this module.</p>
|
|||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code><input <b>[(ngModel)]</b>="userName"></code></td>
|
<td><code><input <b>[(ngModel)]</b>="userName"></code></td>
|
||||||
<td><p>Provides two-way data-binding, parsing, and validation for form controls.</p>
|
<td><p>Provides two-way data-binding, parsing, and validation for form controls.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -164,19 +164,19 @@ is available to <code>declarations</code> of this module.</p>
|
|||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code><b>@Component({...})</b><br>class MyComponent() {}</code></td>
|
<td><code><b>@Component({...})</b><br>class MyComponent() {}</code></td>
|
||||||
<td><p>Declares that a class is a component and provides metadata about the component.</p>
|
<td><p>Declares that a class is a component and provides metadata about the component.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>@Directive({...})</b><br>class MyDirective() {}</code></td>
|
<td><code><b>@Directive({...})</b><br>class MyDirective() {}</code></td>
|
||||||
<td><p>Declares that a class is a directive and provides metadata about the directive.</p>
|
<td><p>Declares that a class is a directive and provides metadata about the directive.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>@Pipe({...})</b><br>class MyPipe() {}</code></td>
|
<td><code><b>@Pipe({...})</b><br>class MyPipe() {}</code></td>
|
||||||
<td><p>Declares that a class is a pipe and provides metadata about the pipe.</p>
|
<td><p>Declares that a class is a pipe and provides metadata about the pipe.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>@Injectable()</b><br>class MyService() {}</code></td>
|
<td><code><b>@Injectable()</b><br>class MyService() {}</code></td>
|
||||||
<td><p>Declares that a class has dependencies that should be injected into the constructor when the dependency injector is creating an instance of this class.
|
<td><p>Declares that a class has dependencies that should be injected into the constructor when the dependency injector is creating an instance of this class.
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
@ -191,13 +191,13 @@ is available to <code>declarations</code> of this module.</p>
|
|||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code><b>selector:</b> '.cool-button:not(a)'</code></td>
|
<td><code><b>selector:</b> '.cool-button:not(a)'</code></td>
|
||||||
<td><p>Specifies a CSS selector that identifies this directive within a template. Supported selectors include <code>element</code>,
|
<td><p>Specifies a CSS selector that identifies this directive within a template. Supported selectors include <code>element</code>,
|
||||||
<code>[attribute]</code>, <code>.class</code>, and <code>:not()</code>.</p>
|
<code>[attribute]</code>, <code>.class</code>, and <code>:not()</code>.</p>
|
||||||
<p>Does not support parent-child relationship selectors.</p>
|
<p>Does not support parent-child relationship selectors.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>providers:</b> [MyService, { provide: ... }]</code></td>
|
<td><code><b>providers:</b> [MyService, { provide: ... }]</code></td>
|
||||||
<td><p>List of dependency injection providers for this directive and its children.</p>
|
<td><p>List of dependency injection providers for this directive and its children.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -212,19 +212,19 @@ so the <code>@Directive</code> configuration applies to components as well</p>
|
|||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code><b>moduleId:</b> module.id</code></td>
|
<td><code><b>moduleId:</b> module.id</code></td>
|
||||||
<td><p>If set, the <code>templateUrl</code> and <code>styleUrl</code> are resolved relative to the component.</p>
|
<td><p>If set, the <code>templateUrl</code> and <code>styleUrl</code> are resolved relative to the component.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>viewProviders:</b> [MyService, { provide: ... }]</code></td>
|
<td><code><b>viewProviders:</b> [MyService, { provide: ... }]</code></td>
|
||||||
<td><p>List of dependency injection providers scoped to this component's view.</p>
|
<td><p>List of dependency injection providers scoped to this component's view.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>template:</b> 'Hello {{name}}'<br><b>templateUrl:</b> 'my-component.html'</code></td>
|
<td><code><b>template:</b> 'Hello {{name}}'<br><b>templateUrl:</b> 'my-component.html'</code></td>
|
||||||
<td><p>Inline template or external template URL of the component's view.</p>
|
<td><p>Inline template or external template URL of the component's view.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>styles:</b> ['.primary {color: red}']<br><b>styleUrls:</b> ['my-component.css']</code></td>
|
<td><code><b>styles:</b> ['.primary {color: red}']<br><b>styleUrls:</b> ['my-component.css']</code></td>
|
||||||
<td><p>List of inline CSS styles or external stylesheet URLs for styling the component’s view.</p>
|
<td><p>List of inline CSS styles or external stylesheet URLs for styling the component’s view.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -238,36 +238,36 @@ so the <code>@Directive</code> configuration applies to components as well</p>
|
|||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code><b>@Input()</b> myProperty;</code></td>
|
<td><code><b>@Input()</b> myProperty;</code></td>
|
||||||
<td><p>Declares an input property that you can update via property binding (example:
|
<td><p>Declares an input property that you can update via property binding (example:
|
||||||
<code><my-cmp [myProperty]="someExpression"></code>).</p>
|
<code><my-cmp [myProperty]="someExpression"></code>).</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>@Output()</b> myEvent = new EventEmitter();</code></td>
|
<td><code><b>@Output()</b> myEvent = new EventEmitter();</code></td>
|
||||||
<td><p>Declares an output property that fires events that you can subscribe to with an event binding (example: <code><my-cmp (myEvent)="doSomething()"></code>).</p>
|
<td><p>Declares an output property that fires events that you can subscribe to with an event binding (example: <code><my-cmp (myEvent)="doSomething()"></code>).</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>@HostBinding('class.valid')</b> isValid;</code></td>
|
<td><code><b>@HostBinding('class.valid')</b> isValid;</code></td>
|
||||||
<td><p>Binds a host element property (here, the CSS class <code>valid</code>) to a directive/component property (<code>isValid</code>).</p>
|
<td><p>Binds a host element property (here, the CSS class <code>valid</code>) to a directive/component property (<code>isValid</code>).</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>@HostListener('click', ['$event'])</b> onClick(e) {...}</code></td>
|
<td><code><b>@HostListener('click', ['$event'])</b> onClick(e) {...}</code></td>
|
||||||
<td><p>Subscribes to a host element event (<code>click</code>) with a directive/component method (<code>onClick</code>), optionally passing an argument (<code>$event</code>).</p>
|
<td><p>Subscribes to a host element event (<code>click</code>) with a directive/component method (<code>onClick</code>), optionally passing an argument (<code>$event</code>).</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>@ContentChild(myPredicate)</b> myChildComponent;</code></td>
|
<td><code><b>@ContentChild(myPredicate)</b> myChildComponent;</code></td>
|
||||||
<td><p>Binds the first result of the component content query (<code>myPredicate</code>) to a property (<code>myChildComponent</code>) of the class.</p>
|
<td><p>Binds the first result of the component content query (<code>myPredicate</code>) to a property (<code>myChildComponent</code>) of the class.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>@ContentChildren(myPredicate)</b> myChildComponents;</code></td>
|
<td><code><b>@ContentChildren(myPredicate)</b> myChildComponents;</code></td>
|
||||||
<td><p>Binds the results of the component content query (<code>myPredicate</code>) to a property (<code>myChildComponents</code>) of the class.</p>
|
<td><p>Binds the results of the component content query (<code>myPredicate</code>) to a property (<code>myChildComponents</code>) of the class.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>@ViewChild(myPredicate)</b> myChildComponent;</code></td>
|
<td><code><b>@ViewChild(myPredicate)</b> myChildComponent;</code></td>
|
||||||
<td><p>Binds the first result of the component view query (<code>myPredicate</code>) to a property (<code>myChildComponent</code>) of the class. Not available for directives.</p>
|
<td><p>Binds the first result of the component view query (<code>myPredicate</code>) to a property (<code>myChildComponent</code>) of the class. Not available for directives.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>@ViewChildren(myPredicate)</b> myChildComponents;</code></td>
|
<td><code><b>@ViewChildren(myPredicate)</b> myChildComponents;</code></td>
|
||||||
<td><p>Binds the results of the component view query (<code>myPredicate</code>) to a property (<code>myChildComponents</code>) of the class. Not available for directives.</p>
|
<td><p>Binds the results of the component view query (<code>myPredicate</code>) to a property (<code>myChildComponents</code>) of the class. Not available for directives.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -281,39 +281,39 @@ so the <code>@Directive</code> configuration applies to components as well</p>
|
|||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code><b>constructor(myService: MyService, ...)</b> { ... }</code></td>
|
<td><code><b>constructor(myService: MyService, ...)</b> { ... }</code></td>
|
||||||
<td><p>Called before any other lifecycle hook. Use it to inject dependencies, but avoid any serious work here.</p>
|
<td><p>Called before any other lifecycle hook. Use it to inject dependencies, but avoid any serious work here.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>ngOnChanges(changeRecord)</b> { ... }</code></td>
|
<td><code><b>ngOnChanges(changeRecord)</b> { ... }</code></td>
|
||||||
<td><p>Called after every change to input properties and before processing content or child views.</p>
|
<td><p>Called after every change to input properties and before processing content or child views.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>ngOnInit()</b> { ... }</code></td>
|
<td><code><b>ngOnInit()</b> { ... }</code></td>
|
||||||
<td><p>Called after the constructor, initializing input properties, and the first call to <code>ngOnChanges</code>.</p>
|
<td><p>Called after the constructor, initializing input properties, and the first call to <code>ngOnChanges</code>.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>ngDoCheck()</b> { ... }</code></td>
|
<td><code><b>ngDoCheck()</b> { ... }</code></td>
|
||||||
<td><p>Called every time that the input properties of a component or a directive are checked. Use it to extend change detection by performing a custom check.</p>
|
<td><p>Called every time that the input properties of a component or a directive are checked. Use it to extend change detection by performing a custom check.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>ngAfterContentInit()</b> { ... }</code></td>
|
<td><code><b>ngAfterContentInit()</b> { ... }</code></td>
|
||||||
<td><p>Called after <code>ngOnInit</code> when the component's or directive's content has been initialized.</p>
|
<td><p>Called after <code>ngOnInit</code> when the component's or directive's content has been initialized.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>ngAfterContentChecked()</b> { ... }</code></td>
|
<td><code><b>ngAfterContentChecked()</b> { ... }</code></td>
|
||||||
<td><p>Called after every check of the component's or directive's content.</p>
|
<td><p>Called after every check of the component's or directive's content.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>ngAfterViewInit()</b> { ... }</code></td>
|
<td><code><b>ngAfterViewInit()</b> { ... }</code></td>
|
||||||
<td><p>Called after <code>ngAfterContentInit</code> when the component's view has been initialized. Applies to components only.</p>
|
<td><p>Called after <code>ngAfterContentInit</code> when the component's view has been initialized. Applies to components only.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>ngAfterViewChecked()</b> { ... }</code></td>
|
<td><code><b>ngAfterViewChecked()</b> { ... }</code></td>
|
||||||
<td><p>Called after every check of the component's view. Applies to components only.</p>
|
<td><p>Called after every check of the component's view. Applies to components only.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><b>ngOnDestroy()</b> { ... }</code></td>
|
<td><code><b>ngOnDestroy()</b> { ... }</code></td>
|
||||||
<td><p>Called once, before the instance is destroyed.</p>
|
<td><p>Called once, before the instance is destroyed.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -325,15 +325,15 @@ so the <code>@Directive</code> configuration applies to components as well</p>
|
|||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>{ <b>provide</b>: MyService, <b>useClass</b>: MyMockService }</code></td>
|
<td><code>{ <b>provide</b>: MyService, <b>useClass</b>: MyMockService }</code></td>
|
||||||
<td><p>Sets or overrides the provider for <code>MyService</code> to the <code>MyMockService</code> class.</p>
|
<td><p>Sets or overrides the provider for <code>MyService</code> to the <code>MyMockService</code> class.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code>{ <b>provide</b>: MyService, <b>useFactory</b>: myFactory }</code></td>
|
<td><code>{ <b>provide</b>: MyService, <b>useFactory</b>: myFactory }</code></td>
|
||||||
<td><p>Sets or overrides the provider for <code>MyService</code> to the <code>myFactory</code> factory function.</p>
|
<td><p>Sets or overrides the provider for <code>MyService</code> to the <code>myFactory</code> factory function.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code>{ <b>provide</b>: MyValue, <b>useValue</b>: 41 }</code></td>
|
<td><code>{ <b>provide</b>: MyValue, <b>useValue</b>: 41 }</code></td>
|
||||||
<td><p>Sets or overrides the provider for <code>MyValue</code> to the value <code>41</code>.</p>
|
<td><p>Sets or overrides the provider for <code>MyValue</code> to the value <code>41</code>.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -347,39 +347,39 @@ so the <code>@Directive</code> configuration applies to components as well</p>
|
|||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>const routes: <b>Routes</b> = [<br> { path: '', component: HomeComponent },<br> { path: 'path/:routeParam', component: MyComponent },<br> { path: 'staticPath', component: ... },<br> { path: '**', component: ... },<br> { path: 'oldPath', redirectTo: '/staticPath' },<br> { path: ..., component: ..., data: { message: 'Custom' } }<br>]);<br><br>const routing = RouterModule.forRoot(routes);</code></td>
|
<td><code>const routes: <b>Routes</b> = [<br> { path: '', component: HomeComponent },<br> { path: 'path/:routeParam', component: MyComponent },<br> { path: 'staticPath', component: ... },<br> { path: '**', component: ... },<br> { path: 'oldPath', redirectTo: '/staticPath' },<br> { path: ..., component: ..., data: { message: 'Custom' } }<br>]);<br><br>const routing = RouterModule.forRoot(routes);</code></td>
|
||||||
<td><p>Configures routes for the application. Supports static, parameterized, redirect, and wildcard routes. Also supports custom route data and resolve.</p>
|
<td><p>Configures routes for the application. Supports static, parameterized, redirect, and wildcard routes. Also supports custom route data and resolve.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><br><<b>router-outlet</b>></<b>router-outlet</b>><br><<b>router-outlet</b> name="aux"></<b>router-outlet</b>><br></code></td>
|
<td><code><br><<b>router-outlet</b>></<b>router-outlet</b>><br><<b>router-outlet</b> name="aux"></<b>router-outlet</b>><br></code></td>
|
||||||
<td><p>Marks the location to load the component of the active route.</p>
|
<td><p>Marks the location to load the component of the active route.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><br><a routerLink="/path"><br><a <b>[routerLink]</b>="[ '/path', routeParam ]"><br><a <b>[routerLink]</b>="[ '/path', { matrixParam: 'value' } ]"><br><a <b>[routerLink]</b>="[ '/path' ]" [queryParams]="{ page: 1 }"><br><a <b>[routerLink]</b>="[ '/path' ]" fragment="anchor"><br></code></td>
|
<td><code><br><a routerLink="/path"><br><a <b>[routerLink]</b>="[ '/path', routeParam ]"><br><a <b>[routerLink]</b>="[ '/path', { matrixParam: 'value' } ]"><br><a <b>[routerLink]</b>="[ '/path' ]" [queryParams]="{ page: 1 }"><br><a <b>[routerLink]</b>="[ '/path' ]" fragment="anchor"><br></code></td>
|
||||||
<td><p>Creates a link to a different view based on a route instruction consisting of a route path, required and optional parameters, query parameters, and a fragment. To navigate to a root route, use the <code>/</code> prefix; for a child route, use the <code>./</code>prefix; for a sibling or parent, use the <code>../</code> prefix.</p>
|
<td><p>Creates a link to a different view based on a route instruction consisting of a route path, required and optional parameters, query parameters, and a fragment. To navigate to a root route, use the <code>/</code> prefix; for a child route, use the <code>./</code>prefix; for a sibling or parent, use the <code>../</code> prefix.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code><a [routerLink]="[ '/path' ]" routerLinkActive="active"></code></td>
|
<td><code><a [routerLink]="[ '/path' ]" routerLinkActive="active"></code></td>
|
||||||
<td><p>The provided classes are added to the element when the <code>routerLink</code> becomes the current active route.</p>
|
<td><p>The provided classes are added to the element when the <code>routerLink</code> becomes the current active route.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code>class <b>CanActivate</b>Guard implements <b>CanActivate</b> {<br> canActivate(<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable<boolean>|Promise<boolean>|boolean { ... }<br>}<br><br>{ path: ..., canActivate: [<b>CanActivate</b>Guard] }</code></td>
|
<td><code>class <b>CanActivate</b>Guard implements <b>CanActivate</b> {<br> canActivate(<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable<boolean>|Promise<boolean>|boolean { ... }<br>}<br><br>{ path: ..., canActivate: [<b>CanActivate</b>Guard] }</code></td>
|
||||||
<td><p>An interface for defining a class that the router should call first to determine if it should activate this component. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
|
<td><p>An interface for defining a class that the router should call first to determine if it should activate this component. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code>class <b>CanDeactivate</b>Guard implements <b>CanDeactivate</b><T> {<br> canDeactivate(<br> component: T,<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable<boolean>|Promise<boolean>|boolean { ... }<br>}<br><br>{ path: ..., canDeactivate: [<b>CanDeactivate</b>Guard] }</code></td>
|
<td><code>class <b>CanDeactivate</b>Guard implements <b>CanDeactivate</b><T> {<br> canDeactivate(<br> component: T,<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable<boolean>|Promise<boolean>|boolean { ... }<br>}<br><br>{ path: ..., canDeactivate: [<b>CanDeactivate</b>Guard] }</code></td>
|
||||||
<td><p>An interface for defining a class that the router should call first to determine if it should deactivate this component after a navigation. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
|
<td><p>An interface for defining a class that the router should call first to determine if it should deactivate this component after a navigation. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code>class <b>CanActivateChild</b>Guard implements <b>CanActivateChild</b> {<br> canActivateChild(<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable<boolean>|Promise<boolean>|boolean { ... }<br>}<br><br>{ path: ..., canActivateChild: [CanActivateGuard],<br> children: ... }</code></td>
|
<td><code>class <b>CanActivateChild</b>Guard implements <b>CanActivateChild</b> {<br> canActivateChild(<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable<boolean>|Promise<boolean>|boolean { ... }<br>}<br><br>{ path: ..., canActivateChild: [CanActivateGuard],<br> children: ... }</code></td>
|
||||||
<td><p>An interface for defining a class that the router should call first to determine if it should activate the child route. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
|
<td><p>An interface for defining a class that the router should call first to determine if it should activate the child route. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code>class <b>Resolve</b>Guard implements <b>Resolve</b><T> {<br> resolve(<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable<any>|Promise<any>|any { ... }<br>}<br><br>{ path: ..., resolve: [<b>Resolve</b>Guard] }</code></td>
|
<td><code>class <b>Resolve</b>Guard implements <b>Resolve</b><T> {<br> resolve(<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable<any>|Promise<any>|any { ... }<br>}<br><br>{ path: ..., resolve: [<b>Resolve</b>Guard] }</code></td>
|
||||||
<td><p>An interface for defining a class that the router should call first to resolve route data before rendering the route. Should return a value or an Observable/Promise that resolves to a value.</p>
|
<td><p>An interface for defining a class that the router should call first to resolve route data before rendering the route. Should return a value or an Observable/Promise that resolves to a value.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><code>class <b>CanLoad</b>Guard implements <b>CanLoad</b> {<br> canLoad(<br> route: Route<br> ): Observable<boolean>|Promise<boolean>|boolean { ... }<br>}<br><br>{ path: ..., canLoad: [<b>CanLoad</b>Guard], loadChildren: ... }</code></td>
|
<td><code>class <b>CanLoad</b>Guard implements <b>CanLoad</b> {<br> canLoad(<br> route: Route<br> ): Observable<boolean>|Promise<boolean>|boolean { ... }<br>}<br><br>{ path: ..., canLoad: [<b>CanLoad</b>Guard], loadChildren: ... }</code></td>
|
||||||
<td><p>An interface for defining a class that the router should call first to check if the lazy loaded module should be loaded. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
|
<td><p>An interface for defining a class that the router should call first to check if the lazy loaded module should be loaded. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -29,7 +29,7 @@ import {HttpClientModule} from '@angular/common/http';
|
|||||||
export class MyAppModule {}
|
export class MyAppModule {}
|
||||||
```
|
```
|
||||||
|
|
||||||
Once you import `HttpClientModule` into your app module, you can inject `HttpClient`
|
Once you import `HttpClientModule` into your app module, you can inject `HttpClient`
|
||||||
into your components and services.
|
into your components and services.
|
||||||
|
|
||||||
## Making a request for JSON data
|
## Making a request for JSON data
|
||||||
@ -50,10 +50,13 @@ The `get()` method on `HttpClient` makes accessing this data straightforward.
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@Component(...)
|
@Component(...)
|
||||||
export class MyComponent implements NgOnInit {
|
export class MyComponent implements OnInit {
|
||||||
|
|
||||||
|
results: string[];
|
||||||
|
|
||||||
// Inject HttpClient into your component or service.
|
// Inject HttpClient into your component or service.
|
||||||
constructor(private http: HttpClient) {}
|
constructor(private http: HttpClient) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
// Make the HTTP request:
|
// Make the HTTP request:
|
||||||
this.http.get('/api/items').subscribe(data => {
|
this.http.get('/api/items').subscribe(data => {
|
||||||
@ -69,7 +72,7 @@ export class MyComponent implements NgOnInit {
|
|||||||
|
|
||||||
In the above example, the `data['results']` field access stands out because you use bracket notation to access the results field. If you tried to write `data.results`, TypeScript would correctly complain that the `Object` coming back from HTTP does not have a `results` property. That's because while `HttpClient` parsed the JSON response into an `Object`, it doesn't know what shape that object is.
|
In the above example, the `data['results']` field access stands out because you use bracket notation to access the results field. If you tried to write `data.results`, TypeScript would correctly complain that the `Object` coming back from HTTP does not have a `results` property. That's because while `HttpClient` parsed the JSON response into an `Object`, it doesn't know what shape that object is.
|
||||||
|
|
||||||
You can, however, tell `HttpClient` what type the response will be, which is recommended.
|
You can, however, tell `HttpClient` what type the response will be, which is recommended.
|
||||||
To do so, first you define an interface with the correct shape:
|
To do so, first you define an interface with the correct shape:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@ -160,7 +163,7 @@ RxJS has a useful operator called `.retry()`, which automatically resubscribes t
|
|||||||
|
|
||||||
First, import it:
|
First, import it:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import 'rxjs/add/operator/retry';
|
import 'rxjs/add/operator/retry';
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -194,7 +197,7 @@ In addition to fetching data from the server, `HttpClient` supports mutating req
|
|||||||
|
|
||||||
### Making a POST request
|
### Making a POST request
|
||||||
|
|
||||||
One common operation is to POST data to a server; for example when submitting a form. The code for
|
One common operation is to POST data to a server; for example when submitting a form. The code for
|
||||||
sending a POST request is very similar to the code for GET:
|
sending a POST request is very similar to the code for GET:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@ -258,22 +261,22 @@ The above sections detail how to use the basic HTTP functionality in `@angular/c
|
|||||||
|
|
||||||
### Intercepting all requests or responses
|
### Intercepting all requests or responses
|
||||||
|
|
||||||
A major feature of `@angular/common/http` is _interception_, the ability to declare interceptors which sit in between your application and the backend. When your application makes a request, interceptors transform it
|
A major feature of `@angular/common/http` is _interception_, the ability to declare interceptors which sit in between your application and the backend. When your application makes a request, interceptors transform it
|
||||||
before sending it to the server, and the interceptors can transform the response on its way back before your application sees it. This is useful for everything from authentication to logging.
|
before sending it to the server, and the interceptors can transform the response on its way back before your application sees it. This is useful for everything from authentication to logging.
|
||||||
|
|
||||||
#### Writing an interceptor
|
#### Writing an interceptor
|
||||||
|
|
||||||
To implement an interceptor, you declare a class that implements `HttpInterceptor`, which
|
To implement an interceptor, you declare a class that implements `HttpInterceptor`, which
|
||||||
has a single `intercept()` method. Here is a simple interceptor which does nothing but forward the request through without altering it:
|
has a single `intercept()` method. Here is a simple interceptor which does nothing but forward the request through without altering it:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest) from '@angular/common/http';
|
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NoopInterceptor implements HttpInterceptor {
|
export class NoopInterceptor implements HttpInterceptor {
|
||||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
return next.handle(Req);
|
return next.handle(req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -316,7 +319,7 @@ An interceptor must pass through all events that it does not understand or inten
|
|||||||
|
|
||||||
##### Ordering
|
##### Ordering
|
||||||
|
|
||||||
When you provide multiple interceptors in an application, Angular applies them in the order that you
|
When you provide multiple interceptors in an application, Angular applies them in the order that you
|
||||||
provided them.
|
provided them.
|
||||||
|
|
||||||
##### Immutability
|
##### Immutability
|
||||||
@ -332,10 +335,10 @@ If you have a need to mutate the request body, you need to copy the request body
|
|||||||
Since requests are immutable, they cannot be modified directly. To mutate them, use `clone()`:
|
Since requests are immutable, they cannot be modified directly. To mutate them, use `clone()`:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpError<any>> {
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
// This is a duplicate. It is exactly the same as the original.
|
// This is a duplicate. It is exactly the same as the original.
|
||||||
const dupReq = req.clone();
|
const dupReq = req.clone();
|
||||||
|
|
||||||
// Change the URL and replace 'http://' with 'https://'
|
// Change the URL and replace 'http://' with 'https://'
|
||||||
const secureReq = req.clone({url: req.url.replace('http://', 'https://')});
|
const secureReq = req.clone({url: req.url.replace('http://', 'https://')});
|
||||||
}
|
}
|
||||||
@ -349,15 +352,15 @@ A common use of interceptors is to set default headers on outgoing responses. Fo
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest) from '@angular/common/http';
|
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthInterceptor implements HttpInterceptor {
|
export class AuthInterceptor implements HttpInterceptor {
|
||||||
constructor(private auth: AuthService) {}
|
constructor(private auth: AuthService) {}
|
||||||
|
|
||||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
// Get the auth header from the service.
|
// Get the auth header from the service.
|
||||||
const authHeader: this.auth.getAuthorizationHeader();
|
const authHeader = this.auth.getAuthorizationHeader();
|
||||||
// Clone the request to add the new header.
|
// Clone the request to add the new header.
|
||||||
const authReq = req.clone({headers: req.headers.set('Authorization', authHeader)});
|
const authReq = req.clone({headers: req.headers.set('Authorization', authHeader)});
|
||||||
// Pass on the cloned request instead of the original request.
|
// Pass on the cloned request instead of the original request.
|
||||||
@ -387,15 +390,15 @@ import 'rxjs/add/operator/do';
|
|||||||
|
|
||||||
export class TimingInterceptor implements HttpInterceptor {
|
export class TimingInterceptor implements HttpInterceptor {
|
||||||
constructor(private auth: AuthService) {}
|
constructor(private auth: AuthService) {}
|
||||||
|
|
||||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
const elapsed = Date.now();
|
const started = Date.now();
|
||||||
return next
|
return next
|
||||||
.handle(req)
|
.handle(req)
|
||||||
.do(event => {
|
.do(event => {
|
||||||
if (event instanceof HttpResponse) {
|
if (event instanceof HttpResponse) {
|
||||||
const time = Date.now() - started;
|
const elapsed = Date.now() - started;
|
||||||
console.log(`Request for ${req.urlWithParams} took ${elapsed} ms.`);
|
console.log(`Request for ${req.urlWithParams} took ${elapsed} ms.`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -413,7 +416,7 @@ abstract class HttpCache {
|
|||||||
* Returns a cached response, if any, or null if not present.
|
* Returns a cached response, if any, or null if not present.
|
||||||
*/
|
*/
|
||||||
abstract get(req: HttpRequest<any>): HttpResponse<any>|null;
|
abstract get(req: HttpRequest<any>): HttpResponse<any>|null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds or updates the response in the cache.
|
* Adds or updates the response in the cache.
|
||||||
*/
|
*/
|
||||||
@ -427,14 +430,14 @@ An interceptor can apply this cache to outgoing requests.
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class CachingInterceptor implements HttpInterceptor {
|
export class CachingInterceptor implements HttpInterceptor {
|
||||||
constructor(private cache: HttpCache) {}
|
constructor(private cache: HttpCache) {}
|
||||||
|
|
||||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
// Before doing anything, it's important to only cache GET requests.
|
// Before doing anything, it's important to only cache GET requests.
|
||||||
// Skip this interceptor if the request method isn't GET.
|
// Skip this interceptor if the request method isn't GET.
|
||||||
if (req.method !== 'GET') {
|
if (req.method !== 'GET') {
|
||||||
return next.handle(req);
|
return next.handle(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, check the cache to see if this request exists.
|
// First, check the cache to see if this request exists.
|
||||||
const cachedResponse = this.cache.get(req);
|
const cachedResponse = this.cache.get(req);
|
||||||
if (cachedResponse) {
|
if (cachedResponse) {
|
||||||
@ -442,7 +445,7 @@ export class CachingInterceptor implements HttpInterceptor {
|
|||||||
// the request to the next handler.
|
// the request to the next handler.
|
||||||
return Observable.of(cachedResponse);
|
return Observable.of(cachedResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No cached response exists. Go to the network, and cache
|
// No cached response exists. Go to the network, and cache
|
||||||
// the response when it arrives.
|
// the response when it arrives.
|
||||||
return next.handle(req).do(event => {
|
return next.handle(req).do(event => {
|
||||||
@ -466,17 +469,17 @@ intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
|
|||||||
if (req.method !== 'GET') {
|
if (req.method !== 'GET') {
|
||||||
return next.handle(req);
|
return next.handle(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will be an Observable of the cached value if there is one,
|
// This will be an Observable of the cached value if there is one,
|
||||||
// or an empty Observable otherwise. It starts out empty.
|
// or an empty Observable otherwise. It starts out empty.
|
||||||
let maybeCachedResponse: Observable<HttpEvent<any>> = Observable.empty();
|
let maybeCachedResponse: Observable<HttpEvent<any>> = Observable.empty();
|
||||||
|
|
||||||
// Check the cache.
|
// Check the cache.
|
||||||
const cachedResponse = this.cache.get(req);
|
const cachedResponse = this.cache.get(req);
|
||||||
if (cachedResponse) {
|
if (cachedResponse) {
|
||||||
maybeCachedResponse = Observable.of(cachedResponse);
|
maybeCachedResponse = Observable.of(cachedResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an Observable (but don't subscribe) that represents making
|
// Create an Observable (but don't subscribe) that represents making
|
||||||
// the network request and caching the value.
|
// the network request and caching the value.
|
||||||
const networkResponse = next.handle(req).do(event => {
|
const networkResponse = next.handle(req).do(event => {
|
||||||
@ -485,7 +488,7 @@ intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
|
|||||||
this.cache.put(req, event);
|
this.cache.put(req, event);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Now, combine the two and send the cached response first (if there is
|
// Now, combine the two and send the cached response first (if there is
|
||||||
// one), and the network response second.
|
// one), and the network response second.
|
||||||
return Observable.concat(maybeCachedResponse, networkResponse);
|
return Observable.concat(maybeCachedResponse, networkResponse);
|
||||||
@ -506,7 +509,7 @@ const req = new HttpRequest('POST', '/upload/file', file, {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
This option enables tracking of progress events. Remember, every progress event triggers
|
This option enables tracking of progress events. Remember, every progress event triggers
|
||||||
change detection, so only turn them on if you intend to actually update the UI on each event.
|
change detection, so only turn them on if you intend to actually update the UI on each event.
|
||||||
|
|
||||||
Next, make the request through the `request()` method of `HttpClient`. The result will be an Observable of events, just like with interceptors:
|
Next, make the request through the `request()` method of `HttpClient`. The result will be an Observable of events, just like with interceptors:
|
||||||
@ -529,11 +532,11 @@ http.request(req).subscribe(event => {
|
|||||||
|
|
||||||
[Cross-Site Request Forgery (XSRF)](https://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by which the attacker can trick an authenticated user into unknowingly executing actions on your website. `HttpClient` supports a [common mechanism](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Cookie-to-Header_Token) used to prevent XSRF attacks. When performing HTTP requests, an interceptor reads a token from a cookie, by default `XSRF-TOKEN`, and sets it as an HTTP header, `X-XSRF-TOKEN`. Since only code that runs on your domain could read the cookie, the backend can be certain that the HTTP request came from your client application and not an attacker.
|
[Cross-Site Request Forgery (XSRF)](https://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by which the attacker can trick an authenticated user into unknowingly executing actions on your website. `HttpClient` supports a [common mechanism](https://en.wikipedia.org/wiki/Cross-site_request_forgery#Cookie-to-Header_Token) used to prevent XSRF attacks. When performing HTTP requests, an interceptor reads a token from a cookie, by default `XSRF-TOKEN`, and sets it as an HTTP header, `X-XSRF-TOKEN`. Since only code that runs on your domain could read the cookie, the backend can be certain that the HTTP request came from your client application and not an attacker.
|
||||||
|
|
||||||
By default, an interceptor sends this cookie on all mutating requests (POST, etc.)
|
By default, an interceptor sends this cookie on all mutating requests (POST, etc.)
|
||||||
to relative URLs but not on GET/HEAD requests or
|
to relative URLs but not on GET/HEAD requests or
|
||||||
on requests with an absolute URL.
|
on requests with an absolute URL.
|
||||||
|
|
||||||
To take advantage of this, your server needs to set a token in a JavaScript readable session cookie called `XSRF-TOKEN` on either the page load or the first GET request. On subsequent requests the server can verify that the cookie matches the `X-XSRF-TOKEN` HTTP header, and therefore be sure that only code running on your domain could have sent the request. The token must be unique for each user and must be verifiable by the server; this prevents the client from making up its own tokens. Set the token to a digest of your site's authentication
|
To take advantage of this, your server needs to set a token in a JavaScript readable session cookie called `XSRF-TOKEN` on either the page load or the first GET request. On subsequent requests the server can verify that the cookie matches the `X-XSRF-TOKEN` HTTP header, and therefore be sure that only code running on your domain could have sent the request. The token must be unique for each user and must be verifiable by the server; this prevents the client from making up its own tokens. Set the token to a digest of your site's authentication
|
||||||
cookie with a salt for added security.
|
cookie with a salt for added security.
|
||||||
|
|
||||||
In order to prevent collisions in environments where multiple Angular apps share the same domain or subdomain, give each application a unique cookie name.
|
In order to prevent collisions in environments where multiple Angular apps share the same domain or subdomain, give each application a unique cookie name.
|
||||||
@ -595,23 +598,23 @@ it('expects a GET request', inject([HttpClient, HttpTestingController], (http: H
|
|||||||
http
|
http
|
||||||
.get('/data')
|
.get('/data')
|
||||||
.subscribe(data => expect(data['name']).toEqual('Test Data'));
|
.subscribe(data => expect(data['name']).toEqual('Test Data'));
|
||||||
|
|
||||||
// At this point, the request is pending, and no response has been
|
// At this point, the request is pending, and no response has been
|
||||||
// sent. The next step is to expect that the request happened.
|
// sent. The next step is to expect that the request happened.
|
||||||
const req = httpMock.expectOne('/test');
|
const req = httpMock.expectOne('/data');
|
||||||
|
|
||||||
// If no request with that URL was made, or if multiple requests match,
|
// If no request with that URL was made, or if multiple requests match,
|
||||||
// expectOne() would throw. However this test makes only one request to
|
// expectOne() would throw. However this test makes only one request to
|
||||||
// this URL, so it will match and return a mock request. The mock request
|
// this URL, so it will match and return a mock request. The mock request
|
||||||
// can be used to deliver a response or make assertions against the
|
// can be used to deliver a response or make assertions against the
|
||||||
// request. In this case, the test asserts that the request is a GET.
|
// request. In this case, the test asserts that the request is a GET.
|
||||||
expect(req.request.method).toEqual('GET');
|
expect(req.request.method).toEqual('GET');
|
||||||
|
|
||||||
// Next, fulfill the request by transmitting a response.
|
// Next, fulfill the request by transmitting a response.
|
||||||
req.flush({name: 'Test Data'});
|
req.flush({name: 'Test Data'});
|
||||||
|
|
||||||
// Finally, assert that there are no outstanding requests.
|
// Finally, assert that there are no outstanding requests.
|
||||||
mockHttp.verify();
|
httpMock.verify();
|
||||||
}));
|
}));
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -619,7 +622,7 @@ The last step, verifying that no requests remain outstanding, is common enough f
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => {
|
afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => {
|
||||||
mockHttp.verify();
|
httpMock.verify();
|
||||||
}));
|
}));
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -628,7 +631,7 @@ afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => {
|
|||||||
If matching by URL isn't sufficient, it's possible to implement your own matching function. For example, you could look for an outgoing request that has an Authorization header:
|
If matching by URL isn't sufficient, it's possible to implement your own matching function. For example, you could look for an outgoing request that has an Authorization header:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const req = mockHttp.expectOne((req) => req.headers.has('Authorization'));
|
const req = httpMock.expectOne((req) => req.headers.has('Authorization'));
|
||||||
```
|
```
|
||||||
|
|
||||||
Just as with the `expectOne()` by URL in the test above, if 0 or 2+ requests match this expectation, it will throw.
|
Just as with the `expectOne()` by URL in the test above, if 0 or 2+ requests match this expectation, it will throw.
|
||||||
@ -639,7 +642,7 @@ If you need to respond to duplicate requests in your test, use the `match()` API
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Expect that 5 pings have been made and flush them.
|
// Expect that 5 pings have been made and flush them.
|
||||||
const reqs = mockHttp.match('/ping');
|
const reqs = httpMock.match('/ping');
|
||||||
expect(reqs.length).toBe(5);
|
expect(reqs.length).toBe(5);
|
||||||
reqs.forEach(req => req.flush());
|
reqs.forEach(req => req.flush());
|
||||||
```
|
```
|
||||||
|
@ -397,8 +397,7 @@ created under test or before you decide to display it.
|
|||||||
Constructors should do no more than set the initial local variables to simple values.
|
Constructors should do no more than set the initial local variables to simple values.
|
||||||
|
|
||||||
An `ngOnInit()` is a good place for a component to fetch its initial data. The
|
An `ngOnInit()` is a good place for a component to fetch its initial data. The
|
||||||
[Tour of Heroes Tutorial](tutorial/toh-pt4#oninit) and [HTTP Client](guide/http#oninit)
|
[Tour of Heroes Tutorial](tutorial/toh-pt4#oninit) guide shows how.
|
||||||
guides show how.
|
|
||||||
|
|
||||||
|
|
||||||
Remember also that a directive's data-bound input properties are not set until _after construction_.
|
Remember also that a directive's data-bound input properties are not set until _after construction_.
|
||||||
|
@ -615,7 +615,7 @@ Once the application begins, the app root injector is closed to new providers.
|
|||||||
|
|
||||||
Time passes and application logic triggers lazy loading of a module.
|
Time passes and application logic triggers lazy loading of a module.
|
||||||
Angular must add the lazy-loaded module's providers to an injector somewhere.
|
Angular must add the lazy-loaded module's providers to an injector somewhere.
|
||||||
It can't added them to the app root injector because that injector is closed to new providers.
|
It can't add them to the app root injector because that injector is closed to new providers.
|
||||||
So Angular creates a new child injector for the lazy-loaded module context.
|
So Angular creates a new child injector for the lazy-loaded module context.
|
||||||
|
|
||||||
|
|
||||||
|
@ -163,7 +163,6 @@ without waiting for Angular updates.
|
|||||||
***angular-in-memory-web-api***: An Angular-supported library that simulates a remote server's web api
|
***angular-in-memory-web-api***: An Angular-supported library that simulates a remote server's web api
|
||||||
without requiring an actual server or real HTTP calls.
|
without requiring an actual server or real HTTP calls.
|
||||||
Good for demos, samples, and early stage development (before you even have a server).
|
Good for demos, samples, and early stage development (before you even have a server).
|
||||||
Read about it in the [HTTP Client](guide/http#in-mem-web-api) page.
|
|
||||||
|
|
||||||
***bootstrap***: [Bootstrap](http://getbootstrap.com/) is a popular HTML and CSS framework for designing responsive web apps.
|
***bootstrap***: [Bootstrap](http://getbootstrap.com/) is a popular HTML and CSS framework for designing responsive web apps.
|
||||||
Some of the samples improve their appearance with *bootstrap*.
|
Some of the samples improve their appearance with *bootstrap*.
|
||||||
|
@ -1080,8 +1080,11 @@ To get access to the `FormArray` class, import it into `hero-detail.component.ts
|
|||||||
|
|
||||||
|
|
||||||
To _work_ with a `FormArray` you do the following:
|
To _work_ with a `FormArray` you do the following:
|
||||||
|
|
||||||
1. Define the items (`FormControls` or `FormGroups`) in the array.
|
1. Define the items (`FormControls` or `FormGroups`) in the array.
|
||||||
|
|
||||||
1. Initialize the array with items created from data in the _data model_.
|
1. Initialize the array with items created from data in the _data model_.
|
||||||
|
|
||||||
1. Add and remove items as the user requires.
|
1. Add and remove items as the user requires.
|
||||||
|
|
||||||
In this guide, you define a `FormArray` for `Hero.addresses` and
|
In this guide, you define a `FormArray` for `Hero.addresses` and
|
||||||
|
@ -255,11 +255,11 @@ During each navigation, the `Router` emits navigation events through the `Router
|
|||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<code>RouteConfigLoadStart</code>
|
<code>RouteConfigLoadEnd</code>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
An [event](api/router/RouteConfigLoadStart) triggered after a route has been lazy loaded.
|
An [event](api/router/RouteConfigLoadEnd) triggered after a route has been lazy loaded.
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -1830,7 +1830,7 @@ Finally, you activate the observable with `subscribe` method and (re)set the com
|
|||||||
|
|
||||||
#### _ParamMap_ API
|
#### _ParamMap_ API
|
||||||
|
|
||||||
The `ParamMap` API is inspired by the [URLSearchParams interface](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParamsOPut). It provides methods
|
The `ParamMap` API is inspired by the [URLSearchParams interface](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams). It provides methods
|
||||||
to handle parameter access for both route parameters (`paramMap`) and query parameters (`queryParamMap`).
|
to handle parameter access for both route parameters (`paramMap`) and query parameters (`queryParamMap`).
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
@ -178,7 +178,7 @@ For a discussion of the unit testing setup files, [see below](guide/testing#setu
|
|||||||
{@a isolated-v-testing-utilities}
|
{@a isolated-v-testing-utilities}
|
||||||
|
|
||||||
|
|
||||||
### Isolated unit tests vs. the Angular testing utilites
|
### Isolated unit tests vs. the Angular testing utilities
|
||||||
|
|
||||||
[Isolated unit tests](guide/testing#isolated-unit-tests "Unit testing without the Angular testing utilities")
|
[Isolated unit tests](guide/testing#isolated-unit-tests "Unit testing without the Angular testing utilities")
|
||||||
examine an instance of a class all by itself without any dependence on Angular or any injected values.
|
examine an instance of a class all by itself without any dependence on Angular or any injected values.
|
||||||
|
@ -247,12 +247,10 @@ next to the original _ES5_ version for comparison:
|
|||||||
</code-pane>
|
</code-pane>
|
||||||
</code-tabs>
|
</code-tabs>
|
||||||
|
|
||||||
|
{@a name-constructor}
|
||||||
|
|
||||||
<div class="callout is-helpful">
|
<div class="callout is-helpful">
|
||||||
|
|
||||||
{@a name-constructor}
|
|
||||||
|
|
||||||
### Name the constructor
|
|
||||||
|
|
||||||
A **named** constructor displays clearly in the console log
|
A **named** constructor displays clearly in the console log
|
||||||
if the component throws a runtime error.
|
if the component throws a runtime error.
|
||||||
An **unnamed** constructor displays as an anonymous function, for example, `class0`,
|
An **unnamed** constructor displays as an anonymous function, for example, `class0`,
|
||||||
|
BIN
aio/content/images/bios/gerardsans.jpg
Normal file
After Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 101 KiB |
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 320 KiB After Width: | Height: | Size: 200 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
aio/content/images/marketing/home/angular-mix.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 257 KiB After Width: | Height: | Size: 257 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 4.1 KiB |
@ -573,5 +573,14 @@
|
|||||||
"website": "http://www.methotic.com",
|
"website": "http://www.methotic.com",
|
||||||
"bio": "Thierry is a senior consultant and trainer, specialized on Angular, and a Google Developer Expert.",
|
"bio": "Thierry is a senior consultant and trainer, specialized on Angular, and a Google Developer Expert.",
|
||||||
"group": "GDE"
|
"group": "GDE"
|
||||||
|
},
|
||||||
|
|
||||||
|
"gerardsans": {
|
||||||
|
"name": "Gerard Sans",
|
||||||
|
"picture": "gerardsans.jpg",
|
||||||
|
"twitter": "gerardsans",
|
||||||
|
"website": "https://medium.com/@gerard.sans",
|
||||||
|
"bio": "Gerard is very excited about the future of the Web and JavaScript. Always happy Computer Science Engineer and humble Google Developer Expert. He loves to share his learnings by giving talks, trainings and writing about cool technologies. He loves running AngularZone and GraphQL London, mentoring students and giving back to the community.",
|
||||||
|
"group": "GDE"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<div class="feature-section">
|
<div class="feature-section">
|
||||||
<div class="feature-header">
|
<div class="feature-header">
|
||||||
<div class="text-headline">Cross Platform</div>
|
<div class="text-headline">Cross Platform</div>
|
||||||
<img src="../assets/images/icons/feature-icon.svg" height="70px">
|
<img src="generated/images/marketing/features/feature-icon.svg" height="70px">
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-row">
|
<div class="feature-row">
|
||||||
|
|
||||||
@ -34,7 +34,7 @@
|
|||||||
<div class="feature-section">
|
<div class="feature-section">
|
||||||
<div class="feature-header">
|
<div class="feature-header">
|
||||||
<div class="text-headline">Speed and Performance</div>
|
<div class="text-headline">Speed and Performance</div>
|
||||||
<img src="../assets/images/icons/feature-icon.svg" height="70px">
|
<img src="generated/images/marketing/features/feature-icon.svg" height="70px">
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-row">
|
<div class="feature-row">
|
||||||
|
|
||||||
@ -59,7 +59,7 @@
|
|||||||
<div class="feature-section">
|
<div class="feature-section">
|
||||||
<div class="feature-header">
|
<div class="feature-header">
|
||||||
<div class="text-headline">Productivity</div>
|
<div class="text-headline">Productivity</div>
|
||||||
<img src="../assets/images/icons/feature-icon.svg" height="70px">
|
<img src="generated/images/marketing/features/feature-icon.svg" height="70px">
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-row">
|
<div class="feature-row">
|
||||||
|
|
||||||
@ -84,7 +84,7 @@
|
|||||||
<div class="feature-section">
|
<div class="feature-section">
|
||||||
<div class="feature-header">
|
<div class="feature-header">
|
||||||
<div class="text-headline">Full Development Story</div>
|
<div class="text-headline">Full Development Story</div>
|
||||||
<img src="../assets/images/icons/feature-icon.svg" height="70px">
|
<img src="generated/images/marketing/features/feature-icon.svg" height="70px">
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-row">
|
<div class="feature-row">
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
<!--Announcement Bar-->
|
<!--Announcement Bar-->
|
||||||
<div class="homepage-container">
|
<div class="homepage-container">
|
||||||
<div class="announcement-bar">
|
<div class="announcement-bar">
|
||||||
<img src="generated/images/marketing/angular-mix.png" height="40" width="151">
|
<img src="generated/images/marketing/home/angular-mix.png" height="40" width="151">
|
||||||
<p>Join us at our newest event, October 2017</p>
|
<p>Join us at our newest event, October 2017</p>
|
||||||
<a class="button" href="https://angularmix.com/">Learn More</a>
|
<a class="button" href="https://angularmix.com/">Learn More</a>
|
||||||
</div>
|
</div>
|
||||||
@ -40,7 +40,7 @@
|
|||||||
<div layout="row" layout-xs="column" class="home-row homepage-container">
|
<div layout="row" layout-xs="column" class="home-row homepage-container">
|
||||||
<div class="promo-img-container promo-1">
|
<div class="promo-img-container promo-1">
|
||||||
<div>
|
<div>
|
||||||
<img height="222" width="340" src="assets/images/home/responsive-framework.svg" alt="responsive framework">
|
<img height="222" width="340" src="generated/images/marketing/home/responsive-framework.svg" alt="responsive framework">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -65,7 +65,7 @@
|
|||||||
|
|
||||||
<div class="promo-img-container promo-2">
|
<div class="promo-img-container promo-2">
|
||||||
<div>
|
<div>
|
||||||
<img height="222" width="323" src="assets/images/home/speed-performance.svg" alt="speed and performance">
|
<img height="222" width="323" src="generated/images/marketing/home/speed-performance.svg" alt="speed and performance">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -74,7 +74,7 @@
|
|||||||
<!-- Group 3-->
|
<!-- Group 3-->
|
||||||
<div layout="row" layout-xs="column" class="home-row">
|
<div layout="row" layout-xs="column" class="home-row">
|
||||||
<div class="promo-img-container promo-3">
|
<div class="promo-img-container promo-3">
|
||||||
<div><img src="assets/images/home/joyful-development.png" alt="IDE example"></div>
|
<div><img src="generated/images/marketing/home/joyful-development.svg" alt="IDE example"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-container">
|
<div class="text-container">
|
||||||
@ -100,7 +100,7 @@
|
|||||||
|
|
||||||
<div class="promo-img-container promo-4">
|
<div class="promo-img-container promo-4">
|
||||||
<div>
|
<div>
|
||||||
<img src="assets/images/home/loved-by-millions.png" alt="angular on the map" width="455" height="228">
|
<img src="generated/images/marketing/home/loved-by-millions.svg" alt="angular on the map" width="455" height="228">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -110,7 +110,7 @@
|
|||||||
|
|
||||||
<a href="guide/quickstart">
|
<a href="guide/quickstart">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<img src="../assets/images/icons/code-icon.svg" height="70px">
|
<img src="generated/images/marketing/home/code-icon.svg" height="70px">
|
||||||
<div class="card-text-container">
|
<div class="card-text-container">
|
||||||
<div class="text-headline">Get Started</div>
|
<div class="text-headline">Get Started</div>
|
||||||
<p>Start building your Angular application.</p>
|
<p>Start building your Angular application.</p>
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
<header class="hero background-sky">
|
|
||||||
<h1 class="hero-title no-toc">News</h1>
|
|
||||||
<div class="clear"></div>
|
|
||||||
</header>
|
|
||||||
<artice>
|
|
||||||
<div class="grid-fluid l-space-bottom-2">
|
|
||||||
<div class="c12 text-center"><h3 class="text-headline text-uppercase"> Core Team</h3></div>
|
|
||||||
<div class="clear"></div>
|
|
||||||
</div>
|
|
||||||
<div class="grid-fluid">
|
|
||||||
<div class="c6">
|
|
||||||
<div class="article-card">
|
|
||||||
<div class="date">Oct 12, 2016</div>
|
|
||||||
<div class="title"><a target="_blank"
|
|
||||||
href="http://angularjs.blogspot.com/2016/10/angular-210-now-available.html">Angular
|
|
||||||
2.1.0 Now Available</a></div>
|
|
||||||
<p>Angular version 2.1.0 - incremental-metamorphosis - is a minor release following our
|
|
||||||
announced adoption of Semantic Versioning...</p>
|
|
||||||
<div class="author"><img src="generated/images/bios/stephenfluin.jpg">
|
|
||||||
<div class="posted">Posted by <b>Stephen Fluin</b></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="c6">
|
|
||||||
<div class="article-card">
|
|
||||||
<div class="date">Oct 7, 2016</div>
|
|
||||||
<div class="title"><a target="_blank"
|
|
||||||
href="http://angularjs.blogspot.com/2016/10/versioning-and-releasing-angular.html">Versioning
|
|
||||||
and Releasing Angular</a></div>
|
|
||||||
<p>In order for the ecosystem around Angular to thrive, developers need stability from the
|
|
||||||
Angular framework so that reusable components and libraries, tools and learned practices
|
|
||||||
don’t go obsolete unexpectedly...</p>
|
|
||||||
<div class="author"><img src="generated/images/bios/igor-minar.jpg">
|
|
||||||
<div class="posted">Posted by <b>Igor Minar</b></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="grid-fluid l-space-bottom-2 l-space-top-4">
|
|
||||||
<div class="c12 text-center"><h3 class="text-headline text-uppercase"> Developer Community</h3>
|
|
||||||
</div>
|
|
||||||
<div class="clear"></div>
|
|
||||||
</div>
|
|
||||||
<div class="grid-fluid">
|
|
||||||
<div class="c6">
|
|
||||||
<div class="article-card">
|
|
||||||
<div class="date">Oct 30, 2016</div>
|
|
||||||
<div class="title"><a target="_blank"
|
|
||||||
href="https://www.thepolyglotdeveloper.com/2016/10/use-pre-populated-sqlite-database-nativescript-angular-2/">Use
|
|
||||||
A Pre-Populated SQLite Database With NativeScript And Angular 2</a></div>
|
|
||||||
<p>I figured it would be a good idea to demonstrate how to ship a NativeScript Angular 2
|
|
||||||
application with a pre-filled SQLite database rather than populating it on-the-fly....</p>
|
|
||||||
<div class="author"><img src="generated/images/bios/shield-bio-placeholder.png">
|
|
||||||
<div class="posted">Posted by <b>Nic Raboy</b></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="c6">
|
|
||||||
<div class="article-card">
|
|
||||||
<div class="date">Oct 13, 2016</div>
|
|
||||||
<div class="title"><a target="_blank"
|
|
||||||
href="http://blog.thoughtram.io/angular/2016/10/13/two-way-data-binding-in-angular-2.html">Two-way
|
|
||||||
Data Binding in Angular 2</a></div>
|
|
||||||
<p>If there was one feature in Angular that made us go “Wow”, then it was probably its
|
|
||||||
two-way data binding system. Changes in the application state have been automagically
|
|
||||||
reflected into the view...</p>
|
|
||||||
<div class="author"><img src="generated/images/bios/angular-gde-bio-placeholder.png">
|
|
||||||
<div class="posted">Posted by <b>Pascal Precht</b></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="grid-fluid">
|
|
||||||
<div class="c6">
|
|
||||||
<div class="article-card">
|
|
||||||
<div class="date">Oct 10, 2016</div>
|
|
||||||
<div class="title"><a target="_blank"
|
|
||||||
href="http://www.creativebloq.com/how-to/build-a-material-design-app-with-angular-2">Build
|
|
||||||
a Material Design app with Angular 2</a></div>
|
|
||||||
<p>This walkthrough reveals how to create a DialogComponent and to-do app with Angular
|
|
||||||
Material and the Angular CLI...</p>
|
|
||||||
<div class="author"><img src="generated/images/bios/shield-bio-placeholder.png">
|
|
||||||
<div class="posted">Posted by <b>Daniel Zen</b></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="c6">
|
|
||||||
<div class="article-card">
|
|
||||||
<div class="date">Sept 30, 2016</div>
|
|
||||||
<div class="title"><a target="_blank"
|
|
||||||
href="http://www.simb.co/angular-cli-using-docker/?platform=hootsuite">Using
|
|
||||||
Angular CLI to create Angular 2 applications in Docker</a></div>
|
|
||||||
<p>Angular CLI is a great tool for developing Angular 2 applications. I thought it would be
|
|
||||||
fun to do a quick demo...</p>
|
|
||||||
<div class="author"><img src="generated/images/bios/shield-bio-placeholder.png">
|
|
||||||
<div class="posted">Posted by <b>Simeon Bateman</b></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="grid-fluid l-space-bottom-2 l-space-top-4">
|
|
||||||
<div class="c12 text-center"><h3 class="text-headline text-uppercase">Twitter</h3></div>
|
|
||||||
<div class="clear"></div>
|
|
||||||
<div class="grid-fluid">
|
|
||||||
<div class="c3"><p></p></div>
|
|
||||||
<div class="c6">
|
|
||||||
<div class="article-card">
|
|
||||||
<div class="title"><a href="http://twitter.com/angularjs" data-show-count="false"
|
|
||||||
class="twitter-follow-button">Follow @angularjs</a></div>
|
|
||||||
<p><a class="twitter-timeline" data-chrome="nofooter noborders noheader"
|
|
||||||
href="http://twitter.com/angularjs" data-widget-id="700150278465523713"></a></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
@ -17,7 +17,7 @@
|
|||||||
"title": "Events"
|
"title": "Events"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "https://blog.angularjs.org/",
|
"url": "https://blog.angular.io/",
|
||||||
"title": "Blog"
|
"title": "Blog"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -39,7 +39,7 @@
|
|||||||
"title": "Events"
|
"title": "Events"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "https://blog.angularjs.org/",
|
"url": "https://blog.angular.io/",
|
||||||
"title": "Blog"
|
"title": "Blog"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -137,7 +137,7 @@ Create a file in the `app` folder called `hero.service.ts`.
|
|||||||
|
|
||||||
|
|
||||||
The naming convention for service files is the service name in lowercase followed by `.service`.
|
The naming convention for service files is the service name in lowercase followed by `.service`.
|
||||||
For a multi-word service name, use lower [dash-case](guide/glossary).
|
For a multi-word service name, use lower [dash-case](guide/glossary#dash-case).
|
||||||
For example, the filename for `SpecialSuperHeroService` is `special-super-hero.service.ts`.
|
For example, the filename for `SpecialSuperHeroService` is `special-super-hero.service.ts`.
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -83,10 +83,6 @@ Added hero "Zero" to confirm that the data service can handle a hero with `id==0
|
|||||||
Don't worry about the details of this backend substitution; you can
|
Don't worry about the details of this backend substitution; you can
|
||||||
skip it when you have a real web API server.
|
skip it when you have a real web API server.
|
||||||
|
|
||||||
Read more about the in-memory web API in the
|
|
||||||
[Appendix: Tour of Heroes in-memory web api](guide/http#in-mem-web-api)
|
|
||||||
section of the [HTTP Client](guide/http#in-mem-web-api) page.
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## Heroes and HTTP
|
## Heroes and HTTP
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
},
|
},
|
||||||
"static.ignore": [
|
"static.ignore": [
|
||||||
"\\.js\\.map$",
|
"\\.js\\.map$",
|
||||||
"^/assets/images/.*/unused/",
|
"^(?:/|\\\\)assets(?:/|\\\\)images(?:/|\\\\).*(?:/|\\\\)_unused(?:/|\\\\)",
|
||||||
"^/generated/(?:docs/(?!api/api-list\\.json).*|images|live-examples|zips)/"
|
"^(?:/|\\\\)generated(?:/|\\\\)(?:docs(?:/|\\\\)(?!api(?:/|\\\\)api-list\\.json).*|images(?:/|\\\\)(?!marketing(?:/|\\\\)).*|live-examples|zips)(?:/|\\\\)"
|
||||||
],
|
],
|
||||||
"static.versioned": [
|
"static.versioned": [
|
||||||
"\\.[0-9a-z]{20}\\."
|
"\\.[0-9a-z]{20}\\."
|
||||||
|
@ -33,8 +33,9 @@
|
|||||||
"docs-test": "node tools/transforms/test.js",
|
"docs-test": "node tools/transforms/test.js",
|
||||||
"serve-and-sync": "concurrently --kill-others \"yarn docs-watch\" \"yarn start\"",
|
"serve-and-sync": "concurrently --kill-others \"yarn docs-watch\" \"yarn start\"",
|
||||||
"~~update-webdriver": "webdriver-manager update --standalone false --gecko false",
|
"~~update-webdriver": "webdriver-manager update --standalone false --gecko false",
|
||||||
"boilerplate:add": "node ./tools/examples/add-example-boilerplate add",
|
"boilerplate:add": "node ./tools/examples/example-boilerplate add",
|
||||||
"boilerplate:remove": "node ./tools/examples/add-example-boilerplate remove",
|
"boilerplate:remove": "node ./tools/examples/example-boilerplate remove",
|
||||||
|
"boilerplate:test": "node tools/examples/test.js",
|
||||||
"generate-plunkers": "node ./tools/plunker-builder/generatePlunkers",
|
"generate-plunkers": "node ./tools/plunker-builder/generatePlunkers",
|
||||||
"generate-zips": "node ./tools/example-zipper/generateZips",
|
"generate-zips": "node ./tools/example-zipper/generateZips",
|
||||||
"sw-manifest": "ngu-sw-manifest --dist dist --in ngsw-manifest.json --out dist/ngsw-manifest.json",
|
"sw-manifest": "ngu-sw-manifest --dist dist --in ngsw-manifest.json --out dist/ngsw-manifest.json",
|
||||||
@ -48,17 +49,18 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^4.2.4",
|
"@angular/animations": "^4.3.1",
|
||||||
"@angular/common": "^4.2.4",
|
"@angular/cdk": "^2.0.0-beta.8",
|
||||||
"@angular/compiler": "^4.2.4",
|
"@angular/common": "^4.3.1",
|
||||||
"@angular/core": "^4.2.4",
|
"@angular/compiler": "^4.3.1",
|
||||||
"@angular/forms": "^4.2.4",
|
"@angular/core": "^4.3.1",
|
||||||
"@angular/http": "^4.2.4",
|
"@angular/forms": "^4.3.1",
|
||||||
"@angular/material": "^2.0.0-beta.7",
|
"@angular/http": "^4.3.1",
|
||||||
"@angular/platform-browser": "^4.2.4",
|
"@angular/material": "^2.0.0-beta.8",
|
||||||
"@angular/platform-browser-dynamic": "^4.2.4",
|
"@angular/platform-browser": "^4.3.1",
|
||||||
"@angular/platform-server": "^4.2.4",
|
"@angular/platform-browser-dynamic": "^4.3.1",
|
||||||
"@angular/router": "^4.2.4",
|
"@angular/platform-server": "^4.3.1",
|
||||||
|
"@angular/router": "^4.3.1",
|
||||||
"@angular/service-worker": "^1.0.0-beta.16",
|
"@angular/service-worker": "^1.0.0-beta.16",
|
||||||
"classlist.js": "^1.1.20150312",
|
"classlist.js": "^1.1.20150312",
|
||||||
"core-js": "^2.4.1",
|
"core-js": "^2.4.1",
|
||||||
@ -72,7 +74,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/cli": "angular/cli-builds#webpack-next",
|
"@angular/cli": "angular/cli-builds#webpack-next",
|
||||||
"@angular/compiler-cli": "^4.2.4",
|
"@angular/compiler-cli": "^4.3.1",
|
||||||
"@types/jasmine": "^2.5.52",
|
"@types/jasmine": "^2.5.52",
|
||||||
"@types/node": "~6.0.60",
|
"@types/node": "~6.0.60",
|
||||||
"archiver": "^1.3.0",
|
"archiver": "^1.3.0",
|
||||||
@ -81,7 +83,7 @@
|
|||||||
"concurrently": "^3.4.0",
|
"concurrently": "^3.4.0",
|
||||||
"cross-spawn": "^5.1.0",
|
"cross-spawn": "^5.1.0",
|
||||||
"dgeni": "^0.4.7",
|
"dgeni": "^0.4.7",
|
||||||
"dgeni-packages": "^0.20.0-rc.5",
|
"dgeni-packages": "^0.20.0",
|
||||||
"entities": "^1.1.1",
|
"entities": "^1.1.1",
|
||||||
"eslint": "^3.19.0",
|
"eslint": "^3.19.0",
|
||||||
"eslint-plugin-jasmine": "^2.2.0",
|
"eslint-plugin-jasmine": "^2.2.0",
|
||||||
|
@ -4,12 +4,8 @@ set -eu -o pipefail
|
|||||||
|
|
||||||
readonly thisDir=$(cd $(dirname $0); pwd)
|
readonly thisDir=$(cd $(dirname $0); pwd)
|
||||||
readonly parentDir=$(dirname $thisDir)
|
readonly parentDir=$(dirname $thisDir)
|
||||||
readonly TOKEN=${ANGULAR_PAYLOAD_FIREBASE_TOKEN:-}
|
|
||||||
readonly PROJECT_NAME="angular-payload-size"
|
readonly PROJECT_NAME="angular-payload-size"
|
||||||
|
|
||||||
# temporarily turn on debugging - we disable it later in the script to prevent token leak
|
|
||||||
set -x
|
|
||||||
|
|
||||||
source ${thisDir}/_payload-limits.sh
|
source ${thisDir}/_payload-limits.sh
|
||||||
|
|
||||||
failed=false
|
failed=false
|
||||||
@ -45,15 +41,21 @@ timestamp=$(date +%s)
|
|||||||
payloadData="$payloadData\"timestamp\": $timestamp, "
|
payloadData="$payloadData\"timestamp\": $timestamp, "
|
||||||
|
|
||||||
# Add change source: application, dependencies, or 'application+dependencies'
|
# Add change source: application, dependencies, or 'application+dependencies'
|
||||||
applicationChanges=$(git diff --name-only $TRAVIS_COMMIT_RANGE $parentDir | grep -v ${parentDir}/content | grep -v ${parentDir}/yarn.lock | wc -l)
|
applicationChanged=false
|
||||||
dependencyChanges=$(git diff --name-only $TRAVIS_COMMIT_RANGE ${parentDir}/yarn.lock | wc -l)
|
dependenciesChanged=false
|
||||||
|
if [[ $(git diff --name-only $TRAVIS_COMMIT_RANGE $parentDir | grep -v aio/yarn.lock | grep -v content) ]]; then
|
||||||
|
applicationChanged=true
|
||||||
|
fi
|
||||||
|
if [[ $(git diff --name-only $TRAVIS_COMMIT_RANGE $parentDir/yarn.lock) ]]; then
|
||||||
|
dependenciesChanged=true
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ $dependencyChanges -eq 1 ]] && [[ $applicationChanges -eq 0 ]]; then
|
if $dependenciesChanged && $applicationChanged; then
|
||||||
|
change='application+dependencies'
|
||||||
|
elif $dependenciesChanged; then
|
||||||
# only yarn.lock changed
|
# only yarn.lock changed
|
||||||
change='dependencies'
|
change='dependencies'
|
||||||
elif [[ $dependencyChanges -eq 1 ]] && [[ $applicationChanges -gt 0 ]]; then
|
elif $applicationChanged; then
|
||||||
change='application+dependencies'
|
|
||||||
elif [[ $applicationChanges -gt 0 ]]; then
|
|
||||||
change='application'
|
change='application'
|
||||||
else
|
else
|
||||||
# Nothing changed in aio/
|
# Nothing changed in aio/
|
||||||
@ -71,7 +73,7 @@ if [[ "$TRAVIS_PULL_REQUEST" == "false" ]]; then
|
|||||||
|
|
||||||
# WARNING: FIREBASE_TOKEN should NOT be printed.
|
# WARNING: FIREBASE_TOKEN should NOT be printed.
|
||||||
set +x
|
set +x
|
||||||
firebase database:update --data "$payloadData" --project $PROJECT_NAME --confirm --token "$TOKEN" $dbPath
|
firebase database:update --data "$payloadData" --project $PROJECT_NAME --confirm --token "$ANGULAR_PAYLOAD_FIREBASE_TOKEN" $dbPath
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $failed = true ]]; then
|
if [[ $failed = true ]]; then
|
||||||
|
@ -19,11 +19,6 @@ const config = require('lighthouse/lighthouse-core/config/default.js');
|
|||||||
// Constants
|
// Constants
|
||||||
const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer/';
|
const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer/';
|
||||||
|
|
||||||
// Specify the path to Chrome on Travis
|
|
||||||
if (process.env.TRAVIS) {
|
|
||||||
process.env.LIGHTHOUSE_CHROMIUM_PATH = process.env.CHROME_BIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run
|
// Run
|
||||||
_main(process.argv.slice(2));
|
_main(process.argv.slice(2));
|
||||||
|
|
||||||
|
@ -632,7 +632,6 @@ describe('AppComponent', () => {
|
|||||||
it('should initialize the search worker', inject([SearchService], (searchService: SearchService) => {
|
it('should initialize the search worker', inject([SearchService], (searchService: SearchService) => {
|
||||||
fixture.detectChanges(); // triggers ngOnInit
|
fixture.detectChanges(); // triggers ngOnInit
|
||||||
expect(searchService.initWorker).toHaveBeenCalled();
|
expect(searchService.initWorker).toHaveBeenCalled();
|
||||||
expect(searchService.loadIndex).toHaveBeenCalled();
|
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ export class AppComponent implements OnInit {
|
|||||||
* the styling of individual pages.
|
* the styling of individual pages.
|
||||||
* You will get three classes:
|
* You will get three classes:
|
||||||
*
|
*
|
||||||
* * `page-...`: computed from the current document id (e.g. news, guide-security, tutorial-toh-pt2)
|
* * `page-...`: computed from the current document id (e.g. events, guide-security, tutorial-toh-pt2)
|
||||||
* * `folder-...`: computed from the top level folder for an id (e.g. guide, tutorial, etc)
|
* * `folder-...`: computed from the top level folder for an id (e.g. guide, tutorial, etc)
|
||||||
* * `view-...`: computef from the navigation view (e.g. SideNav, TopBar, etc)
|
* * `view-...`: computef from the navigation view (e.g. SideNav, TopBar, etc)
|
||||||
*/
|
*/
|
||||||
@ -76,8 +76,8 @@ export class AppComponent implements OnInit {
|
|||||||
|
|
||||||
get homeImageUrl() {
|
get homeImageUrl() {
|
||||||
return this.isSideBySide ?
|
return this.isSideBySide ?
|
||||||
'assets/images/logos/standard/logo-nav@2x.png' :
|
'assets/images/logos/angular/logo-nav@2x.png' :
|
||||||
'assets/images/logos/standard/shield-large.svg';
|
'assets/images/logos/angular/shield-large.svg';
|
||||||
}
|
}
|
||||||
get isOpened() { return this.isSideBySide && this.isSideNavDoc; }
|
get isOpened() { return this.isSideBySide && this.isSideNavDoc; }
|
||||||
get mode() { return this.isSideBySide ? 'side' : 'over'; }
|
get mode() { return this.isSideBySide ? 'side' : 'over'; }
|
||||||
@ -111,8 +111,8 @@ export class AppComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
// Do not initialize the search on browsers that lack web worker support
|
// Do not initialize the search on browsers that lack web worker support
|
||||||
if ('Worker' in window) {
|
if ('Worker' in window) {
|
||||||
this.searchService.initWorker('app/search/search-worker.js');
|
// Delay initialization by up to 2 seconds
|
||||||
this.searchService.loadIndex();
|
this.searchService.initWorker('app/search/search-worker.js', 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onResize(window.innerWidth);
|
this.onResize(window.innerWidth);
|
||||||
|
@ -65,6 +65,13 @@ describe('CodeExampleComponent', () => {
|
|||||||
expect(actual).toBe('Great Example');
|
expect(actual).toBe('Great Example');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should remove the `title` attribute after initialisation', () => {
|
||||||
|
TestBed.overrideComponent(HostComponent, {
|
||||||
|
set: {template: '<code-example title="Great Example"></code-example>'}});
|
||||||
|
createComponent(oneLineCode);
|
||||||
|
expect(codeExampleDe.nativeElement.getAttribute('title')).toEqual(null);
|
||||||
|
});
|
||||||
|
|
||||||
it('should pass hideCopy to CodeComonent', () => {
|
it('should pass hideCopy to CodeComonent', () => {
|
||||||
TestBed.overrideComponent(HostComponent, {
|
TestBed.overrideComponent(HostComponent, {
|
||||||
set: {template: '<code-example hideCopy="true"></code-example>'}});
|
set: {template: '<code-example hideCopy="true"></code-example>'}});
|
||||||
|
@ -45,6 +45,8 @@ export class CodeExampleComponent implements OnInit {
|
|||||||
this.path = element.getAttribute('path') || '';
|
this.path = element.getAttribute('path') || '';
|
||||||
this.region = element.getAttribute('region') || '';
|
this.region = element.getAttribute('region') || '';
|
||||||
this.title = element.getAttribute('title') || '';
|
this.title = element.getAttribute('title') || '';
|
||||||
|
// Now remove the title attribute to prevent unwanted tooltip popups when hovering over the code.
|
||||||
|
element.removeAttribute('title');
|
||||||
|
|
||||||
this.isAvoid = this.path.indexOf('.avoid.') !== -1;
|
this.isAvoid = this.path.indexOf('.avoid.') !== -1;
|
||||||
this.hideCopy = this.isAvoid || getBoolFromAttribute(element, ['hidecopy', 'hide-copy']);
|
this.hideCopy = this.isAvoid || getBoolFromAttribute(element, ['hidecopy', 'hide-copy']);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { async, ComponentFixture, TestBed, inject } from '@angular/core/testing';
|
import { ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { SearchBoxComponent } from './search-box.component';
|
import { SearchBoxComponent } from './search-box.component';
|
||||||
import { MockSearchService } from 'testing/search.service';
|
import { MockSearchService } from 'testing/search.service';
|
||||||
@ -36,30 +36,67 @@ describe('SearchBoxComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('initialisation', () => {
|
describe('initialisation', () => {
|
||||||
it('should get the current search query from the location service', inject([LocationService], (location: MockLocationService) => {
|
it('should get the current search query from the location service',
|
||||||
|
inject([LocationService], (location: MockLocationService) => fakeAsync(() => {
|
||||||
location.search.and.returnValue({ search: 'initial search' });
|
location.search.and.returnValue({ search: 'initial search' });
|
||||||
component.ngOnInit();
|
component.ngOnInit();
|
||||||
expect(location.search).toHaveBeenCalled();
|
expect(location.search).toHaveBeenCalled();
|
||||||
|
tick(300);
|
||||||
expect(host.searchHandler).toHaveBeenCalledWith('initial search');
|
expect(host.searchHandler).toHaveBeenCalledWith('initial search');
|
||||||
expect(component.searchBox.nativeElement.value).toEqual('initial search');
|
expect(component.searchBox.nativeElement.value).toEqual('initial search');
|
||||||
|
})));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onSearch', () => {
|
||||||
|
it('should debounce by 300ms', fakeAsync(() => {
|
||||||
|
component.doSearch();
|
||||||
|
expect(host.searchHandler).not.toHaveBeenCalled();
|
||||||
|
tick(300);
|
||||||
|
expect(host.searchHandler).toHaveBeenCalled();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should pass through the value of the input box', fakeAsync(() => {
|
||||||
|
const input = fixture.debugElement.query(By.css('input'));
|
||||||
|
input.nativeElement.value = 'some query (input)';
|
||||||
|
component.doSearch();
|
||||||
|
tick(300);
|
||||||
|
expect(host.searchHandler).toHaveBeenCalledWith('some query (input)');
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should only send events if the search value has changed', fakeAsync(() => {
|
||||||
|
const input = fixture.debugElement.query(By.css('input'));
|
||||||
|
|
||||||
|
input.nativeElement.value = 'some query';
|
||||||
|
component.doSearch();
|
||||||
|
tick(300);
|
||||||
|
expect(host.searchHandler).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
component.doSearch();
|
||||||
|
tick(300);
|
||||||
|
expect(host.searchHandler).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
input.nativeElement.value = 'some other query';
|
||||||
|
component.doSearch();
|
||||||
|
tick(300);
|
||||||
|
expect(host.searchHandler).toHaveBeenCalledTimes(2);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('on input', () => {
|
describe('on input', () => {
|
||||||
it('should trigger the onSearch event', () => {
|
it('should trigger a search', () => {
|
||||||
const input = fixture.debugElement.query(By.css('input'));
|
const input = fixture.debugElement.query(By.css('input'));
|
||||||
input.nativeElement.value = 'some query (input)';
|
spyOn(component, 'doSearch');
|
||||||
input.triggerEventHandler('input', { });
|
input.triggerEventHandler('input', { });
|
||||||
expect(host.searchHandler).toHaveBeenCalledWith('some query (input)');
|
expect(component.doSearch).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('on keyup', () => {
|
describe('on keyup', () => {
|
||||||
it('should trigger the onSearch event', () => {
|
it('should trigger a search', () => {
|
||||||
const input = fixture.debugElement.query(By.css('input'));
|
const input = fixture.debugElement.query(By.css('input'));
|
||||||
input.nativeElement.value = 'some query (keyup)';
|
spyOn(component, 'doSearch');
|
||||||
input.triggerEventHandler('keyup', { });
|
input.triggerEventHandler('keyup', { });
|
||||||
expect(host.searchHandler).toHaveBeenCalledWith('some query (keyup)');
|
expect(component.doSearch).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -73,28 +110,11 @@ describe('SearchBoxComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('on click', () => {
|
describe('on click', () => {
|
||||||
it('should trigger the search event', () => {
|
it('should trigger a search', () => {
|
||||||
const input = fixture.debugElement.query(By.css('input'));
|
const input = fixture.debugElement.query(By.css('input'));
|
||||||
input.nativeElement.value = 'some query (click)';
|
spyOn(component, 'doSearch');
|
||||||
input.triggerEventHandler('click', { });
|
input.triggerEventHandler('click', { });
|
||||||
expect(host.searchHandler).toHaveBeenCalledWith('some query (click)');
|
expect(component.doSearch).toHaveBeenCalled();
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('event filtering', () => {
|
|
||||||
it('should only send events if the search value has changed', () => {
|
|
||||||
const input = fixture.debugElement.query(By.css('input'));
|
|
||||||
|
|
||||||
input.nativeElement.value = 'some query';
|
|
||||||
input.triggerEventHandler('input', { });
|
|
||||||
expect(host.searchHandler).toHaveBeenCalledTimes(1);
|
|
||||||
|
|
||||||
input.triggerEventHandler('input', { });
|
|
||||||
expect(host.searchHandler).toHaveBeenCalledTimes(1);
|
|
||||||
|
|
||||||
input.nativeElement.value = 'some other query';
|
|
||||||
input.triggerEventHandler('input', { });
|
|
||||||
expect(host.searchHandler).toHaveBeenCalledTimes(2);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -26,10 +26,11 @@ import 'rxjs/add/operator/distinctUntilChanged';
|
|||||||
})
|
})
|
||||||
export class SearchBoxComponent implements OnInit {
|
export class SearchBoxComponent implements OnInit {
|
||||||
|
|
||||||
|
private searchDebounce = 300;
|
||||||
private searchSubject = new Subject<string>();
|
private searchSubject = new Subject<string>();
|
||||||
|
|
||||||
@ViewChild('searchBox') searchBox: ElementRef;
|
@ViewChild('searchBox') searchBox: ElementRef;
|
||||||
@Output() onSearch = this.searchSubject.distinctUntilChanged();
|
@Output() onSearch = this.searchSubject.distinctUntilChanged().debounceTime(this.searchDebounce);
|
||||||
@Output() onFocus = new EventEmitter<string>();
|
@Output() onFocus = new EventEmitter<string>();
|
||||||
|
|
||||||
constructor(private locationService: LocationService) { }
|
constructor(private locationService: LocationService) { }
|
||||||
|
@ -1,24 +1,62 @@
|
|||||||
import { ReflectiveInjector, NgZone } from '@angular/core';
|
import { ReflectiveInjector, NgZone } from '@angular/core';
|
||||||
|
import { fakeAsync, tick } from '@angular/core/testing';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { SearchService } from './search.service';
|
import { SearchService } from './search.service';
|
||||||
|
import { WebWorkerClient } from 'app/shared/web-worker';
|
||||||
|
|
||||||
describe('SearchService', () => {
|
describe('SearchService', () => {
|
||||||
|
|
||||||
let injector: ReflectiveInjector;
|
let injector: ReflectiveInjector;
|
||||||
|
let service: SearchService;
|
||||||
|
let sendMessageSpy: jasmine.Spy;
|
||||||
|
let mockWorker: WebWorkerClient;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
sendMessageSpy = jasmine.createSpy('sendMessage').and.returnValue(Observable.of({}));
|
||||||
|
mockWorker = { sendMessage: sendMessageSpy } as any;
|
||||||
|
spyOn(WebWorkerClient, 'create').and.returnValue(mockWorker);
|
||||||
|
|
||||||
injector = ReflectiveInjector.resolveAndCreate([
|
injector = ReflectiveInjector.resolveAndCreate([
|
||||||
SearchService,
|
SearchService,
|
||||||
{ provide: NgZone, useFactory: () => new NgZone({ enableLongStackTrace: false }) }
|
{ provide: NgZone, useFactory: () => new NgZone({ enableLongStackTrace: false }) }
|
||||||
]);
|
]);
|
||||||
|
service = injector.get(SearchService);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('loadIndex', () => {
|
describe('initWorker', () => {
|
||||||
it('should send a "load-index" message to the worker');
|
it('should create the worker and load the index after the specified delay', fakeAsync(() => {
|
||||||
it('should connect the `ready` property to the response to the "load-index" message');
|
service.initWorker('some/url', 100);
|
||||||
|
expect(WebWorkerClient.create).not.toHaveBeenCalled();
|
||||||
|
expect(mockWorker.sendMessage).not.toHaveBeenCalled();
|
||||||
|
tick(100);
|
||||||
|
expect(WebWorkerClient.create).toHaveBeenCalledWith('some/url', jasmine.any(NgZone));
|
||||||
|
expect(mockWorker.sendMessage).toHaveBeenCalledWith('load-index');
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('search', () => {
|
describe('search', () => {
|
||||||
it('should send a "query-index" message to the worker');
|
beforeEach(() => {
|
||||||
it('should push the response to the `searchResults` observable');
|
// We must initialize the service before calling search
|
||||||
|
service.initWorker('some/url', 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should trigger a `loadIndex` synchronously', () => {
|
||||||
|
service.search('some query');
|
||||||
|
expect(mockWorker.sendMessage).toHaveBeenCalledWith('load-index');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send a "query-index" message to the worker', () => {
|
||||||
|
service.search('some query');
|
||||||
|
expect(mockWorker.sendMessage).toHaveBeenCalledWith('query-index', 'some query');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should push the response to the `searchResults` observable', () => {
|
||||||
|
const mockSearchResults = { results: ['a', 'b'] };
|
||||||
|
(mockWorker.sendMessage as jasmine.Spy).and.returnValue(Observable.of(mockSearchResults));
|
||||||
|
let searchResults: any;
|
||||||
|
service.searchResults.subscribe(results => searchResults = results);
|
||||||
|
service.search('some query');
|
||||||
|
expect(searchResults).toEqual(mockSearchResults);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -7,8 +7,10 @@ can be found in the LICENSE file at http://angular.io/license
|
|||||||
import { NgZone, Injectable, Type } from '@angular/core';
|
import { NgZone, Injectable, Type } from '@angular/core';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { ReplaySubject } from 'rxjs/ReplaySubject';
|
import { ReplaySubject } from 'rxjs/ReplaySubject';
|
||||||
import 'rxjs/add/operator/publishLast';
|
import 'rxjs/add/observable/race';
|
||||||
|
import 'rxjs/add/observable/timer';
|
||||||
import 'rxjs/add/operator/concatMap';
|
import 'rxjs/add/operator/concatMap';
|
||||||
|
import 'rxjs/add/operator/publish';
|
||||||
import { WebWorkerClient } from 'app/shared/web-worker';
|
import { WebWorkerClient } from 'app/shared/web-worker';
|
||||||
|
|
||||||
export interface SearchResults {
|
export interface SearchResults {
|
||||||
@ -27,26 +29,50 @@ export interface SearchResult {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SearchService {
|
export class SearchService {
|
||||||
private worker: WebWorkerClient;
|
private searchesSubject = new ReplaySubject<string>(1);
|
||||||
private ready: Observable<boolean>;
|
searchResults: Observable<SearchResults>;
|
||||||
private resultsSubject = new ReplaySubject<SearchResults>(1);
|
|
||||||
readonly searchResults = this.resultsSubject.asObservable();
|
|
||||||
|
|
||||||
constructor(private zone: NgZone) {}
|
constructor(private zone: NgZone) {}
|
||||||
|
|
||||||
initWorker(workerUrl) {
|
/**
|
||||||
this.worker = new WebWorkerClient(new Worker(workerUrl), this.zone);
|
* Initialize the search engine. We offer an `initDelay` to prevent the search initialisation from delaying the
|
||||||
}
|
* initial rendering of the web page. Triggering a search will override this delay and cause the index to be
|
||||||
|
* loaded immediately.
|
||||||
loadIndex() {
|
*
|
||||||
const ready = this.ready = this.worker.sendMessage<boolean>('load-index').publishLast();
|
* @param workerUrl the url of the WebWorker script that runs the searches
|
||||||
// trigger the index to be loaded immediately
|
* @param initDelay the number of milliseconds to wait before we load the WebWorker and generate the search index
|
||||||
ready.connect();
|
*/
|
||||||
|
initWorker(workerUrl: string, initDelay: number) {
|
||||||
|
const searchResults = Observable
|
||||||
|
// Wait for the initDelay or the first search
|
||||||
|
.race(
|
||||||
|
Observable.timer(initDelay),
|
||||||
|
this.searchesSubject.first()
|
||||||
|
)
|
||||||
|
.concatMap(() => {
|
||||||
|
// Create the worker and load the index
|
||||||
|
const worker = WebWorkerClient.create(workerUrl, this.zone);
|
||||||
|
return worker.sendMessage('load-index').concatMap(() =>
|
||||||
|
// Once the index has loaded, switch to listening to the searches coming in
|
||||||
|
this.searchesSubject.switchMap((query) =>
|
||||||
|
// Each search gets switched to a web worker message, whose results are returned via an observable
|
||||||
|
worker.sendMessage<SearchResults>('query-index', query)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}).publish();
|
||||||
|
|
||||||
|
// Connect to the observable to kick off the timer
|
||||||
|
searchResults.connect();
|
||||||
|
|
||||||
|
// Expose the connected observable to the rest of the world
|
||||||
|
this.searchResults = searchResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a search query to the index.
|
||||||
|
* The results will appear on the `searchResults` observable.
|
||||||
|
*/
|
||||||
search(query: string) {
|
search(query: string) {
|
||||||
this.ready.concatMap(ready => {
|
this.searchesSubject.next(query);
|
||||||
return this.worker.sendMessage('query-index', query) as Observable<SearchResults>;
|
|
||||||
}).subscribe(results => this.resultsSubject.next(results));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,11 @@ export interface WebWorkerMessage {
|
|||||||
export class WebWorkerClient {
|
export class WebWorkerClient {
|
||||||
private nextId = 0;
|
private nextId = 0;
|
||||||
|
|
||||||
constructor(private worker: Worker, private zone: NgZone) {
|
static create(workerUrl: string, zone: NgZone) {
|
||||||
|
return new WebWorkerClient(new Worker(workerUrl), zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
private constructor(private worker: Worker, private zone: NgZone) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessage<T>(type: string, payload?: any): Observable<T> {
|
sendMessage<T>(type: string, payload?: any): Observable<T> {
|
||||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
BIN
aio/src/assets/images/backgrounds/_unused/ng-pattern-lg.png
Normal file
After Width: | Height: | Size: 178 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
BIN
aio/src/assets/images/backgrounds/_unused/ng-pattern-sm.png
Normal file
After Width: | Height: | Size: 59 KiB |