Compare commits

...

114 Commits

Author SHA1 Message Date
61b1425aed release: cut the v10.2.0 release 2020-10-21 17:42:17 +00:00
71fb99f062 fix(platform-server): Resolve absolute URL from baseUrl (#39334)
This commit fixes a bug when `useAbsoluteUrl` is set to true and
`ServerPlatformLocation` infers the base url from the supplied
`url`. User should explicitly set the `baseUrl` when they turn on
`useAbsoluteUrl`.

Breaking change:
If you use `useAbsoluteUrl` to setup `platform-server`, you now need to
also specify `baseUrl`.
We are intentionally making this a breaking change in a minor release,
because if `useAbsoluteUrl` is set to `true` then the behavior of the
application could be unpredictable, resulting in issues that are hard to
discover but could be affecting production environments.

PR Close #39334

(cherry picked from commit 7768aeb62f)
2020-10-21 09:46:22 -07:00
7ca17a6249 build(docs-infra): upgrade cli command docs sources to cba6d86ca (#39360)
Updating [angular#10.1.x](https://github.com/angular/angular/tree/10.1.x) from
[cli-builds#10.1.x](https://github.com/angular/cli-builds/tree/10.1.x).

##
Relevant changes in
[commit range](ab97bc382...cba6d86ca):

**Modified**
- help/build.json
- help/generate.json
- help/test.json
- help/xi18n.json

PR Close #39360
2020-10-21 08:27:13 -07:00
3cce723370 docs: remove style commit type from CONTRIBUTING.md (#39357)
Commit type Style is still present in Commiit Message Header while it shouldn't

PR Close #39357
2020-10-21 08:25:31 -07:00
b7bf5258ce docs: edit property binding doc (#38799)
This commit edits the property binding doc copy and adds some
docregions to clarify explanations.

PR Close #38799
2020-10-21 08:23:44 -07:00
823200c6c1 docs: Add Component Overview topic to angular.io (#39186)
PR Close #39186
2020-10-20 10:47:45 -07:00
cd8ec3d902 docs: add Jessica Janiuk to contributors.json (#39253)
PR Close #39253
2020-10-19 16:25:18 -07:00
02b87505ee docs: clarify grammatical error (#39279)
The sentence is grammatically incorrect. The new sentence fixes the error.
PR Close #39279
2020-10-19 14:32:42 -07:00
32a8e72a14 feat(dev-infra): prompt caretaker to confirm the merge branches on merge (#39333)
Perviously, it was not immediately clear what branches a PR would merge
into during the merge process.  This prompt allows for caretakers to
understand and acknowledge where the PR will merge to.

PR Close #39333
2020-10-19 12:06:17 -07:00
7827d3ee73 docs: change definition of NgModules in Angular concepts guide (#36179)
Indicate that the basic building block in Angular is the component which is organized into modules

PR Close #36179
2020-10-19 11:22:32 -07:00
38db976617 docs: add Johannes Hoppe to GDE resources (#34694)
PR Close #34694
2020-10-19 08:04:58 -07:00
d8632ed541 docs: add Ferdinand Malcher to GDE resources (#34694)
PR Close #34694
2020-10-19 08:04:58 -07:00
10db99588f refactor(docs-infra): fix strictTemplates failures in accessibility docs example (#39248)
fix `strictTemplates` failures in `accessibility` docs example

PR Close #39248
2020-10-16 16:09:08 -07:00
8fd59dabba ci: separate the windows CI tests into build and test (#39289)
Because the compiler-cli tests modify node_modules, this can cause
failures on windows CI specifically as node_modules are symlinked
to rather than copied.  By running the test and build actions in
separate commands, all of the tests are built to be executed before
and tests are executed and modify the node_modules content.

PR Close #39289
2020-10-16 14:22:23 -07:00
d8e313bb6d docs: edit attribute-binding doc and move colSpan note to property binding (#38860)
This commit edits the copy of the attribute binding documentation, moves the
colspan section that is primarily about property binding to the property
binding document, and adds a docregion to the attribute-binding
example to help clarify a point in the document.
Part of the copy edit reformats the style precedence list in tabular format
so that it is easier to read and understand.

PR Close #38860
2020-10-16 10:06:17 -07:00
c602c9bdc6 docs: Typos fixes in built-in directives guide (#38520)
PR Close #38520
2020-10-16 10:05:27 -07:00
4a5f17cd8e build(docs-infra): add a tool to create new examples (#39283)
This tool can be run from anywhere in the aio folder as:

```sh
yarn create-example <example-name>
```

It will create some basic scaffold files to get the example started.
After creation the developer should then use `yarn boilerplate:add`
or similar to ensure that the example can be run and tested.

You can optionally provide an absolute path to a pre-existing CLI
project and it will copy over appropriate files (ignoring boilerplate)
to the newly created example.

```sh
yarn create-example <example-name> /path/to/other/cli/project
```

Fixes #39275

PR Close #39283
2020-10-16 08:14:40 -07:00
02405f1406 fix(core): guard reading of global ngDevMode for undefined. (#36055)
When reading globals such as `ngDevMode` the read should be guarded by `typeof ngDevMode` otherwise it will throw if not
defined in `"use strict"` mode.

PR Close #36055
2020-10-16 08:12:24 -07:00
94d7ef3909 refactor(core): renames checkNoChangesMode to be clearer (#39277)
getCheckNoChangesMode was discovered to be unclear as to the purpose of
it. This refactor is a simple renaming to make it much clearer what that
method and property does.

PR Close #39277
2020-10-15 17:01:22 -07:00
4fd70a2bf3 docs: Very minor spelling mistake (#39299)
1659: teh -> the
PR Close #39299
2020-10-15 17:00:20 -07:00
af170384b4 docs: fix typo at console.log (#39252)
PR Close #39252
2020-10-15 14:15:37 -07:00
95fcb4164f docs(core): fix typo in the "Template statements" guide (#39244)
PR Close #39244
2020-10-15 14:14:26 -07:00
f90c1f77d8 refactor(dev-infra): remove branches created for g3 comparison (#39137)
Previously, temporary branches were created to be used for comparison to
the g3 branch, instead comparisons are now done using the branches
latest shas.

PR Close #39137
2020-10-15 14:11:32 -07:00
6efbc8b58c docs: update readme (#32084)
PR Close #32084
2020-10-15 14:08:19 -07:00
33c7d23fdd docs: Move pipes documentation from Components to Templates (#38983)
PR Close #38983
2020-10-15 14:07:29 -07:00
670fac0ace docs: deprecate displaying data in views topic (#38885)
The Displaying Data in Views topic is actually a small tutorial
that describes Angular features such as interpolation and
structural directives. These content is already covered in
our getting started tutorial and in Tour of Heroes.

This change adds redirects to the Template Syntax section
of the Getting Started tutorial and deletes displaying-data.md.

PR Close #38885
2020-10-15 14:05:29 -07:00
9baa85f83b ci: add jessicajaniuk to require-minimum-review reviewers (#39268)
Add jessicajaniuk@ to the list of reviewers included in the required
minimum reviewers list.

PR Close #39268
2020-10-15 11:06:05 -07:00
72cdd42278 docs: Update output directory name in Deployment guide (#39247)
The default output directory is no longer `dist/` but `dist/project-name/`
PR Close #39247
2020-10-15 09:08:24 -07:00
591fa51a6f docs: fix broken link (#39256)
PR Close #39256
2020-10-14 14:10:59 -07:00
1623f5d817 refactor(core): use relative import paths in micro benchmarks (#39142)
This commit updates micro benchmarks to use relative path to Ivy runtime code. Keeping absolute
locations caused issues with build optimizer that retained certain symbols and they appeared in the
output twice.

PR Close #39142
2020-10-14 14:10:14 -07:00
4207cff04f test(core): add micro benchmarks for i18n scenarios (#39142)
This commit adds micro benchmarks to run micro benchmarks for i18n-related logic in the
following scenarios:

- i18n static attributes
- i18n attributes with interpolations
- i18n blocks of static text
- i18n blocks of text + interpolations
- simple ICUs
- nested ICUs

First 4 scenarios also have baseline scenarios (non-i18n) so that we can compare i18n perf with
non-i18n logic.

PR Close #39142
2020-10-14 14:10:14 -07:00
f591fc8d53 ci: setup windows from scratch (#39139)
Rather than setting up windows by relying on attaching the saved workspace
failes from the previous step, instead checkout and install the yarn items
within the windows steps.  Additionally, since the bazel remote cache is
used and relied on, saving the cached results of the bazel runs to be resumed
on subsequent runs does not provide enough value to make it worth the time
consumed.

PR Close #39139
2020-10-14 14:09:50 -07:00
c558c02e9e ci: run windows CI jobs on PRs (#39139)
Previously windows CI jobs were only run on upstream branches, with the addition
of larger Windows executors as well as the improvement of setup speed in the
windows environment setup script allows for the windows tests to pass in a
reasonable timeframe.

PR Close #39139
2020-10-14 14:09:50 -07:00
2664338582 docs: update marketing home loved-by-millions svg (#39105)
docs: include entire worldmap

docs: feedback changes on loved-by-millions

PR Close #39105
2020-10-14 14:09:26 -07:00
5db7b4c354 release: cut the v10.1.6 release 2020-10-14 13:33:19 -07:00
e08d02145e fix(ngcc): ensure that "inline exports" can be interpreted correctly (#39272)
Previously, inline exports of the form `exports.foo = <implementation>;` were
being interpreted (by the ngtsc `PartialInterpeter`) as `Reference` objects.
This is not what is desired since it prevents the value of the export
from being unpacked, such as when analyzing `NgModule` declarations:

```
exports.directives = [Directive1, Directive2];

@NgImport({declarations: [exports.directives]})
class AppModule {}
```

In this example the interpreter would think that `exports.directives`
was a reference rather than an array that needs to be unpacked.

This bug was picked up by the ngcc-validation repository. See
https://github.com/angular/ngcc-validation/pull/1990 and
https://circleci.com/gh/angular/ngcc-validation/17130

PR Close #39272
2020-10-14 12:59:07 -07:00
dae3a77c43 refactor(compiler-cli): visit inline declarations with implementations differently (#39272)
Some inline declarations are of the form:

```
exports.<name> = <implementation>;
```

In this case the declaration `node` is `exports.<name>`.
When interpreting such inline declarations we actually want
to visit the `implementation` expression rather than visiting
the declaration `node`.

This commit adds `implementation?: ts.Expression` to the
`InlineDeclaration` type and updates the interpreter to visit
these expressions as described above.

PR Close #39272
2020-10-14 12:59:07 -07:00
02e75df3e7 refactor(compiler-cli): ensure isNamed....() helpers check name is identity (#38959) (#39272)
Previously the `node.name` property was only checked to ensure it was
defined. But that meant that it was a `ts.BindingName`, which also includes
`ts.BindingPattern`, which we do not support. But these helper methods were
forcefully casting the value to `ts.Identifier.

Now we also check that the `node.name` is actually an `ts.Identifier`.

PR Close #38959

PR Close #39272
2020-10-14 12:59:07 -07:00
f752ab9367 fix(compiler-cli): support namespaced query types in directives (#38959) (#39272)
Previously directive "queries" that relied upon a namespaced type

```ts
queries: {
  'mcontent': new core.ContentChild('test2'),
}
```

caused an error to be thrown. This is now supported.

PR Close #38959

PR Close #39272
2020-10-14 12:59:07 -07:00
9c875b30dc fix(ngcc): support inline export declarations in UMD files (#38959) (#39272)
Previously, any declarations that were defined "inline" were not
recognised by the `UmdReflectionHost`.

For example, the following syntax was completely unrecognized:

```ts
var Foo_1;
exports.Foo = Foo_1 = (function() {
  function Foo() {}
  return Foo;
})();
exports.Foo = Foo_1 = __decorate(SomeDecorator, Foo);
```

Such inline classes were ignored and not processed by ngcc.

This lack of processing led to failures in Ivy applications that relied
on UMD formats of libraries such as `syncfusion/ej2-angular-ui-components`.

Now all known inline UMD exports are recognized and processed accordingly.

Fixes #38947

PR Close #38959

PR Close #39272
2020-10-14 12:59:07 -07:00
8fa78d10ab test(ngcc): use isNamedDeclaration() helper to simplify tests (#38959) (#39272)
Previously these tests were checking multiple specific expression
types. The new helper function is more general and will also support
`PropertyAccessExpression` nodes for `InlineDeclaration` types.

PR Close #38959

PR Close #39272
2020-10-14 12:59:07 -07:00
26988f0d62 refactor(compiler-cli): implement DeclarationNode node type (#38959) (#39272)
Previously the `ConcreteDeclaration` and `InlineDeclaration` had
different properties for the underlying node type. And the `InlineDeclaration`
did not store a value that represented its declaration.

It turns out that a natural declaration node for an inline type is the
expression. For example in UMD/CommonJS this would be the `exports.<name>`
property access node.

So this expression is now used for the `node` of `InlineDeclaration` types
and the `expression` property is dropped.

To support this the codebase has been refactored to use a new `DeclarationNode`
type which is a union of `ts.Declaration|ts.Expression` instead of `ts.Declaration`
throughout.

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
6acf117386 test(ngcc): use isNamedFunctionDeclaration() in UMD tests (#38959) (#39272)
This makes these tests more resilient to changes in the test code
structure. For example switching from

```
var SomeClass = <implementation>;
exports.SomeClass = SomeClass;
```

to

```
exports.SomeClass = <implementation>;
```

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
8b731e374d test(compiler-cli): make the getDeclaration() utility more resilient to code format (#38959) (#39272)
Previously `getDeclaration()` would only return the first node that matched
the name passed in and then assert the predicate on this single node.
It also only considered a subset of possible declaration types that we might
care about.

Now the function will parse the whole tree collecting an array of all the
nodes that match the name. It then filters this array based on the predicate
and only errors if the filtered array is empty.

This makes this function much more resilient to more esoteric code formats
such as UMD.

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
5378f78e79 refactor(ngcc): simplify and break up ES2015 functions with helpers (#38959) (#39272)
The protected helper functions can then be overridden by subclasses of the
Esm2015ReflectionHost.

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
495c40e31c refactor(ngcc): simplify and rename getClassDeclarationFromInnerDeclaration() (#38959) (#39272)
The new function does not try to restrict the kind of AST node that it
finds, leaving that to the caller. This will make it more resuable in the
UMD reflection host.

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
9963c5d8f7 fix(ngcc): handle aliases in UMD export declarations (#38959) (#39272)
Sometimes UMD exports appear in the following form:

```
exports.MyClass = alias1 = alias2 = <<declaration>>
```

Previously the declaration of the export would have been captured
as `alias1 = alias2 = <<declaration>>`, which the `PartialInterpreter`
would have failed on, since it cannot handle assignments.

Now we skip over these aliases capturing only the `<<declaration>>`
expression.

Fixes #38947

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
13c4a7b1da fix(ngcc): map exports to the current module in UMD files (#38959) (#39272)
UMD files export values by assigning them to an `exports` variable.
When evaluating expressions ngcc was failing to cope with expressions
like `exports.MyComponent`.

This commit fixes the `UmdReflectionHost.getDeclarationOfIdentifier()`
method to map the `exports` variable to the current source file.

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
70e85d226c test(ngcc): fix incorrect test setup (#38959) (#39272)
The `SIMPLE_CLASS_FILE` contained a `ChildClass` that had an
internal aliases implementation and extended a `SuperClass` base
class. The call to `__extends` was using the wrong argument for
the child class.

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
dfb129dbfa refactor(compiler-cli): move map creation to avoid unnecessary work (#38959) (#39272)
If the `symbol` for the given `node` does not exist then there is no
point in creating the `map`.

PR Close #38959

PR Close #39272
2020-10-14 12:59:06 -07:00
1a1407aef6 refactor(ngcc): rename ExportStatement to ExportsStatement (#38959) (#39272)
This clarifies that this is specifically about statements of the form
`exports.<name> = <declaration>`, rather than a general export
statement such as `export class <ClassName> { ... }`.

PR Close #38959

PR Close #39272
2020-10-14 12:59:05 -07:00
da71f76a6a refactor(ngcc): remove unused imports (#38959) (#39272)
The `isAssignment` and `isAssignmentStatement` are not used in this file.

PR Close #38959

PR Close #39272
2020-10-14 12:59:05 -07:00
0c9b76e9e7 refactor(compiler-cli): remove unnecessary constraint on isDeclarationReference() (#38959) (#39272)
There is no need to check that the `ref.node` is of any particular type
because immediately after this check the entry is tested to see if it passes
`isClassDeclarationReference()`.

The only difference is that the error that is reported is slightly different
in the case that it is a `ref` but not one of the TS node types.

Previously:

```
`Value at position ${idx} in the NgModule.${arrayName} of ${
                className} is not a reference`
```

now

```
`Value at position ${idx} in the NgModule.${arrayName} of ${
                  className} is not a class`
```

Arguably the previous message was wrong, since this entry IS a reference
but is not a class.

PR Close #38959

PR Close #39272
2020-10-14 12:59:05 -07:00
db34b23ab5 test(compiler-cli): improve error message if a unit test is bad (#38959) (#39272)
The message now also reports the name of the predicate function
that failed.

PR Close #38959

PR Close #39272
2020-10-14 12:59:05 -07:00
df0941554b docs: add Discord as an official communication channel (#39149)
PR Close #39149
2020-10-14 10:23:16 -07:00
5221df8e92 perf(ngcc): do not rescan program source files when referenced from multiple root files (#39254)
When ngcc is configured to run with the `--use-program-dependencies`
flag, as is the case in the CLI's asynchronous processing, it will scan
all source files in the program, starting from the program's root files
as configured in the tsconfig. Each individual root file could
potentially rescan files that had already been scanned for an earlier
root file, causing a severe performance penalty if the number of root
files is large. This would be the case if glob patterns are used in the
"include" specification of a tsconfig file.

This commit avoids the performance penalty by keeping track of the files
that have been scanned across all root files, such that no source file
is scanned multiple times.

Fixes #39240

PR Close #39254
2020-10-14 09:34:11 -07:00
bc35c6a8ed refactor(dev-infra): Adjust caretaker queries (#39257)
- The current initial triage does not include PRs. This includes them by removing the issue filter
- The merge assistance label is often applied to PRs that do not have
status=success. Caretaker should handle these as well

PR Close #39257
2020-10-14 09:07:05 -07:00
23fc2b43ac updated sajee's profile (#39019)
PR Close #39019
2020-10-13 14:59:04 -07:00
c16995eb59 docs: fix typo in the Reactive Forms guide #5 (#39245)
PR Close #39245
2020-10-13 13:38:29 -07:00
3487d5a13a docs: move Inputs and Outputs topic to Components section (#38984)
PR Close #38984
2020-10-12 12:40:50 -07:00
1efc75cd72 fix(dev-infra): detect all commit message keywords that can close a PR (#39229)
Previously, the `isCommitClosingPullRequest()` method (used in
`ng-dev release` to detect whether a commit is closing a PR based on
keywords found in the commit message) was only able to detect a subset
of the keywords supported by GitHub.

This is fine currently, because the merge script adds `PR Close #XYZ`
when merging a PR, but it might break in the future.

This commit makes the code more robust by ensuring the method can detect
all keywords supported by GitHub for automatically closing a PR based on
a commit message.

Original discussion:
https://github.com/angular/angular/pull/39135#discussion_r503440973

PR Close #39229
2020-10-12 12:02:49 -07:00
c4190e3142 fix(dev-infra): fix error message in invokeSetNpmDistCommand() function (#39229)
In #39135, the commit message string was accidentally changed from a
template literal to a regular string literal. This prevented the
`npmDistTag` variable from being correctly displayed in the error
message.

This commit fixes it by switching it back to a template literal.

NOTE:
This was pointed out in
https://github.com/angular/angular/pull/39135#discussion_r503361412, but
the PR was accidentally merged before the review feedback had been
addressed.

PR Close #39229
2020-10-12 12:02:49 -07:00
5d98834585 fix(dev-infra): correctly check for commit that closes PR (#39135)
The `ng-dev release publish` command needs to check whether a commit
closed a pull request. This is implemented via checking the commit
message for specific closing keywords referencing the pull request
number.

The regex used previously failed to correctly ensure that the specified
pull request was referenced. For example, it would allow `#12345` to
also match for `#1234`.

This commit fixes the regex.

PR Close #39135
2020-10-12 10:47:14 -07:00
529ff73200 refactor(dev-infra): several code style and typo fixes (#39135)
This commit addresses comments from [my review][1] on PR #38656 (which
was merged without comments addressed). The changes are mostly related
to code style and typos.

[1]: https://github.com/angular/angular/pull/38656#pullrequestreview-482129333

PR Close #39135
2020-10-12 10:47:14 -07:00
791205005c refactor(animations): do not assign to innerHTML (#37397)
This should not change behavior, but it prevents false-positive warnings in various static analysis
tools, including tools used internally at Google.

PR Close #37397
2020-10-12 10:45:00 -07:00
2d37e47e95 build(docs-infra): support passing args to ng serve via serve-and-sync (#39201)
When working on the docs, it is helpful to run a local instance of the
angular.io app and run scripts that watch both the docs contents and the
app build artifacts to automatically update the running instance on
changes. Typically, this is achieved via the `start` and `docs-watch`
npm scripts. As a convenience, one can run the `serve-and-sync` script,
which runs both in one terminal.

Previously, it was not possible to pass arguments to `ng nerve` (which
is what the `start` script runs under the hood) when running it via
`serve-and-sync`.

This commit adds support for passing any arguments passed to
`serve-and-sync` through to the `start` script. This can be useful for
things like specifying a custom host or port.

PR Close #39201
2020-10-12 08:27:01 -07:00
27c8066641 docs: add linkable section about updating commit messages in CONTRIBUTING.md (#39215)
A common review request is updating the commit message of a commit.
Since this is something that is not straight forward for inexperienced
contributors, it is useful to be able to point a contributor to some
docs outlining the process.

This commit adds such a section in `CONTRIBUTING.md` (as discussed in
https://github.com/angular/angular/pull/39110#discussion_r499935502).

PR Close #39215
2020-10-12 08:26:09 -07:00
952fd8662c fix(elements): detect matchesSelector prototype without IIFE (#37799)
Although in SSR we patch the global prototypes with DOM globals
like Element and Node, this patch does not occur before the
matches function is called in Angular Elements. This is similar
to the behavior in @angular/upgrade.

Fixes #24551

PR Close #37799
2020-10-09 10:02:25 -07:00
42be9047d8 feat(dev-infra): Add github links to caretaker checks (#39185)
This commit adds links to the PR/Issue for queries in the caretaker check.

PR Close #39185
2020-10-09 09:39:33 -07:00
52a0c6b36e fix(compiler): incorrectly encapsulating @import containing colons and semicolons (#38716)
At a high level, the current shadow DOM shim logic works by escaping the content of a CSS rule
(e.g. `div {color: red;}` becomes `div {%BLOCK%}`), using a regex to parse out things like the
selector and the rule body, and then re-adding the content after the selector has been modified.
The problem is that the regex has to be very broad in order capture all of the different use cases,
which can cause it to match strings suffixed with a semi-colon in some places where it shouldn't,
like this URL from Google Fonts `https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&display=swap`.
Most of the time this is fine, because the logic that escapes the rule content to `%BLOCK%` will
have converted it to something that won't be matched by the regex. However, it breaks down for rules
like `@import` which don't have a body, but can still have quoted content with characters that can
match the regex.

These changes resolve the issue by making a second pass over the escaped string and replacing all
of the remaining quoted content with `%QUOTED%` before parsing it with the regex. Once everything
has been processed, we make a final pass where we restore the quoted content.

In a previous iteration of this PR, I went with a shorter approach which narrowed down the
regex so that it doesn't capture rules without a body. It fixed the issue, but it also ended
up breaking some of the more contrived unit test cases. I decided not to pursue it further, because
we would've ended up with a very long and brittle regex that likely would've broken in even weirder
ways.

Fixes #38587.

PR Close #38716
2020-10-09 08:33:05 -07:00
8913aee527 build: bump Chromium to next stable version: 84.0.4147 (#39179)
Bump Chrome to the next stable release (84.0.4147) by following the
instructions in dev-infra/browsers/README.md.

With Chrome 86 about to be released as stable, the current local version
(Chrome 83) is starting to lag behind. It also contains a bug that
blocks Angular unit and integration tests from using Trusted Types.

PR Close #39179
2020-10-09 07:53:12 -07:00
7628c36f49 build: upgrade angular build, integration/bazel and @angular/bazel package to rule_nodejs 2.2.0 (#39182)
Updates to rules_nodejs 2.2.0. This is the first major release in 7 months and includes a number of features as well
as breaking changes.

Release notes: https://github.com/bazelbuild/rules_nodejs/releases/tag/2.0.0

Features of note for angular/angular:

* stdout/stderr/exit code capture; this could be potentially be useful

* TypeScript (ts_project); a simpler tsc rule that ts_library that can be used in the repo where ts_library is too
  heavy weight

Breaking changes of note for angular/angular:

* loading custom rules from npm packages: `ts_library` is no longer loaded from `@npm_bazel_typescript//:index.bzl`
  (which no longer exists) but is now loaded from `@npm//@bazel/typescript:index.bzl`

* with the loading changes above, `load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")` is
  no longer needed in the WORKSPACE which also means that yarn_install does not need to run unless building/testing
  a target that depends on @npm. In angular/angular this is a minor improvement as almost everything depends on @npm.

* @angular/bazel package is also updated in this PR to support the new load location; Angular + Bazel users that
  require it for ng_package (ng_module is no longer needed in OSS with Angular 10) will need to load from
  `@npm//@angular/bazel:index.bzl`. I investigated if it was possible to maintain backward compatability for the old
  load location `@npm_angular_bazel` but it is not since the package itself needs to be updated to load from
  `@npm//@bazel/typescript:index.bzl` instead of `@npm_bazel_typescript//:index.bzl` as it depends on ts_library
  internals for ng_module.

* runfiles.resolve will now throw instead of returning undefined to match behavior of node require

Other changes in angular/angular:

* integration/bazel has been updated to use both ng_module and ts_libary with use_angular_plugin=true.
  The latter is the recommended way for rules_nodejs users to compile Angular 10 with Ivy. Bazel + Angular ViewEngine is
  supported with @angular/bazel <= 9.0.5 and Angular <= 8. There is still Angular ViewEngine example on rules_nodejs
  https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular_view_engine on these older versions but users
  that want to update to Angular 10 and are on Bazel must switch to Ivy and at that point ts_library with
  use_angular_plugin=true is more performant that ng_module. Angular example in rules_nodejs is configured this way
  as well: https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular. As an aside, we also have an
  example of building Angular 10 with architect() rule directly instead of using ts_library with angular plugin:
  https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular_bazel_architect.

NB: ng_module is still required for angular/angular repository as it still builds ViewEngine & @angular/bazel
also provides the ng_package rule. ng_module can be removed in the future if ViewEngine is no longer needed in
angular repo.

* JSModuleInfo provider added to ng_module. this is for forward compat for future rules_nodejs versions.

PR Close #39182
2020-10-08 11:55:00 -07:00
b417dd7b9c docs: fix for HttpRequest expansion panel (#39166)
Fixes #39156

PR Close #39166
2020-10-08 09:38:10 -07:00
8cf16b4815 feat(docs-infra): add short url for strict mode guide (#39129)
With this change we add a short url to strict mode guide
(angular.io/strict -> angular.io/guide/strict-mode). This is important because
of two reasons.

1) Reduce the clutter in the terminal when we include the strict mode guide url in a prompt.
2) Easiler to share in conferences, slides etc..

PR Close #39129
2020-10-08 08:45:03 -07:00
806aed63f4 test(compiler-cli): temporarily disable integrationtest (#39168)
Temporarily disable the //packages/compiler-cli/integrationtest:integrationtest
target while continuing to investigate its unknown failures

PR Close #39168
2020-10-08 08:43:49 -07:00
eb34037cd7 Revert "refactor(compiler-cli): wrap RHS of property write in parens (#39143)" (#39171)
This reverts commit ba0df5250f.
Causes CI failures

PR Close #39171
2020-10-07 16:09:07 -07:00
ba0df5250f refactor(compiler-cli): wrap RHS of property write in parens (#39143)
The right needs to be wrapped in parens or we cannot accurately match its
span to just the RHS. For example, the span in `e = $event /*0,10*/` is ambiguous.
It could refer to either the whole binary expression or just the RHS.
We should instead generate `e = ($event /*0,10*/)` so we know the span 0,10 matches RHS.
This is specifically needed for the TemplateTypeChecker/Language Service
when mapping template positions to items in the TCB.

PR Close #39143
2020-10-07 14:49:47 -07:00
c4553bbed9 release: cut the v10.1.5 release 2020-10-07 14:20:12 -07:00
cc13b37446 build(docs-infra): render optional decorator options with a ? (#39167)
Decorator API pages list all their available options in an overview
table and also in a detailed view. Now the rendered syntax of each
option will show a `?` after the name if the option is not required.
This is inline with how class and interface members are rendered.

PR Close #39167
2020-10-07 13:33:26 -07:00
166df5d2ca refactor(common): remove i (ignore case) regex flag where it is not needed (#39077)
It is not necessary to set IGNORECASE flag when the regex pattern does
not contain alphabetic characters

PR Close #39077
2020-10-07 13:32:00 -07:00
a5b474580c docs: change heading to a sub-heading (#39131)
This commit changes the heading of the section
`Use TypeScript path mapping for peer dependencies` to a sub-heading of
`Linked Libraries`.

Fixes #39130

PR Close #39131
2020-10-07 13:31:24 -07:00
9f132d0d93 docs: remove explicit boolean type in examples as TS infers it automatically (#39081)
In the `packages/examples/common/ngif/module.ts` file, the field `show` is given an explicit
boolean type. Since typescript infers boolean type, it is redundant and this commit removes it.

PR Close #39081
2020-10-06 08:39:02 -07:00
8dee378b3e docs: add info about working with fixup commits (#39110)
Using fixup commits when addressing review feedback can considerably
improve the review experience on subsequent reviews.

This commit adds information and guidelines for contributors on how to
work with fixup commits.

Fixes #33042

PR Close #39110
2020-10-06 08:38:35 -07:00
0845d1148f build: update bazelversion (#39123)
Updates to the latest version of bazel

PR Close #39123
2020-10-05 17:08:08 -07:00
7cfa57a5f7 ci: use larger resource classes for bazel builds (#39124)
Migrates to using larger resource classes for windows CI runs as well as updating
the bazel rcs for windows and linux to use all/more of the resources available in
the executors

PR Close #39124
2020-10-05 17:06:49 -07:00
f80c22002b test(compiler): add tests for parsing of malformed property reads (#38998)
The expression parser already has support for recovering on malformed
property reads, but did not have tests describing the recovered ast in
such cases. This commit adds tests to demonstrate such cases; in
particular, the recovered ast is a full PropertyRead but with an empty
property name. This is likely the most preferred option, as it does not
constrain consumers of the AST to what the property name should look
like. Furthermore, we cannot mark the property name as empty in any
other way (e.g. an EmptyExpr) because the property name, as of present,
is a string field rather than an AST itself.

Note that tokens past a malformed property read are not preserved in the
AST (for example in `foo.1234`, `1234` is not preserved in the AST).
This is because the extra tokens do not belong to the singular
expression created by the property read, and there is not a meaningful
way to interpret a secondary expression in a single parsed expression.

Part of #38596

PR Close #38998
2020-10-05 14:24:47 -07:00
7aa12412f3 docs: Migrate section, view encapsulation, from Component Styles topic into its own topic. (#38986)
PR Close #38986
2020-10-05 13:23:41 -07:00
072b707b38 ci: update to latest version of sauce-connect (#39073)
Update to the latest version of sauce-connect, 4.6.2.

PR Close #39073
2020-10-05 12:53:28 -07:00
223b80cb7d docs(common): update docs for HttpClient methods (#38878)
PR Close #38878
2020-10-05 12:43:48 -07:00
416403fc63 docs: Made a minor change in the documentation (#38917)
PR Close #38917
2020-10-05 12:43:15 -07:00
878e2f0deb feat(dev-infra): show CI status of all active release trains (#39067)
As part of the ng-dev caretaker check command, show the status of the
lastest CircleCI run for each active release train.

PR Close #39067
2020-10-05 10:23:34 -07:00
4c30f5135b docs(upgrade): expand upon change detection implications for downgraded components (#39100)
PR Close #39100
2020-10-05 08:08:31 -07:00
6791cd79af refactor(compiler): iteratively parse interpolations (#38977)
This patch refactors the interpolation parser to do so iteratively
rather than using a regex. Doing so prepares us for supporting granular
recovery on poorly-formed interpolations, for example when an
interpolation does not terminate (`{{ 1 + 2`) or is not terminated
properly (`{{ 1 + 2 {{ 2 + 3 }}`).

Part of #38596

PR Close #38977
2020-10-02 15:13:24 -07:00
f50313f54d feat(compiler): Recover on malformed keyed reads and keyed writes (#39004)
This patch adds support for recovering well-formed (and near-complete)
ASTs for semantically malformed keyed reads and keyed writes. See the
added tests for details on the types of semantics we can now recover;
in particular, notice that some assumptions are made about the form of
a keyed read/write intended by a user. For example, in the malformed
expression `a[1 + = 2`, we assume that the user meant to write a binary
expression for the key of `a`, and assign that key the value `2`. In
particular, we now parse this as `a[1 + <empty expression>] = 2`. There
are some different interpretations that can be made here, but I think
this is reasonable.

The actual changes in the parser code are fairly minimal (a nice
surprise!); the biggest addition is a `writeContext` that marks whether
the `=` operator can serve as a recovery point after error detection.

Part of #38596

PR Close #39004
2020-10-02 11:37:03 -07:00
30433a0710 fix(docs-infra): better distinguish wrapped headings from other entries in TOC (#39092)
Previously, when a heading was longer than the Table of Content's  (TOC)
width and it had to be wrapped into multiple lines, it was hard to
distinguish the subsequent lines from other TOC entries (i.e. other
headings).

This commit makes it easier to visually distinguish wrapped heading
lines from other headings by reducing the spacing between wrapped lines
of the same heading (making it more obvious that they belong together).

PR Close #39092
2020-10-02 10:59:41 -07:00
86ab9f92b4 Revert "build: upgrade angular build, integration/bazel and @angular/bazel package to rule_nodejs 2.2.0 (#37727)" (#39097)
This reverts commit db56cf18ba.

PR Close #39097
2020-10-02 10:56:53 -07:00
42f9679376 build: upgrade angular build, integration/bazel and @angular/bazel package to rule_nodejs 2.2.0 (#37727)
Updates to rules_nodejs 2.2.0. This is the first major release in 7 months and includes a number of features as well
as breaking changes.

Release notes: https://github.com/bazelbuild/rules_nodejs/releases/tag/2.0.0

Features of note for angular/angular:

* stdout/stderr/exit code capture; this could be potentially be useful

* TypeScript (ts_project); a simpler tsc rule that ts_library that can be used in the repo where ts_library is too
  heavy weight

Breaking changes of note for angular/angular:

* loading custom rules from npm packages: `ts_library` is no longer loaded from `@npm_bazel_typescript//:index.bzl`
  (which no longer exists) but is now loaded from `@npm//@bazel/typescript:index.bzl`

* with the loading changes above, `load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")` is
  no longer needed in the WORKSPACE which also means that yarn_install does not need to run unless building/testing
  a target that depends on @npm. In angular/angular this is a minor improvement as almost everything depends on @npm.

* @angular/bazel package is also updated in this PR to support the new load location; Angular + Bazel users that
  require it for ng_package (ng_module is no longer needed in OSS with Angular 10) will need to load from
  `@npm//@angular/bazel:index.bzl`. I investigated if it was possible to maintain backward compatability for the old
  load location `@npm_angular_bazel` but it is not since the package itself needs to be updated to load from
  `@npm//@bazel/typescript:index.bzl` instead of `@npm_bazel_typescript//:index.bzl` as it depends on ts_library
  internals for ng_module.

* runfiles.resolve will now throw instead of returning undefined to match behavior of node require

Other changes in angular/angular:

* integration/bazel has been updated to use both ng_module and ts_libary with use_angular_plugin=true.
  The latter is the recommended way for rules_nodejs users to compile Angular 10 with Ivy. Bazel + Angular ViewEngine is
  supported with @angular/bazel <= 9.0.5 and Angular <= 8. There is still Angular ViewEngine example on rules_nodejs
  https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular_view_engine on these older versions but users
  that want to update to Angular 10 and are on Bazel must switch to Ivy and at that point ts_library with
  use_angular_plugin=true is more performant that ng_module. Angular example in rules_nodejs is configured this way
  as well: https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular. As an aside, we also have an
  example of building Angular 10 with architect() rule directly instead of using ts_library with angular plugin:
  https://github.com/bazelbuild/rules_nodejs/tree/stable/examples/angular_bazel_architect.

NB: ng_module is still required for angular/angular repository as it still builds ViewEngine & @angular/bazel
also provides the ng_package rule. ng_module can be removed in the future if ViewEngine is no longer needed in
angular repo.

* JSModuleInfo provider added to ng_module. this is for forward compat for future rules_nodejs versions.
  @josephperrott, this touches `packages/bazel/src/external.bzl` which will make the sync to g3 non-trivial.

PR Close #37727
2020-10-01 15:34:37 -07:00
bee10574d8 ci: update g3 synced file list (#39084) (#39087)
Update the list of files synced into g3

PR Close #39087
2020-10-01 15:33:17 -07:00
afce0f5038 fix(dev-infra): correct matching logic for g3 comparison (#39084) (#39087)
Corrects the matching logic for g3 comparison check, previously more matches were
found than were correct.

PR Close #39087
2020-10-01 15:33:17 -07:00
bb19e61848 feat(dev-infra): add a command to verify NgBot YAML config syntax (#39071)
This commit adds a new command to the `ng-dev` suite, which verifies that the NgBot YAML config is
correct. It also adds this command to the `lint` CircleCI job so that we execute this check while
running CI.

This should help prevent syntax errors similar to the one introduced in:
393ce5574b

PR Close #39071
2020-10-01 12:31:45 -07:00
50e83e2566 refactor(docs-infra): leave TODO comments for aligning tslint with CLI (#39018)
This commit adds some TODO comments in `tslint.json` regardling rules
that need to be enabled or removed to more closely align `tslint.json`
with the one generated by the latest Angular CLI for new apps.

Updating these rules generates a lot of linting failures, so fixing
them is outside the scope of this PR.

PR Close #39018
2020-10-01 09:32:58 -07:00
d80c4890be build(docs-infra): remove the only-arrow-functions tslint rule to align with CLI (#39018)
This commit removes the `only-arrow-functions: false` tslint rule to
more closely align `tslint.json` with the one generated by the latest
Angular CLI for new apps.

PR Close #39018
2020-10-01 09:32:58 -07:00
4f8b716c13 build(docs-infra): update the object-literal-key-quotes tslint rule to align with CLI (#39018)
This commit updates the `object-literal-key-quotes` tslint rule to more
closely align `tslint.json` with the one generated by the latest Angular
CLI for new apps.

PR Close #39018
2020-10-01 09:32:58 -07:00
cb85d69450 build(docs-infra): remove the no-string-literal tslint rule to align with CLI (#39018)
This commit removes the `no-string-literal: false` tslint rule to
more closely align `tslint.json` with the one generated by the latest
Angular CLI for new apps.

PR Close #39018
2020-10-01 09:32:58 -07:00
4a446878fa build(docs-infra): enable the no-redundant-jsdoc tslint rule to align with CLI (#39018)
This commit enables the `no-redundant-jsdoc` tslint rule to more closely
align `tslint.json` with the one generated by the latest Angular CLI for
new apps.

PR Close #39018
2020-10-01 09:32:57 -07:00
cb80f46c64 refactor(docs-infra): more closely align tslint.json with CLI (#39018)
This commit re-organizes the `tslint.json` configuration file to more
closely align with the one generated by the latest Angular CLI for new
apps. This makes it easier to see the difference with new CLI versions
in the future and keep our `tslint.json` up-to-date (while keeping our
own rules).

NOTE:
This commit only re-orders rules and removes redundant ones. It does not
change the linting behavior.

PR Close #39018
2020-10-01 09:32:57 -07:00
5199d55d45 fix(dev-infra): run git fetch in quiet mode (#39068)
Runs git fetch with the -q flag during fetch while comparing the master and
g3 branches.

PR Close #39068
2020-10-01 09:30:15 -07:00
bb11fd9058 ci: change required labels for issue triage (#38932)
Issue triage _currently_ requires a component to be set and one of the following to be true for an issue to be
considered triaged:
* Marked as a bug _and_ has a severity _and_ has a frequency
* Mark as a feature
* Marked as a refactor
* Marked as a discussion
* Marked as "confusing"
* Marked as "use-case"

This PR changes the rules so that (in addition to the component), triage
requires:
* A priority label (P0 through P5)
* Marked as a feature
* Marked as a discussion

Triage may also apply additional, optional info labels to issues.

[This document outlines the new priority
scheme](https://docs.google.com/document/d/1mN2zWsr1pxChSTHC7UkOgl4PhhuoFONtG_zcMWeqLwA/preview).

While this PR is focused on issue triage and not PR triage, I have
changed the PR section triage to remove reference to the "effort: *" and
"risk: *" labels. Looking through recent PRs, Kapunahele is the only
person applying these, so it's clear that this bit is no longer widely
practiced.

This is just one step in the always-ongoing process of managing GitHub
labels. More adjustments will come over time. In writing this PR, I have
already unearthed a few more areas that can be polished in follow-ups.

PR Close #38932
2020-10-01 08:32:21 -07:00
771f7318f0 fix(router): update getRouteGuards to check if the context outlet is activated (#39049)
In certain circumstances (errors during component constructor) the router outlet may not be activated before
redirecting to a new route. If the new route requires running guards and resolvers the current logic will throw
when accessing outlet.component due to an isActivated check within the property getter.  This update brings the
logic inline with deactivateRouterAndItsChildren, namely checking outlet.isActivated before trying to access
outlet.component.

Fixes #39030

PR Close #39049
2020-09-30 14:58:47 -07:00
5d584b7728 ci: remove errant comma from angular robot config (#39066)
Remove superfluous comma from exclude list for g3 status in the angular
robot config.

PR Close #39066
2020-09-30 13:27:31 -07:00
1b5f6ee7a6 refactor(localize): avoid free-standing FileSystem functions (#39006)
These free standing functions rely upon the "current" `FileSystem`,
but it is safer to explicitly pass the `FileSystem` into functions or
classes that need it.

Fixes #38711

PR Close #39006
2020-09-30 12:49:44 -07:00
669e07580c refactor(compiler-cli): avoid free-standing FileSystem functions (#39006)
These free standing functions rely upon the "current" `FileSystem`,
but it is safer to explicitly pass the `FileSystem` into functions or
classes that need it.

PR Close #39006
2020-09-30 12:49:43 -07:00
965249d1da docs(localize): add public api markers for CLI integration (#39006)
This commit marks the functions and classes that are
used by the CLI.

PR Close #39006
2020-09-30 12:49:43 -07:00
3a01856e7c docs: fix typo in Pipes guide (aynchronous --> asynchronous) (#38996)
PR Close #38996
2020-09-30 12:46:27 -07:00
344 changed files with 8012 additions and 5537 deletions

View File

@ -74,8 +74,8 @@ test --test_output=errors
# Trick bazel into treating BUILD files under integration/bazel as being regular files
# This lets us glob() up all the files inside this integration test to make them inputs to tests
# (Note, we cannot use common --deleted_packages because the bazel version command doesn't support it)
build --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/test/e2e
query --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/test/e2e
build --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/tools,integration/bazel/test/e2e
query --deleted_packages=integration/bazel,integration/bazel/src,integration/bazel/src/hello-world,integration/bazel/test,integration/bazel/tools,integration/bazel/test/e2e
################################
# Temporary Settings for Ivy #

View File

@ -1,3 +1,3 @@
3.2.0
3.5.1
# [NB: this comment has to be after the first line, see https://github.com/bazelbuild/bazelisk/issues/117]
# When updating the Bazel version you also need to update the RBE toolchains version in package.bzl

View File

@ -14,8 +14,8 @@ build --repository_cache=/home/circleci/bazel_repository_cache
# Bazel doesn't calculate the memory ceiling correctly when running under Docker.
# Limit Bazel to consuming resources that fit in CircleCI "xlarge" class
# https://circleci.com/docs/2.0/configuration-reference/#resource_class
build --local_cpu_resources=8
build --local_ram_resources=14336
build --local_cpu_resources=20
build --local_ram_resources=32768
# All build executed remotely should be done using our RBE configuration.
build:remote --google_default_credentials

View File

@ -6,13 +6,9 @@
# https://docs.bazel.build/versions/master/guide.html#bazelrc-syntax-and-semantics
try-import %workspace%/.circleci/bazel.common.rc
# Save downloaded repositories in a location that can be cached by CircleCI. This helps us
# speeding up the analysis time significantly with Bazel managed node dependencies on the CI.
build --repository_cache=C:/Users/circleci/bazel_repository_cache
# Manually set the local resources used in windows CI runs
build --local_ram_resources=13500
build --local_cpu_resources=4
build --local_ram_resources=120000
build --local_cpu_resources=32
# All windows jobs run on master and should use http caching
build --remote_http_cache=https://storage.googleapis.com/angular-team-cache

View File

@ -27,8 +27,6 @@ var_3: &cache_key v7-angular-node-12-{{ checksum ".bazelversion" }}-{{ checksum
# folder will contain all previously used versions and ultimately cause the cache restoring to
# be slower due to its growing size.
var_4: &cache_key_fallback v7-angular-node-12-{{ checksum ".bazelversion" }}
var_3_win: &cache_key_win v7-angular-win-node-12-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }}
var_4_win: &cache_key_win_fallback v7-angular-win-node-12-{{ checksum ".bazelversion" }}
# Cache key for the `components-repo-unit-tests` job. **Note** when updating the SHA in the
# cache keys also update the SHA for the "COMPONENTS_REPO_COMMIT" environment variable.
@ -80,7 +78,7 @@ executors:
windows-executor:
working_directory: ~/ng
resource_class: windows.medium
resource_class: windows.2xlarge
# CircleCI windows VMs do have the GitBash shell available:
# https://github.com/CircleCI-Public/windows-preview-docs#shells
# But in this specific case we really should not use it because Bazel must not be ran from
@ -183,23 +181,12 @@ commands:
setup_win:
description: Setup windows node environment
steps:
# Use the Linux workspace directly, as it already has checkout, rebased and node modules.
- custom_attach_workspace
- checkout
# Install Bazel pre-requisites that aren't in the preconfigured CircleCI Windows VM.
- run: ./.circleci/windows-env.ps1
- run: node --version
- run: yarn --version
- restore_cache:
keys:
- *cache_key_win
- *cache_key_win_fallback
# Reinstall to get windows binaries.
- run: yarn install --frozen-lockfile --non-interactive
# Install @bazel/bazelisk globally and use that for the first run.
# Workaround for https://github.com/bazelbuild/rules_nodejs/issues/894
# NB: the issue was for @bazel/bazel but the same problem applies to @bazel/bazelisk
- run: yarn global add @bazel/bazelisk@$env:BAZELISK_VERSION
- run: bazelisk info
notify_webhook_on_fail:
description: Notify a webhook about failure
@ -273,6 +260,7 @@ jobs:
- run: yarn -s ng-dev format changed $CI_GIT_BASE_REVISION --check
- run: yarn -s ts-circular-deps:check
- run: yarn -s ng-dev pullapprove verify
- run: yarn -s ng-dev ngbot verify
- run: yarn -s ng-dev commit-message validate-range --range $CI_COMMIT_RANGE
test:
@ -755,25 +743,26 @@ jobs:
steps:
- setup_win
- run:
# Ran into a command parsing problem where `-browser:chromium-local` was converted to
# `-browser: chromium-local` (a space was added) in https://circleci.com/gh/angular/angular/357511.
# Probably a powershell command parsing thing. There's no problem using a yarn script though.
command: yarn circleci-win-ve
no_output_timeout: 45m
# Save bazel repository cache to use on subsequent runs.
# We don't save node_modules because it's faster to use the linux workspace and reinstall.
- save_cache:
key: *cache_key_win
paths:
- "C:/Users/circleci/bazel_repository_cache"
name: Build all windows CI targets
command: yarn bazel build --build_tag_filters=-ivy-only //packages/compiler-cli/... //tools/ts-api-guardian/...
no_output_timeout: 15m
- run:
name: Test all windows CI targets
command: yarn bazel test --test_tag_filters="-ivy-only,-browser:chromium-local" //packages/compiler-cli/... //tools/ts-api-guardian/...
no_output_timeout: 15m
test_ivy_aot_win:
executor: windows-executor
steps:
- setup_win
- run:
command: yarn circleci-win-ivy
no_output_timeout: 45m
name: Build all windows CI targets
command: yarn bazel build --config=ivy --build_tag_filters=-no-ivy-aot,-fixme-ivy-aot //packages/compiler-cli/... //tools/ts-api-guardian/...
no_output_timeout: 15m
- run:
name: Test all windows CI targets
command: yarn bazel test --config=ivy --test_tag_filters="-no-ivy-aot,-fixme-ivy-aot,-browser:chromium-local" //packages/compiler-cli/... //tools/ts-api-guardian/...
no_output_timeout: 15m
workflows:
@ -857,26 +846,25 @@ workflows:
- build-npm-packages
- build-ivy-npm-packages
- legacy-unit-tests-saucelabs
- components-repo-unit-tests:
requires:
- build-npm-packages
# Temporarily disabled components-repo-unit-tests to update rules_nodejs to 2.0.0. Breaking changes in
# rules_nodejs create a dependency sandwich between angular/angular & angular/components that are very
# difficult and time consuming to resolve and involve patching @angular/bazel in components repo such
# as https://github.com/angular/components/commit/9e7ba251207df77164d73d66620e619bcbc4d2ad. It is simpler to
# 1) land angular/angular upgrade to rule_nodejs 2.0.0 which has breaking changes
# 2) land angular/components upgrade to rules_nodejs 2.0.0 using the @angular/bazel builds snapshot
# 3) update angular/angular to the landed components commit and re-enable these tests
# - components-repo-unit-tests:
# requires:
# - build-npm-packages
- test_zonejs:
requires:
- setup
# Windows Jobs
# These are very slow so we run them on non-PRs only for now.
# TODO: remove the filter when CircleCI makes Windows FS faster.
# The Windows jobs are only run after their non-windows counterparts finish successfully.
# This isn't strictly necessary as there is no artifact dependency, but helps economize
# CI resources by not attempting to build when we know should fail.
- test_win:
<<: *skip_on_pull_requests
requires:
- test
- setup
- test_ivy_aot_win:
<<: *skip_on_pull_requests
requires:
- test_ivy_aot
- setup
monitoring:
jobs:

View File

@ -2,8 +2,8 @@
# https://docs.bazel.build/versions/master/install-windows.html
# https://docs.bazel.build/versions/master/windows.html
# Install MSYS2 and packages
choco install msys2 --version 20180531.0.0 --no-progress --package-parameters "/NoUpdate"
C:\tools\msys64\usr\bin\bash.exe -l -c "pacman --needed --noconfirm -S zip unzip patch diffutils git"
choco install msys2 --version 20200903.0.0 --no-progress --package-parameters "/NoUpdate"
C:\tools\msys64\usr\bin\bash.exe -l -c "pacman --needed --noconfirm -S zip unzip patch diffutils"
# Add PATH modifications to the Powershell profile. This is the win equivalent of .bash_profile.
# https://docs.microsoft.com/en-us/previous-versions//bb613488(v=vs.85)
@ -41,7 +41,8 @@ copy .circleci\bazel.windows.rc ${Env:USERPROFILE}\.bazelrc
####################################################################################################
# Install specific version of node.
####################################################################################################
choco install nodejs --version 12.14.1 --no-progress
nvm install 12.14.1
nvm use 12.14.1
# These Bazel prereqs aren't needed because the CircleCI image already includes them.
# choco install yarn --version 1.16.0 --no-progress

View File

@ -38,6 +38,7 @@ merge:
- "modules/benchmarks/**"
- "modules/system.d.ts"
- "packages/**"
- "dev-infra/benchmark/driver-utilities/**"
# list of patterns to ignore for the files changed by the PR
exclude:
- "packages/*"
@ -47,8 +48,10 @@ merge:
- "packages/bazel/src/ng_package/**"
- "packages/bazel/src/protractor/**"
- "packages/bazel/src/schematics/**"
- "packages/compiler-cli/src/ngcc/**"
- "packages/compiler-cli/linker/**"
- "packages/compiler-cli/ngcc/**"
- "packages/compiler-cli/src/ngtsc/sourcemaps/**",
- "packages/compiler-cli/src/ngtsc/sourcemaps/**"
- "packages/docs/**"
- "packages/elements/schematics/**"
- "packages/examples/**"
@ -56,6 +59,8 @@ merge:
- "packages/localize/**"
- "packages/private/**"
- "packages/service-worker/**"
- "packages/common/locales/**"
- "packages/http/**"
- "**/.gitignore"
- "**/.gitkeep"
- "**/yarn.lock"
@ -137,24 +142,28 @@ triage:
# arrays of labels that determine if an issue has been fully triaged
l2TriageLabels:
-
- "type: bug/fix"
- "severity*"
- "freq*"
- "P0"
- "comp: *"
-
- "type: feature"
- "P1"
- "comp: *"
-
- "type: refactor"
- "P2"
- "comp: *"
-
- "type: RFC / Discussion / question"
- "P3"
- "comp: *"
-
- "type: confusing"
- "P4"
- "comp: *"
-
- "type: use-case"
- "P5"
- "comp: *"
-
- "feature"
- "comp: *"
-
- "discussion"
- "comp: *"
# options for the triage PR plugin

View File

@ -9,11 +9,11 @@ export const caretaker: CaretakerConfig = {
},
{
name: 'Merge Assistance Queue',
query: `is:pr is:open status:success label:"action: merge-assistance"`,
query: `is:pr is:open label:"action: merge-assistance"`,
},
{
name: 'Primary Triage Queue',
query: `is:open is:issue no:milestone`,
name: 'Initial Triage Queue',
query: `is:open no:milestone`,
}
]
};

View File

@ -26,7 +26,7 @@ export const release: ReleaseConfig = {
],
// TODO: Implement release package building here.
buildPackages: async () => [],
// TODO: This can be removed once there is a org-wide tool for changelog generation.
// TODO: This can be removed once there is an org-wide tool for changelog generation.
generateReleaseNotesForHead: async () => {
exec('yarn -s gulp changelog', {cwd: join(__dirname, '../')});
},

View File

@ -186,6 +186,7 @@ groups:
- IgorMinar # Igor Minar
- jbogarthyde # Judy Bogart
- jelbourn # Jeremy Elbourn
- jessicajaniuk # Jessica Janiuk
- JiaLiPassion # Jia Li
- JoostK # Joost Koehoorn
- josephperrott # Joey Perrott
@ -325,7 +326,10 @@ groups:
'aio/content/guide/component-interaction.md',
'aio/content/examples/component-interaction/**',
'aio/content/images/guide/component-interaction/**',
'aio/content/guide/component-overview.md',
'aio/content/examples/component-overview/**',
'aio/content/guide/component-styles.md',
'aio/content/guide/view-encapsulation.md',
'aio/content/examples/component-styles/**',
'aio/content/guide/dependency-injection.md',
'aio/content/examples/dependency-injection/**',
@ -378,6 +382,7 @@ groups:
'aio/content/examples/binding-syntax/**',
'aio/content/guide/property-binding.md',
'aio/content/examples/property-binding/**',
'aio/content/guide/property-binding-best-practices.md',
'aio/content/guide/attribute-binding.md',
'aio/content/examples/attribute-binding/**',
'aio/content/guide/two-way-binding.md',
@ -406,6 +411,7 @@ groups:
'aio/content/guide/structural-directives.md',
'aio/content/examples/structural-directives/**',
'aio/content/guide/svg-in-templates.md',
'aio/content/guide/style-precedence.md',
'aio/content/images/guide/structural-directives/**',
'aio/content/guide/template-statements.md',
'aio/content/guide/user-input.md',
@ -1115,11 +1121,13 @@ groups:
'docs/DEBUG.md',
'docs/DEBUG_COMPONENTS_REPO_IVY.md',
'docs/DEVELOPER.md',
'docs/FIXUP_COMMITS.md',
'docs/GITHUB_PROCESS.md',
'docs/PR_REVIEW.md',
'docs/SAVED_REPLIES.md',
'docs/TOOLS.md',
'docs/TRIAGE_AND_LABELS.md',
'docs/images/**',
'goldens/*',
'modules/*',
'packages/*',

View File

@ -47,3 +47,9 @@ filegroup(
"@npm//:node_modules/angular-mocks-1.6/angular-mocks.js",
],
)
# Detect if the build is running under --stamp
config_setting(
name = "stamp",
values = {"stamp": "true"},
)

View File

@ -1,3 +1,60 @@
<a name="10.2.0"></a>
# 10.2.0 (2020-10-21)
### Bug Fixes
* **core:** guard reading of global `ngDevMode` for undefined. ([#36055](https://github.com/angular/angular/issues/36055)) ([02405f1](https://github.com/angular/angular/commit/02405f1))
* **platform-server:** Resolve absolute URL from baseUrl ([#39334](https://github.com/angular/angular/issues/39334)) ([71fb99f](https://github.com/angular/angular/commit/71fb99f))
### BREAKING CHANGES
* **platform-server:** If you use `useAbsoluteUrl` to setup `platform-server`, you now need to
also specify `baseUrl`.
We are intentionally making this a breaking change in a minor release,
because if `useAbsoluteUrl` is set to `true` then the behavior of the
application could be unpredictable, resulting in issues that are hard to
discover but could be affecting production environments.
<a name="10.1.6"></a>
## 10.1.6 (2020-10-14)
### Bug Fixes
* **compiler:** incorrectly encapsulating [@import](https://github.com/import) containing colons and semicolons ([#38716](https://github.com/angular/angular/issues/38716)) ([52a0c6b](https://github.com/angular/angular/commit/52a0c6b)), closes [#38587](https://github.com/angular/angular/issues/38587)
* **compiler-cli:** support namespaced query types in directives ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([f752ab9](https://github.com/angular/angular/commit/f752ab9))
* **elements:** detect matchesSelector prototype without IIFE ([#37799](https://github.com/angular/angular/issues/37799)) ([952fd86](https://github.com/angular/angular/commit/952fd86)), closes [#24551](https://github.com/angular/angular/issues/24551)
* **ngcc:** ensure that "inline exports" can be interpreted correctly ([#39272](https://github.com/angular/angular/issues/39272)) ([e08d021](https://github.com/angular/angular/commit/e08d021))
* **ngcc:** handle aliases in UMD export declarations ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([9963c5d](https://github.com/angular/angular/commit/9963c5d)), closes [#38947](https://github.com/angular/angular/issues/38947)
* **ngcc:** map `exports` to the current module in UMD files ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([13c4a7b](https://github.com/angular/angular/commit/13c4a7b))
* **ngcc:** support inline export declarations in UMD files ([#38959](https://github.com/angular/angular/issues/38959)) ([#39272](https://github.com/angular/angular/issues/39272)) ([9c875b3](https://github.com/angular/angular/commit/9c875b3)), closes [#38947](https://github.com/angular/angular/issues/38947)
### build
* upgrade angular build, integration/bazel and [@angular](https://github.com/angular)/bazel package to rule_nodejs 2.2.0 ([#39182](https://github.com/angular/angular/issues/39182)) ([7628c36](https://github.com/angular/angular/commit/7628c36))
### Performance Improvements
* **ngcc:** do not rescan program source files when referenced from multiple root files ([#39254](https://github.com/angular/angular/issues/39254)) ([5221df8](https://github.com/angular/angular/commit/5221df8)), closes [#39240](https://github.com/angular/angular/issues/39240)
<a name="10.1.5"></a>
## 10.1.5 (2020-10-07)
### Bug Fixes
* **router:** update getRouteGuards to check if the context outlet is activated ([#39049](https://github.com/angular/angular/issues/39049)) ([771f731](https://github.com/angular/angular/commit/771f731)), closes [#39030](https://github.com/angular/angular/issues/39030)
* **compiler:** Recover on malformed keyed reads and keyed writes ([#39004](https://github.com/angular/angular/issues/39004)) ([f50313f](https://github.com/angular/angular/commit/f50313f)), closes [#38596](https://github.com/angular/angular/issues/38596)
<a name="10.1.4"></a>
## 10.1.4 (2020-09-30)

View File

@ -3,7 +3,7 @@
As contributors and maintainers of the Angular project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities.
Communication through any of Angular's channels (GitHub, Gitter, IRC, mailing lists, Google+, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
Communication through any of Angular's channels (GitHub, Discord, Gitter, IRC, mailing lists, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to the Angular project to do the same.

View File

@ -32,7 +32,7 @@ Stack Overflow is a much better place to ask questions since:
To save your and our time, we will systematically close all issues that are requests for general support and redirect people to Stack Overflow.
If you would like to chat about the question in real-time, you can reach out via [our gitter channel][gitter].
If you would like to chat about the question in real-time, you can reach out via [our Discord server][discord].
## <a name="issue"></a> Found a Bug?
@ -107,7 +107,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
Adherence to these conventions is necessary because release notes are automatically generated from these messages.
```shell
git commit -a
git commit --all
```
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
@ -119,20 +119,55 @@ Before you submit your Pull Request (PR) consider the following guidelines:
11. In GitHub, send a pull request to `angular:master`.
If we ask for changes via code reviews then:
* Make the required updates.
* Re-run the Angular test suites to ensure tests are still passing.
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
#### Addressing review feedback
```shell
git rebase master -i
git push -f
```
If we ask for changes via code reviews then:
1. Make the required updates to the code.
2. Re-run the Angular test suites to ensure tests are still passing.
3. Create a fixup commit and push to your GitHub repository (this will update your Pull Request):
```shell
git commit --all --fixup HEAD
git push
```
For more info on working with fixup commits see [here](docs/FIXUP_COMMITS.md).
That's it! Thank you for your contribution!
##### Updating the commit message
A reviewer might often suggest changes to a commit message (for example, to add more context for a change or adhere to our [commit message guidelines](#commit)).
In order to update the commit message of the last commit on your branch:
1. Check out your branch:
```shell
git checkout my-fix-branch
```
2. Amend the last commit and modify the commit message:
```shell
git commit --amend
```
3. Push to your GitHub repository:
```shell
git push --force-with-lease
```
> NOTE:<br />
> If you need to update the commit message of an earlier commit, you can use `git rebase` in interactive mode.
> See the [git docs](https://git-scm.com/docs/git-rebase#_interactive_mode) for more details.
#### After your pull request is merged
After your pull request is merged, you can safely delete your branch and pull the changes from the main (upstream) repository:
@ -213,7 +248,7 @@ Any line of the commit message cannot be longer than 100 characters.
│ platform-webworker-dynamic|router|service-worker|upgrade|zone.js|
│ packaging|changelog|dev-infra|docs-infra|migrations|ngcc|ve
└─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|style|test
└─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|test
```
The `<type>` and `<summary>` fields are mandatory, the `(<scope>)` field is optional.
@ -276,7 +311,7 @@ There are currently a few exceptions to the "use package name" rule:
* `ve`: used for changes specific to ViewEngine (legacy compiler/renderer).
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`) and for docs changes that are not related to a specific package (e.g. `docs: fix typo in tutorial`).
* none/empty string: useful for `test` and `refactor` changes that are done across all packages (e.g. `test: add missing unit tests`) and for docs changes that are not related to a specific package (e.g. `docs: fix typo in tutorial`).
##### Summary
@ -349,7 +384,7 @@ The following documents can help you sort out issues with GitHub accounts and mu
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
[dev-doc]: https://github.com/angular/angular/blob/master/docs/DEVELOPER.md
[github]: https://github.com/angular/angular
[gitter]: https://gitter.im/angular/angular
[discord]: https://discord.gg/angular
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
[js-style-guide]: https://google.github.io/styleguide/jsguide.html
[jsfiddle]: http://jsfiddle.net

145
README.md
View File

@ -1,26 +1,151 @@
[![CircleCI](https://circleci.com/gh/angular/angular/tree/master.svg?style=shield)](https://circleci.com/gh/angular/workflows/angular/tree/master)
[![Join the chat at https://gitter.im/angular/angular](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![npm version](https://badge.fury.io/js/%40angular%2Fcore.svg)](https://www.npmjs.com/@angular/core)
<h1 align="center">Angular - One framework. Mobile & desktop.</h1>
<p align="center">
<img src="aio/src/assets/images/logos/angular/angular.png" alt="angular-logo" width="120px" height="120px"/>
<br>
<i>Angular is a development platform for building mobile and desktop web applications
<br> using Typescript/JavaScript and other languages.</i>
<br>
</p>
# Angular
<p align="center">
<a href="https://www.angular.io"><strong>www.angular.io</strong></a>
<br>
</p>
Angular is a development platform for building mobile and desktop web applications using TypeScript/JavaScript and other languages.
<p align="center">
<a href="CONTRIBUTING.md">Contributing Guidelines</a>
·
<a href="https://github.com/angular/angular/issues">Submit an Issue</a>
·
<a href="https://blog.angular.io/">Blog</a>
<br>
<br>
</p>
<p align="center">
<a href="https://circleci.com/gh/angular/workflows/angular/tree/master">
<img src="https://img.shields.io/circleci/build/github/angular/angular/master.svg?logo=circleci&logoColor=fff&label=CircleCI" alt="CI status" />
</a>&nbsp;
<a href="https://www.npmjs.com/@angular/core">
<img src="https://img.shields.io/npm/v/@angular/core.svg?logo=npm&logoColor=fff&label=NPM+package&color=limegreen" alt="Angular on npm" />
</a>&nbsp;
<a href="https://discord.gg/angular">
<img src="https://img.shields.io/discord/463752820026376202.svg?logo=discord&logoColor=fff&label=Discord&color=7389d8" alt="Discord conversation" />
</a>
</p>
<hr>
## Documentation
Get started with Angular, learn the fundamentals and explore advanced topics on our documentation website.
- [Getting Started][quickstart]
- [Architecture][architecture]
- [Components and Templates][componentstemplates]
- [Forms][forms]
- [API][api]
### Advanced
- [Angular Elements][angularelements]
- [Server Side Rendering][ssr]
- [Schematics][schematics]
- [Lazy Loading][lazyloading]
## Development Setup
### Prerequisites
- Install [Node.js] which includes [Node Package Manager][npm]
### Setting Up a Project
Intall the Angular CLI globally:
```
npm install -g @angular/cli
```
Create workspace:
```
ng new [PROJECT NAME]
```
Run the application:
```
cd [PROJECT NAME]
ng serve
```
## Quickstart
[Get started in 5 minutes][quickstart].
## Ecosystem
<p>
<img src="/docs/images/angular-ecosystem-logos.png" alt="angular ecosystem logos" width="500px" height="auto">
</p>
- [Angular Command Line (CLI)][cli]
- [Angular Material][angularmaterial]
## Changelog
[Learn about the latest improvements][changelog].
## Want to help?
## Upgrading
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our
guidelines for [contributing][contributing] and then check out one of our issues in the [hotlist: community-help](https://github.com/angular/angular/labels/hotlist%3A%20community-help).
Check out our [upgrade guide](https://update.angular.io/) to find out the best way to upgrade your project.
[contributing]: https://github.com/angular/angular/blob/master/CONTRIBUTING.md
## Contributing
### Contributing Guidelines
Read through our [contributing guidelines][contributing] to learn about our submission process, coding rules and more.
### Want to Help?
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our guidelines for [contributing][contributing] and then check out one of our issues in the [hotlist: community-help](https://github.com/angular/angular/labels/hotlist%3A%20community-help).
### Code of Conduct
Help us keep Angular open and inclusive. Please read and follow our [Code of Conduct][codeofconduct].
## Community
Join the conversation and help the community.
- [Twitter][twitter]
- [Gitter][gitter]
- Find a Local [Meetup][meetup]
[![Love Angular badge](https://img.shields.io/badge/angular-love-blue?logo=angular&angular=love)](https://www.github.com/angular/angular)
**Love Angular? Give our repo a star :star: :arrow_up:.**
[contributing]: CONTRIBUTING.md
[quickstart]: https://angular.io/start
[changelog]: https://github.com/angular/angular/blob/master/CHANGELOG.md
[changelog]: CHANGELOG.md
[ng]: https://angular.io
[documentation]: https://angular.io/docs
[angularmaterial]: https://material.angular.io/
[cli]: https://cli.angular.io/
[architecture]: https://angular.io/guide/architecture
[componentstemplates]: https://angular.io/guide/displaying-data
[forms]: https://angular.io/guide/forms-overview
[api]: https://angular.io/api
[angularelements]: https://angular.io/guide/elements
[ssr]: https://angular.io/guide/universal
[schematics]: https://angular.io/guide/schematics
[lazyloading]: https://angular.io/guide/lazy-loading-ngmodules
[node.js]: https://nodejs.org/
[npm]: https://www.npmjs.com/get-npm
[codeofconduct]: CODE_OF_CONDUCT.md
[twitter]: https://www.twitter.com/angular
[gitter]: https://gitter.im/angular/angular
[meetup]: https://www.meetup.com/find/?keywords=angular"

View File

@ -8,8 +8,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# Fetch rules_nodejs so we can install our npm dependencies
http_archive(
name = "build_bazel_rules_nodejs",
sha256 = "84abf7ac4234a70924628baa9a73a5a5cbad944c4358cf9abdb4aab29c9a5b77",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.7.0/rules_nodejs-1.7.0.tar.gz"],
sha256 = "4952ef879704ab4ad6729a29007e7094aef213ea79e9f2e94cbe1c9a753e63ef",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/2.2.0/rules_nodejs-2.2.0.tar.gz"],
)
# Check the rules_nodejs version and download npm dependencies
@ -17,7 +17,7 @@ http_archive(
# assert on that.
load("@build_bazel_rules_nodejs//:index.bzl", "check_rules_nodejs_version", "node_repositories", "yarn_install")
check_rules_nodejs_version(minimum_version_string = "1.7.0")
check_rules_nodejs_version(minimum_version_string = "2.2.0")
# Setup the Node.js toolchain
node_repositories(
@ -39,23 +39,18 @@ yarn_install(
yarn_lock = "//:yarn.lock",
)
# Install all bazel dependencies of the @npm npm packages
load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
install_bazel_dependencies()
# Load angular dependencies
load("//packages/bazel:package.bzl", "rules_angular_dev_dependencies")
rules_angular_dev_dependencies()
# Load protractor dependencies
load("@npm_bazel_protractor//:package.bzl", "npm_bazel_protractor_dependencies")
load("@npm//@bazel/protractor:package.bzl", "npm_bazel_protractor_dependencies")
npm_bazel_protractor_dependencies()
# Load karma dependencies
load("@npm_bazel_karma//:package.bzl", "npm_bazel_karma_dependencies")
load("@npm//@bazel/karma:package.bzl", "npm_bazel_karma_dependencies")
npm_bazel_karma_dependencies()
@ -68,11 +63,6 @@ load("//dev-infra/browsers:browser_repositories.bzl", "browser_repositories")
browser_repositories()
# Setup the rules_typescript tooolchain
load("@npm_bazel_typescript//:index.bzl", "ts_setup_workspace")
ts_setup_workspace()
# Setup the rules_sass toolchain
load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories")
@ -91,8 +81,8 @@ rbe_autoconfig(
# Need to specify a base container digest in order to ensure that we can use the checked-in
# platform configurations for the "ubuntu16_04" image. Otherwise the autoconfig rule would
# need to pull the image and run it in order determine the toolchain configuration. See:
# https://github.com/bazelbuild/bazel-toolchains/blob/3.2.0/configs/ubuntu16_04_clang/versions.bzl
base_container_digest = "sha256:5e750dd878df9fcf4e185c6f52b9826090f6e532b097f286913a428290622332",
# https://github.com/bazelbuild/bazel-toolchains/blob/3.5.1/configs/ubuntu16_04_clang/versions.bzl
base_container_digest = "sha256:f6568d8168b14aafd1b707019927a63c2d37113a03bcee188218f99bd0327ea1",
# Note that if you change the `digest`, you might also need to update the
# `base_container_digest` to make sure marketplace.gcr.io/google/rbe-ubuntu16-04-webtest:<digest>
# and marketplace.gcr.io/google/rbe-ubuntu16-04:<base_container_digest> have

View File

@ -36,8 +36,9 @@ Here are the most important tasks you might need to use:
* `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally.
* `yarn boilerplate:add:viewengine` - same as `boilerplate:add` but also turns on `ViewEngine` (pre-Ivy) mode.
* `yarn boilerplate:remove` - remove all the boilerplate code that was added via `yarn boilerplate:add`.
* `yarn create-example` - create a new example directory containing initial source files.
* `yarn generate-stackblitz` - generate the stackblitz files that are used by the `live-example` tags in the docs.
* `yarn generate-zips` - generate the zip files from the examples. Zip available via the `live-example` tags in the docs.

View File

@ -32,6 +32,8 @@
**/karma-test-shim.js
**/browser-test-shim.js
**/node_modules
**/yarn.lock
**/package-lock.json
# built files
*.map

View File

@ -12,7 +12,7 @@ describe('Accessibility example e2e tests', () => {
it('should take a number and change progressbar width', () => {
element(by.css('input')).sendKeys('16');
expect(element(by.css('input')).getAttribute('value')).toEqual('016');
expect(element(by.css('input')).getAttribute('value')).toEqual('16');
expect(element(by.css('app-example-progressbar div')).getCssValue('width')).toBe('48px');
});

View File

@ -3,7 +3,7 @@
<label>
Enter an example progress value
<input type="number" min="0" max="100"
[value]="progress" (input)="progress = $event.target.value">
[value]="progress" (input)="setProgress($event)">
</label>
<!-- The user of the progressbar sets an aria-label to communicate what the progress means. -->

View File

@ -7,4 +7,8 @@ import { Component } from '@angular/core';
})
export class AppComponent {
progress = 0;
setProgress($event: Event) {
this.progress = +($event.target as HTMLInputElement).value;
}
}

View File

@ -3,8 +3,10 @@
<h2>Attribute binding</h2>
<!-- #docregion attrib-binding-colspan -->
<table border=1>
<!-- #docregion colspan -->
<!-- expression calculates colspan=2 -->
<tr><td [attr.colspan]="1 + 1">One-Two</td></tr>
<!-- #enddocregion colspan -->
<!-- ERROR: There is no `colspan` property to set!
<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
@ -32,31 +34,31 @@
<!-- #docregion basic-specificity -->
<h3>Basic specificity</h3>
<!-- The `class.special` binding will override any value for the `special` class in `classExpr`. -->
<div [class.special]="isSpecial" [class]="classExpr">Some text.</div>
<!-- The `class.special` binding overrides any value for the `special` class in `classExpression`. -->
<div [class.special]="isSpecial" [class]="classExpression">Some text.</div>
<!-- The `style.color` binding will override any value for the `color` property in `styleExpr`. -->
<div [style.color]="color" [style]="styleExpr">Some text.</div>
<!-- The `style.color` binding overrides any value for the `color` property in `styleExpression`. -->
<div [style.color]="color" [style]="styleExpression">Some text.</div>
<!-- #enddocregion basic-specificity -->
<!-- #docregion source-specificity -->
<h3>Source specificity</h3>
<!-- The `class.special` template binding will override any host binding to the `special` class set by `dirWithClassBinding` or `comp-with-host-binding`.-->
<!-- The `class.special` template binding overrides any host binding to the `special` class set by `dirWithClassBinding` or `comp-with-host-binding`.-->
<comp-with-host-binding [class.special]="isSpecial" dirWithClassBinding>Some text.</comp-with-host-binding>
<!-- The `style.color` template binding will override any host binding to the `color` property set by `dirWithStyleBinding` or `comp-with-host-binding`. -->
<!-- The `style.color` template binding overrides any host binding to the `color` property set by `dirWithStyleBinding` or `comp-with-host-binding`. -->
<comp-with-host-binding [style.color]="color" dirWithStyleBinding>Some text.</comp-with-host-binding>
<!-- #enddocregion source-specificity -->
<!-- #docregion dynamic-priority -->
<h3>Dynamic vs static</h3>
<!-- If `classExpr` has a value for the `special` class, this value will override the `class="special"` below -->
<div class="special" [class]="classExpr">Some text.</div>
<!-- If `classExpression` has a value for the `special` class, this value overrides the `class="special"` below -->
<div class="special" [class]="classExpression">Some text.</div>
<!-- If `styleExpr` has a value for the `color` property, this value will override the `style="color: blue"` below -->
<div style="color: blue" [style]="styleExpr">Some text.</div>
<!-- If `styleExpression` has a value for the `color` property, this value overrides the `style="color: blue"` below -->
<div style="color: blue" [style]="styleExpression">Some text.</div>
<!-- #enddocregion dynamic-priority -->

View File

@ -9,7 +9,7 @@ export class AppComponent {
actionName = 'Go for it';
isSpecial = true;
canSave = true;
classExpr = 'special clearance';
styleExpr = 'color: red';
classExpression = 'special clearance';
styleExpression = 'color: red';
color = 'blue';
}

View File

@ -11,6 +11,9 @@ export class CompWithHostBindingComponent {
@HostBinding('style.color')
color = 'green';
// #docregion hostbinding
@HostBinding('style.width')
width = '200px';
// #enddocregion hostbinding
}

View File

@ -0,0 +1,13 @@
import { browser, element, by } from 'protractor';
describe('Component Overview', () => {
beforeAll(() => {
browser.get('');
});
it('should display component overview works ', () => {
expect(element(by.css('p')).getText()).toEqual('component-overview works!');
});
});

View File

@ -0,0 +1 @@
<app-component-overview></app-component-overview>

View File

@ -0,0 +1,31 @@
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'component-overview'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('component-overview');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.querySelector('.content span').textContent).toContain('component-overview app is running!');
});
});

View File

@ -0,0 +1,10 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'component-overview';
}

View File

@ -0,0 +1,18 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { ComponentOverviewComponent } from './component-overview/component-overview.component';
@NgModule({
declarations: [
AppComponent,
ComponentOverviewComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@ -0,0 +1,14 @@
// #docplaster
import { Component } from '@angular/core';
// #docregion template
@Component({
selector: 'app-component-overview',
template: '<h1>Hello World!</h1>',
})
// #enddocregion template
export class ComponentOverviewComponent {
}

View File

@ -0,0 +1,16 @@
// #docplaster
import { Component } from '@angular/core';
// #docregion templatebacktick
@Component({
selector: 'app-component-overview',
template: `<h1>Hello World!</h1>
<p>This template definition spans
multiple lines.</p>`
})
// #enddocregion templatebacktick
export class ComponentOverviewComponent {
}

View File

@ -0,0 +1,15 @@
// #docplaster
import { Component } from '@angular/core';
// #docregion styles
@Component({
selector: 'app-component-overview',
template: '<h1>Hello World!</h1>',
styles: ['h1 { font-weight: normal; }']
})
// #enddocregion styles
export class ComponentOverviewComponent {
}

View File

@ -0,0 +1 @@
<p>component-overview works!</p>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentOverviewComponent } from './component-overview.component';
describe('ComponentOverviewComponent', () => {
let component: ComponentOverviewComponent;
let fixture: ComponentFixture<ComponentOverviewComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ComponentOverviewComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ComponentOverviewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,22 @@
// #docplaster
// #docregion import
import { Component } from '@angular/core';
// #enddocregion import
// #docregion decorator, decorator-skeleton, selector, templateUrl
@Component({
// #enddocregion decorator-skeleton
selector: 'app-component-overview',
// #enddocregion selector
templateUrl: './component-overview.component.html',
// #enddocregion templateUrl
styleUrls: ['./component-overview.component.css']
// #docregion decorator-skeleton, selector, templateUrl
})
// #enddocregion decorator, decorator-skeleton, selector, templateUrl
// #docregion class
export class ComponentOverviewComponent {
}
// #enddocregion class

View File

@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ComponentOverview</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>

View File

@ -0,0 +1,12 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));

View File

@ -0,0 +1,8 @@
{
"description": "Component Overview",
"files":[
"!**/*.d.ts",
"!**/*.js"
],
"tags":["overview", "component"]
}

View File

@ -7,9 +7,15 @@ import { Component } from '@angular/core';
styleUrls: ['./app.component.css']
})
export class AppComponent {
// #docregion item-image
itemImageUrl = '../assets/phone.png';
// #enddocregion item-image
// #docregion boolean
isUnchanged = true;
// #enddocregion boolean
// #docregion directive-property
classes = 'special';
// #enddocregion directive-property
// #docregion parent-data-type
parentItem = 'lamp';
// #enddocregion parent-data-type

View File

@ -23,13 +23,13 @@ describe('retry-on-error', () => {
docRegionDefault(mockConsole, ajax);
expect(mockConsole.log.calls.allArgs()).toEqual([
['Subscribed to AJAX'],
['Error occured.'],
['Error occurred.'],
['Subscribed to AJAX'],
['Error occured.'],
['Error occurred.'],
['Subscribed to AJAX'],
['Error occured.'],
['Error occurred.'],
['Subscribed to AJAX'],
['Error occured.'],
['Error occurred.'],
['data: ', []],
]);
});

View File

@ -17,7 +17,7 @@ export function docRegionDefault(console, ajax) {
const apiData = ajax('/api/data').pipe(
map((res: any) => {
if (!res.response) {
console.log('Error occured.');
console.log('Error occurred.');
throw new Error('Value expected!');
}
return res.response;

View File

@ -89,7 +89,7 @@ This example from the `HeroListComponent` template uses three of these forms.
<code-example path="architecture/src/app/hero-list.component.1.html" header="src/app/hero-list.component.html (binding)" region="binding"></code-example>
* The `{{hero.name}}` [*interpolation*](guide/displaying-data#interpolation)
* The `{{hero.name}}` [*interpolation*](guide/interpolation)
displays the component's `hero.name` property value within the `<li>` element.
* The `[hero]` [*property binding*](guide/property-binding) passes the value of
@ -166,8 +166,8 @@ The example template uses two built-in structural directives to add application
<code-example path="architecture/src/app/hero-list.component.1.html" header="src/app/hero-list.component.html (structural)" region="structural"></code-example>
* [`*ngFor`](guide/displaying-data#ngFor) is an iterative; it tells Angular to stamp out one `<li>` per hero in the `heroes` list.
* [`*ngIf`](guide/displaying-data#ngIf) is a conditional; it includes the `HeroDetail` component only if a selected hero exists.
* [`*ngFor`](guide/structural-directives#inside-ngfor) is an iterative; it tells Angular to stamp out one `<li>` per hero in the `heroes` list.
* [`*ngIf`](guide/structural-directives#ngif-case-study) is a conditional; it includes the `HeroDetail` component only if a selected hero exists.
#### Attribute directives

View File

@ -11,7 +11,7 @@ about the features and tools that can help you develop and deliver Angular appli
## Application architecture
* The [Components and templates](guide/displaying-data) guide explains how to connect the application data in your [components](guide/glossary#component) to your page-display [templates](guide/glossary#template), to create a complete interactive application.
* The **Main Concepts** section located in the table of contents contains several topics that explain how to connect the application data in your [components](guide/glossary#component) to your page-display [templates](guide/glossary#template), to create a complete interactive application.
* The [NgModules](guide/ngmodules) guide provides in-depth information on the modular structure of an Angular application.
@ -21,7 +21,7 @@ about the features and tools that can help you develop and deliver Angular appli
## Responsive programming
The **Components and Templates** guide provides guidance and details of the [template syntax](guide/template-syntax) that you use to display your component data when and where you want it within a view, and to collect input from users that you can respond to.
The [template syntax](guide/template-syntax) and related topics contain details about how to display your component data when and where you want it within a view, and how to collect input from users that you can respond to.
Additional pages and sections describe some basic programming techniques for Angular apps.
@ -52,8 +52,6 @@ For some platforms and applications, you might also want to use the PWA (Progres
## Support for the development cycle
The **Development Workflow** section describes the tools and processes you use to compile, test, and deploy Angular applications.
* [CLI Command Reference](cli): The Angular CLI is a command-line tool that you use to create projects, generate application and library code, and perform a variety of ongoing development tasks such as testing, bundling, and deployment.
* [Compilation](guide/aot-compiler): Angular provides just-in-time (JIT) compilation for the development environment, and ahead-of-time (AOT) compilation for the production environment.
@ -68,7 +66,6 @@ The **Development Workflow** section describes the tools and processes you use t
* [Accessibility](guide/accessibility): Make your app accessible to all users.
## File structure, configuration, and dependencies
* [Workspace and file structure](guide/file-structure): Understand the structure of Angular workspace and project folders.

View File

@ -5,7 +5,7 @@ Angular is written in TypeScript.
It implements core and optional functionality as a set of TypeScript libraries that you import into your apps.
The architecture of an Angular application relies on certain fundamental concepts.
The basic building blocks are *NgModules*, which provide a compilation context for *components*. NgModules collect related code into functional sets; an Angular app is defined by a set of NgModules. An app always has at least a *root module* that enables bootstrapping, and typically has many more *feature modules*.
The basic building blocks of the Angular framework are Angular components that are organized into *NgModules*. NgModules collect related code into functional sets; an Angular app is defined by a set of NgModules. An app always has at least a *root module* that enables bootstrapping, and typically has many more *feature modules*.
* Components define *views*, which are sets of screen elements that Angular can choose among and modify according to your program logic and data.

View File

@ -1,6 +1,7 @@
# Attribute, class, and style bindings
The template syntax provides specialized one-way bindings for scenarios less well-suited to property binding.
Attribute binding in Angular helps you set values for attributes directly.
With attribute binding, you can improve accessibility, style your application dynamically, and manage multiple CSS classes or styles simultaneously.
<div class="alert is-helpful">
@ -8,23 +9,36 @@ See the <live-example></live-example> for a working example containing the code
</div>
## Binding to an attribute
## Attribute binding
It is recommended that you set an element property with a [property binding](guide/property-binding) whenever possible.
However, sometimes you don't have an element property to bind.
In those situations, you can use attribute binding.
Set the value of an attribute directly with an **attribute binding**. This is the only exception to the rule that a binding sets a target property and the only binding that creates and sets an attribute.
For example, [ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) and
[SVG](https://developer.mozilla.org/en-US/docs/Web/SVG) are purely attributes.
Neither ARIA nor SVG correspond to element properties and don't set element properties.
In these cases, you must use attribute binding because there are no corresponding property targets.
Usually, setting an element property with a [property binding](guide/property-binding)
is preferable to setting the attribute with a string. However, sometimes
there is no element property to bind, so attribute binding is the solution.
Consider the [ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) and
[SVG](https://developer.mozilla.org/en-US/docs/Web/SVG). They are purely attributes, don't correspond to element properties, and don't set element properties. In these cases, there are no property targets to bind to.
## Syntax
Attribute binding syntax resembles property binding, but
instead of an element property between brackets, start with the prefix `attr`,
followed by a dot (`.`), and the name of the attribute.
You then set the attribute value, using an expression that resolves to a string,
or remove the attribute when the expression resolves to `null`.
Attribute binding syntax resembles [property binding](guide/property-binding), but instead of an element property between brackets, you precede the name of the attribute with the prefix `attr`, followed by a dot.
Then, you set the attribute value with an expression that resolves to a string.
<code-example language="html">
&lt;p [attr.attribute-you-are-targeting]="expression"&gt;&lt;/p&gt;
</code-example>
<div class="alert is-helpful">
When the expression resolves to `null`, Angular removes the attribute altogether.
</div>
## Binding ARIA attributes
One of the primary use cases for attribute binding
is to set ARIA attributes, as in this example:
@ -33,32 +47,30 @@ is to set ARIA attributes, as in this example:
{@a colspan}
## Binding to `colspan`
Another common use case for attribute binding is with the `colspan` attribute in tables.
Binding to the `colspan` attribute helps you keep your tables programmatically dynamic.
Depending on the amount of data that your application populates a table with, the number of columns that a row spans could change.
To use attribute binding with the `<td>` attribute `colspan`:
1. Specify the `colspan` attribute by using the following syntax: `[attr.colspan]`.
1. Set `[attr.colspan]` equal to an expression.
In the following example, binds the `colspan` attribute to the expression `1 + 1`.
<code-example path="attribute-binding/src/app/app.component.html" region="colspan" header="src/app/app.component.html"></code-example>
This binding causes the `<tr>` to span two columns.
<div class="alert is-helpful">
#### `colspan` and `colSpan`
Sometimes there are differences between the name of property and an attribute.
Notice the difference between the `colspan` attribute and the `colSpan` property.
If you wrote something like this:
<code-example language="html">
&lt;tr&gt;&lt;td colspan="{{1 + 1}}"&gt;Three-Four&lt;/td&gt;&lt;/tr&gt;
</code-example>
You'd get this error:
<code-example language="bash">
Template parse errors:
Can't bind to 'colspan' since it isn't a known native property
</code-example>
As the message says, the `<td>` element does not have a `colspan` property. This is true
because `colspan` is an attribute&mdash;`colSpan`, with a capital `S`, is the
corresponding property. Interpolation and property binding can set only *properties*, not attributes.
Instead, you'd use property binding and write it like this:
<code-example path="attribute-binding/src/app/app.component.html" region="colSpan" header="src/app/app.component.html"></code-example>
`colspan` is an attribute of `<tr>`, while `colSpan` with a capital "S" is a property.
When using attribute binding, use `colspan` with a lowercase "s".
For more information on how to bind to the `colSpan` property, see the [`colspan` and `colSpan`](guide/property-binding#colspan) section of [Property Binding](guide/property-binding).
</div>
@ -66,28 +78,32 @@ Instead, you'd use property binding and write it like this:
{@a class-binding}
## Class binding
## Binding to the `class` attribute
Here's how to set the `class` attribute without a binding in plain HTML:
You can use class binding to add and remove CSS class names from an element's `class` attribute.
```html
<!-- standard class attribute setting -->
<div class="foo bar">Some text</div>
```
### Binding to a single CSS `class`
You can also add and remove CSS class names from an element's `class` attribute with a **class binding**.
To create a single class binding, use the prefix `class` followed by a dot and the name of the CSS class&mdash;for example, `[class.sale]="onSale"`.
Angular adds the class when the bound expression, `onSale` is truthy, and it removes the class when the expression is falsy&mdash;with the exception of `undefined`.
See [styling delegation](guide/style-precedence#styling-delegation) for more information.
To create a single class binding, start with the prefix `class` followed by a dot (`.`) and the name of the CSS class (for example, `[class.foo]="hasFoo"`).
Angular adds the class when the bound expression is truthy, and it removes the class when the expression is falsy (with the exception of `undefined`, see [styling delegation](#styling-delegation)).
### Binding to multiple CSS classes
To create a binding to multiple classes, use a generic `[class]` binding without the dot (for example, `[class]="classExpr"`).
The expression can be a space-delimited string of class names, or you can format it as an object with class names as the keys and truthy/falsy expressions as the values.
With object format, Angular will add a class only if its associated value is truthy.
To bind to multiple classes, use `[class]` set to an expression&mdash;for example, `[class]="classExpression"`.
The expression can be a space-delimited string of class names, or an object with class names as the keys and truthy or falsy expressions as the values.
With an object format, Angular adds a class only if its associated value is truthy.
It's important to note that with any object-like expression (`object`, `Array`, `Map`, `Set`, etc), the identity of the object must change for the class list to be updated.
Updating the property without changing object identity will have no effect.
<div class="alert is-important">
If there are multiple bindings to the same class name, conflicts are resolved using [styling precedence](#styling-precedence).
With any object-like expression&mdash;such as `object`, `Array`, `Map`, or `Set`&mdash;the identity of the object must change for Angular to update the class list.
Updating the property without changing object identity has no effect.
</div>
If there are multiple bindings to the same class name, Angular uses [styling precedence](guide/style-precedence) to determine which binding to use.
The following table summarizes class binding syntax.
<style>
td, th {vertical-align: top}
@ -118,13 +134,13 @@ If there are multiple bindings to the same class name, conflicts are resolved us
</tr>
<tr>
<td>Single class binding</td>
<td><code>[class.foo]="hasFoo"</code></td>
<td><code>[class.sale]="onSale"</code></td>
<td><code>boolean | undefined | null</code></td>
<td><code>true</code>, <code>false</code></td>
</tr>
<tr>
<td rowspan=3>Multi-class binding</td>
<td rowspan=3><code>[class]="classExpr"</code></td>
<td rowspan=3><code>[class]="classExpression"</code></td>
<td><code>string</code></td>
<td><code>"my-class-1 my-class-2 my-class-3"</code></td>
</tr>
@ -138,44 +154,44 @@ If there are multiple bindings to the same class name, conflicts are resolved us
</tr>
</table>
The [NgClass](guide/built-in-directives/#ngclass) directive can be used as an alternative to direct `[class]` bindings.
However, using the above class binding syntax without `NgClass` is preferred because due to improvements in class binding in Angular, `NgClass` no longer provides significant value, and might eventually be removed in the future.
<hr/>
## Style binding
{@a style-binding}
Here's how to set the `style` attribute without a binding in plain HTML:
## Binding to the style attribute
```html
<!-- standard style attribute setting -->
<div style="color: blue">Some text</div>
```
You can use style binding to set styles dynamically.
You can also set styles dynamically with a **style binding**.
### Binding to a single style
To create a single style binding, start with the prefix `style` followed by a dot (`.`) and the name of the CSS style property (for example, `[style.width]="width"`).
The property will be set to the value of the bound expression, which is normally a string.
To create a single style binding, use the prefix `style` followed by a dot and the name of the CSS style property&mdash;for example, `[style.width]="width"`.
Angular sets the property to the value of the bound expression, which is usually a string.
Optionally, you can add a unit extension like `em` or `%`, which requires a number type.
<div class="alert is-helpful">
Note that a _style property_ name can be written in either
[dash-case](guide/glossary#dash-case), as shown above, or
[camelCase](guide/glossary#camelcase), such as `fontSize`.
You can write a style property name in either [dash-case](guide/glossary#dash-case), or
[camelCase](guide/glossary#camelcase).
</div>
If there are multiple styles you'd like to toggle, you can bind to the `[style]` property directly without the dot (for example, `[style]="styleExpr"`).
The expression attached to the `[style]` binding is most often a string list of styles like `"width: 100px; height: 100px;"`.
### Binding to multiple styles
You can also format the expression as an object with style names as the keys and style values as the values, like `{width: '100px', height: '100px'}`.
It's important to note that with any object-like expression (`object`, `Array`, `Map`, `Set`, etc), the identity of the object must change for the class list to be updated.
Updating the property without changing object identity will have no effect.
To toggle multiple styles, bind to the `[style]` attribute&mdash;for example, `[style]="styleExpression"`).
The expression is often a string list of styles such as `"width: 100px; height: 100px;"`.
If there are multiple bindings to the same style property, conflicts are resolved using [styling precedence rules](#styling-precedence).
You can also format the expression as an object with style names as the keys and style values as the values, such as `{width: '100px', height: '100px'}`.
<div class="alert is-important">
With any object-like expression&mdash;such as `object`, `Array`, `Map`, or `Set`&mdash;the identity of the object must change for Angular to update the class list.
Updating the property without changing object identity has no effect.
</div>
If there are multiple bindings to the same style attribute, Angular uses [styling precedence](guide/style-precedence) to determine which binding to use.
The following table summarizes style binding syntax.
<style>
td, th {vertical-align: top}
@ -219,7 +235,7 @@ If there are multiple bindings to the same style property, conflicts are resolve
</tr>
<tr>
<td rowspan=3>Multi-style binding</td>
<td rowspan=3><code>[style]="styleExpr"</code></td>
<td rowspan=3><code>[style]="styleExpression"</code></td>
<td><code>string</code></td>
<td><code>"width: 100px; height: 100px"</code></td>
</tr>
@ -232,72 +248,3 @@ If there are multiple bindings to the same style property, conflicts are resolve
<td><code>['width', '100px']</code></td>
</tr>
</table>
The [NgStyle](guide/built-in-directives/#ngstyle) directive can be used as an alternative to direct `[style]` bindings.
However, using the above style binding syntax without `NgStyle` is preferred because due to improvements in style binding in Angular, `NgStyle` no longer provides significant value, and might eventually be removed in the future.
<hr/>
{@a styling-precedence}
## Styling Precedence
A single HTML element can have its CSS class list and style values bound to multiple sources (for example, host bindings from multiple directives).
When there are multiple bindings to the same class name or style property, Angular uses a set of precedence rules to resolve conflicts and determine which classes or styles are ultimately applied to the element.
<div class="alert is-helpful">
<h4>Styling precedence (highest to lowest)</h4>
1. Template bindings
1. Property binding (for example, `<div [class.foo]="hasFoo">` or `<div [style.color]="color">`)
1. Map binding (for example, `<div [class]="classExpr">` or `<div [style]="styleExpr">`)
1. Static value (for example, `<div class="foo">` or `<div style="color: blue">`)
1. Directive host bindings
1. Property binding (for example, `host: {'[class.foo]': 'hasFoo'}` or `host: {'[style.color]': 'color'}`)
1. Map binding (for example, `host: {'[class]': 'classExpr'}` or `host: {'[style]': 'styleExpr'}`)
1. Static value (for example, `host: {'class': 'foo'}` or `host: {'style': 'color: blue'}`)
1. Component host bindings
1. Property binding (for example, `host: {'[class.foo]': 'hasFoo'}` or `host: {'[style.color]': 'color'}`)
1. Map binding (for example, `host: {'[class]': 'classExpr'}` or `host: {'[style]': 'styleExpr'}`)
1. Static value (for example, `host: {'class': 'foo'}` or `host: {'style': 'color: blue'}`)
</div>
The more specific a class or style binding is, the higher its precedence.
A binding to a specific class (for example, `[class.foo]`) will take precedence over a generic `[class]` binding, and a binding to a specific style (for example, `[style.bar]`) will take precedence over a generic `[style]` binding.
<code-example path="attribute-binding/src/app/app.component.html" region="basic-specificity" header="src/app/app.component.html"></code-example>
Specificity rules also apply when it comes to bindings that originate from different sources.
It's possible for an element to have bindings in the template where it's declared, from host bindings on matched directives, and from host bindings on matched components.
Template bindings are the most specific because they apply to the element directly and exclusively, so they have the highest precedence.
Directive host bindings are considered less specific because directives can be used in multiple locations, so they have a lower precedence than template bindings.
Directives often augment component behavior, so host bindings from components have the lowest precedence.
<code-example path="attribute-binding/src/app/app.component.html" region="source-specificity" header="src/app/app.component.html"></code-example>
In addition, bindings take precedence over static attributes.
In the following case, `class` and `[class]` have similar specificity, but the `[class]` binding will take precedence because it is dynamic.
<code-example path="attribute-binding/src/app/app.component.html" region="dynamic-priority" header="src/app/app.component.html"></code-example>
{@a styling-delegation}
### Delegating to styles with lower precedence
It is possible for higher precedence styles to "delegate" to lower precedence styles using `undefined` values.
Whereas setting a style property to `null` ensures the style is removed, setting it to `undefined` will cause Angular to fall back to the next-highest precedence binding to that style.
For example, consider the following template:
<code-example path="attribute-binding/src/app/app.component.html" region="style-delegation" header="src/app/app.component.html"></code-example>
Imagine that the `dirWithHostBinding` directive and the `comp-with-host-binding` component both have a `[style.width]` host binding.
In that case, if `dirWithHostBinding` sets its binding to `undefined`, the `width` property will fall back to the value of the `comp-with-host-binding` host binding.
However, if `dirWithHostBinding` sets its binding to `null`, the `width` property will be removed entirely.

View File

@ -194,7 +194,7 @@ which explains the following:
* Using [`<ng-container>`](guide/structural-directives#ngcontainer "<ng-container>")
to group elements when there is no suitable host element for the directive.
* How to write your own structural directive.
* That you can only apply [one structural directive](guide/structural-directives#one-per-element "one per host element") to an element.
* Why you [can only apply one structural directive](guide/structural-directives#one-per-element "one per host element") to an element.
</div>
@ -281,7 +281,7 @@ You define a block of HTML that defines how a single item should be displayed
and then you tell Angular to use that block as a template for rendering each item in the list.
The text assigned to `*ngFor` is the instruction that guides the repeater process.
The following example shows `NgFor` applied to a simple `<div>`. (Don't forget the asterisk (`*`) in front of `ngFor`.)
The following example shows `NgFor` applied to a simple `<div>`.
<code-example path="built-in-directives/src/app/app.component.html" region="NgFor-1" header="src/app/app.component.html"></code-example>

View File

@ -0,0 +1,182 @@
# Angular Components Overview
Components are the main building block for Angular applications. Each component consists of:
* An HTML template that declares what renders on the page
* A Typescript class that defines behavior
* A CSS selector that defines how the component is used in a template
* Optionally, CSS styles applied to the template
This topic describes how to create and configure an Angular component.
<div class="alert is-helpful">
To view or download the example code used in this topic, see the <live-example></live-example>.
</div>
## Prerequisites
To create a component, verify that you have met the following prerequisites:
1. Install the Angular CLI.
1. Create an Angular project.
If you don't have a project, you can create one using `ng new <project-name>`, where `<project-name>` is the name of your Angular application.
## Creating a component
The easiest way to create a component is with the Angular CLI. You can also create a component manually.
### Creating a component using the Angular CLI
To create a component using the Angular CLI:
1. From a terminal window, navigate to the directory containing your application.
1. Run the `ng generate component <component-name>` command, where `<component-name>` is the name of your new component.
By default, this command creates the following:
* A folder named after the component
* A component file, `<component-name>.component.ts`
* A template file, `<component-name>.component.ts`
* A CSS file, `<component-name>.component.css`
* A testing specification file, `<component-name>.component.spec.ts`
Where `<component-name>` is the name of your component.
<div class="alert is-helpful">
You can change how `ng generate component` creates new components.
For more information, see [ng generate component](cli/generate#component-command) in the Angular CLI documentation.
</div>
### Creating a component manually
Although the Angular CLI is the easiest way to create an Angular component, you can also create a component manually.
This section describes how to create the core component file within an existing Angular project.
To create a new component manually:
1. Navigate to your Angular project directory.
1. Create a new file, `<component-name>.component.ts`.
1. At the top of the file, add the following import statement.
<code-example
path="component-overview/src/app/component-overview/component-overview.component.ts"
region="import">
</code-example>
1. After the `import` statement, add a `@Component` decorator.
<code-example
path="component-overview/src/app/component-overview/component-overview.component.ts"
region="decorator-skeleton">
</code-example>
1. Choose a CSS selector for the component.
<code-example
path="component-overview/src/app/component-overview/component-overview.component.ts"
region="selector">
</code-example>
For more information on choosing a selector, see [Specifying a component's selector](#specifying-a-components-css-selector).
1. Define the HTML template that the component uses to display information.
In most cases, this template is a separate HTML file.
<code-example
path="component-overview/src/app/component-overview/component-overview.component.ts"
region="templateUrl">
</code-example>
For more information on defining a component's template, see [Defining a component's template](#defining-a-components-template).
1. Select the styles for the component's template.
In most cases, you define the styles for you component's template in a separate file.
<code-example
path="component-overview/src/app/component-overview/component-overview.component.ts"
region="decorator">
</code-example>
1. Add a `class` statement that includes the code for the component.
<code-example
path="component-overview/src/app/component-overview/component-overview.component.ts"
region="class">
</code-example>
## Specifying a component's CSS selector
Every component requires a CSS _selector_. A selector instructs Angular to instantiate this component wherever it finds the corresponding tag in template HTML. For example, consider a component, `hello-world.component.ts` that defines its selector as `app-hello-world`. This selector instructs angular to instantiate this component any time the tag, `<app-hellow-world>` in a template.
To specify a component's selector, add a `selector` statement to the `@Component` decorator.
<code-example
path="component-overview/src/app/component-overview/component-overview.component.ts"
region="selector">
</code-example>
## Defining a component's template
A template is a block of HTML that tells Angular how to render the component in your application.
You can define a template for your component in one of two ways: by referencing an external file, or directly within the component.
To define a template as an external file, add a `templateUrl` property to the `@Component` decorator.
<code-example
path="component-overview/src/app/component-overview/component-overview.component.ts"
region="templateUrl">
</code-example>
To define a template within the component, add a `template` property to the `@Component` decorator that contains the HTML you want to use.
<code-example
path="component-overview/src/app/component-overview/component-overview.component.1.ts"
region="template">
</code-example>
If your want your template to span multiple lines, you can use backticks (<code> ` </code>).
For example:
<code-example
path="component-overview/src/app/component-overview/component-overview.component.2.ts"
region="templatebacktick">
</code-example>
<div class="alert is-helpful">
An Angular component requires a template defined using `template` or `templateUrl`. You cannot have both statements in a component.
</div>
## Declaring a component's styles
You can declare component styles uses for its template in one of two ways: by referencing an external file, or directly within the component.
To declare the styles for a component in a separate file, add a `stylesUrls` property to the `@Component` decorator.
<code-example
path="component-overview/src/app/component-overview/component-overview.component.ts"
region="decorator">
</code-example>
To select the styles within the component, add a `styles` property to the `@Component` decorator that contains the styles you want to use.
<code-example
path="component-overview/src/app/component-overview/component-overview.component.3.ts"
region="styles">
</code-example>
The `styles` property takes an array of strings that contain the CSS rule declarations.
## Next steps
* For an archictural overview of components, see [Introduction to components and templates](guide/architecture-components).
* For additional options you can use when creating a component, see [Component](api/core/Component) in the API Reference.
* For more information on styling components, see [Component styles](guide/component-styles).
* For more information on templates, see [Template syntax](guide/template-syntax).

View File

@ -119,7 +119,7 @@ The `/deep/` combinator also has the aliases `>>>`, and `::ng-deep`.
Use `/deep/`, `>>>` and `::ng-deep` only with *emulated* view encapsulation.
Emulated is the default and most commonly used view encapsulation. For more information, see the
[Controlling view encapsulation](guide/component-styles#view-encapsulation) section.
[View Encapsulation](guide/view-encapsulation) section.
</div>
@ -267,89 +267,3 @@ as explained in the [CLI wiki](https://github.com/angular/angular-cli/wiki/stori
Style strings added to the `@Component.styles` array _must be written in CSS_ because the CLI cannot apply a preprocessor to inline styles.
</div>
{@a view-encapsulation}
## View encapsulation
As discussed earlier, component CSS styles are encapsulated into the component's view and don't
affect the rest of the application.
To control how this encapsulation happens on a *per
component* basis, you can set the *view encapsulation mode* in the component metadata.
Choose from the following modes:
* `ShadowDom` view encapsulation uses the browser's native shadow DOM implementation (see
[Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
on the [MDN](https://developer.mozilla.org) site)
to attach a shadow DOM to the component's host element, and then puts the component
view inside that shadow DOM. The component's styles are included within the shadow DOM.
* `Native` view encapsulation uses a now deprecated version of the browser's native shadow DOM implementation - [learn about the changes](https://hayato.io/2016/shadowdomv1/).
* `Emulated` view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing
(and renaming) the CSS code to effectively scope the CSS to the component's view.
For details, see [Inspecting generated CSS](guide/component-styles#inspect-generated-css) below.
* `None` means that Angular does no view encapsulation.
Angular adds the CSS to the global styles.
The scoping rules, isolations, and protections discussed earlier don't apply.
This is essentially the same as pasting the component's styles into the HTML.
To set the components encapsulation mode, use the `encapsulation` property in the component metadata:
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" header="src/app/quest-summary.component.ts"></code-example>
`ShadowDom` view encapsulation only works on browsers that have native support
for shadow DOM (see [Shadow DOM v1](https://caniuse.com/#feat=shadowdomv1) on the
[Can I use](http://caniuse.com) site). The support is still limited,
which is why `Emulated` view encapsulation is the default mode and recommended
in most cases.
{@a inspect-generated-css}
## Inspecting generated CSS
When using emulated view encapsulation, Angular preprocesses
all component styles so that they approximate the standard shadow CSS scoping rules.
In the DOM of a running Angular application with emulated view
encapsulation enabled, each DOM element has some extra attributes
attached to it:
<code-example format="">
&lt;hero-details _nghost-pmm-5>
&lt;h2 _ngcontent-pmm-5>Mister Fantastic&lt;/h2>
&lt;hero-team _ngcontent-pmm-5 _nghost-pmm-6>
&lt;h3 _ngcontent-pmm-6>Team&lt;/h3>
&lt;/hero-team>
&lt;/hero-detail>
</code-example>
There are two kinds of generated attributes:
* An element that would be a shadow DOM host in native encapsulation has a
generated `_nghost` attribute. This is typically the case for component host elements.
* An element within a component's view has a `_ngcontent` attribute
that identifies to which host's emulated shadow DOM this element belongs.
The exact values of these attributes aren't important. They are automatically
generated and you never refer to them in application code. But they are targeted
by the generated component styles, which are in the `<head>` section of the DOM:
<code-example format="">
[_nghost-pmm-5] {
display: block;
border: 1px solid black;
}
h3[_ngcontent-pmm-6] {
background-color: white;
border: 1px solid #777;
}
</code-example>
These styles are post-processed so that each selector is augmented
with `_nghost` or `_ngcontent` attribute selectors.
These extra selectors enable the scoping rules described in this page.

View File

@ -156,7 +156,7 @@ The library must be rebuilt on every change.
When linking a library, make sure that the build step runs in watch mode, and that the library's `package.json` configuration points at the correct entry points.
For example, `main` should point at a JavaScript file, not a TypeScript file.
## Use TypeScript path mapping for peer dependencies
### Use TypeScript path mapping for peer dependencies
Angular libraries should list all `@angular/*` dependencies as peer dependencies.
This ensures that when modules ask for Angular, they all get the exact same module.

View File

@ -97,7 +97,7 @@ For the simplest deployment, create a production build and copy the output direc
</code-example>
2. Copy _everything_ within the output folder (`dist/` by default) to a folder on the server.
2. Copy _everything_ within the output folder (`dist/project-name/` by default) to a folder on the server.
3. Configure the server to redirect requests for missing files to `index.html`.
Learn more about server-side redirects [below](#fallback).
@ -211,11 +211,11 @@ modified to serve `index.html`:
# .
# -- server.rb
# -- public
# |-- dist
# |-- project-name
# |-- index.html
get '/' do
folderDir = settings.public_folder + '/dist' # ng build output folder
folderDir = settings.public_folder + '/project-name' # ng build output folder
send_file File.join(folderDir, 'index.html')
end
```
@ -383,11 +383,11 @@ Build your app for production _including the source maps_
</code-example>
List the generated bundles in the `dist/` folder.
List the generated bundles in the `dist/project-name/` folder.
<code-example language="none" class="code-shell">
ls dist/*.js
ls dist/project-name/*.js
</code-example>
@ -396,7 +396,7 @@ The following example displays the graph for the _main_ bundle.
<code-example language="none" class="code-shell">
node_modules/.bin/source-map-explorer dist/main*
node_modules/.bin/source-map-explorer dist/project-name/main*
</code-example>

View File

@ -1,312 +0,0 @@
# Displaying data in views
Angular [components](guide/glossary#component) form the data structure of your application.
The HTML [template](guide/glossary#template) associated with a component provides the means to display that data in the context of a web page.
Together, a component's class and template form a [view](guide/glossary#view) of your application data.
The process of combining data values with their representation on the page is called [data binding](guide/glossary#data-binding).
You display your data to a user (and collect data from the user) by *binding* controls in the HTML template to the data properties of the component class.
In addition, you can add logic to the template by including [directives](guide/glossary#directive), which tell Angular how to modify the page as it is rendered.
Angular defines a *template language* that expands HTML notation with syntax that allows you to define various kinds of data binding and logical directives.
When the page is rendered, Angular interprets the template syntax to update the HTML according to your logic and current data state.
Before you read the complete [template syntax guide](guide/template-syntax), the exercises on this page give you a quick demonstration of how template syntax works.
In this demo, you'll create a component with a list of heroes.
You'll display the list of hero names and conditionally show a message below the list.
The final UI looks like this:
<div class="lightbox">
<img src="generated/images/guide/displaying-data/final.png" alt="Final UI">
</div>
<div class="alert is-helpful">
The <live-example></live-example> demonstrates all of the syntax and code snippets described in this page.
</div>
{@a interpolation}
## Showing component properties with interpolation
The easiest way to display a component property is to bind the property name through interpolation.
With interpolation, you put the property name in the view template, enclosed in double curly braces: `{{myHero}}`.
Use the CLI command [`ng new displaying-data`](cli/new) to create a workspace and app named `displaying-data`.
Delete the <code>app.component.html</code> file. It is not needed for this example.
Then modify the <code>app.component.ts</code> file by
changing the template and the body of the component.
When you're done, it should look like this:
<code-example path="displaying-data/src/app/app.component.1.ts" header="src/app/app.component.ts"></code-example>
You added two properties to the formerly empty component: `title` and `myHero`.
The template displays the two component properties using double curly brace
interpolation:
<code-example path="displaying-data/src/app/app.component.1.ts" header="src/app/app.component.ts (template)" region="template"></code-example>
<div class="alert is-helpful">
The template is a multi-line string within ECMAScript 2015 backticks (<code>\`</code>).
The backtick (<code>\`</code>)&mdash;which is *not* the same character as a single
quote (`'`)&mdash;allows you to compose a string over several lines, which makes the
HTML more readable.
</div>
Angular automatically pulls the value of the `title` and `myHero` properties from the component and
inserts those values into the browser. Angular updates the display
when these properties change.
<div class="alert is-helpful">
More precisely, the redisplay occurs after some kind of asynchronous event related to
the view, such as a keystroke, a timer completion, or a response to an HTTP request.
</div>
Notice that you don't call **new** to create an instance of the `AppComponent` class.
Angular is creating an instance for you. How?
The CSS `selector` in the `@Component` decorator specifies an element named `<app-root>`.
That element is a placeholder in the body of your `index.html` file:
<code-example path="displaying-data/src/index.html" header="src/index.html (body)" region="body"></code-example>
When you bootstrap with the `AppComponent` class (in <code>main.ts</code>), Angular looks for a `<app-root>`
in the `index.html`, finds it, instantiates an instance of `AppComponent`, and renders it
inside the `<app-root>` tag.
Now run the app. It should display the title and hero name:
<div class="lightbox">
<img src="generated/images/guide/displaying-data/title-and-hero.png" alt="Title and Hero">
</div>
The next few sections review some of the coding choices in the app.
## Choosing the template source
The `@Component` metadata tells Angular where to find the component's template.
You can store your component's template in one of two places.
* You can define the template *inline* using the `template` property of the `@Component` decorator. An inline template is useful for a small demo or test.
* Alternatively, you can define the template in a separate HTML file and link to that file in the `templateUrl` property of the `@Component` decorator. This configuration is typical for anything more complex than a small test or demo, and is the default when you generate a new component.
In either style, the template data bindings have the same access to the component's properties.
Here the app uses inline HTML because the template is small and the demo is simpler without the additional HTML file.
<div class="alert is-helpful">
By default, the Angular CLI command [`ng generate component`](cli/generate) generates components with a template file.
You can override that by adding the "-t" (short for `inlineTemplate=true`) option:
<code-example hideCopy language="sh" class="code-shell">
ng generate component hero -t
</code-example>
</div>
## Initialization
The following example uses variable assignment to initialize the components.
<code-example path="displaying-data/src/app/app-ctor.component.1.ts" region="class"></code-example>
You could instead declare and initialize the properties using a constructor.
This app uses more terse "variable assignment" style simply for brevity.
{@a ngFor}
## Add logic to loop through data
The `*ngFor` directive (predefined by Angular) lets you loop through data. The following example uses the directive to show all of the values in an array property.
To display a list of heroes, begin by adding an array of hero names to the component and redefine `myHero` to be the first name in the array.
<code-example path="displaying-data/src/app/app.component.2.ts" header="src/app/app.component.ts (class)" region="class"></code-example>
Now use the Angular `ngFor` directive in the template to display each item in the `heroes` list.
<code-example path="displaying-data/src/app/app.component.2.ts" header="src/app/app.component.ts (template)" region="template"></code-example>
This UI uses the HTML unordered list with `<ul>` and `<li>` tags. The `*ngFor`
in the `<li>` element is the Angular "repeater" directive.
It marks that `<li>` element (and its children) as the "repeater template":
<code-example path="displaying-data/src/app/app.component.2.ts" header="src/app/app.component.ts (li)" region="li"></code-example>
<div class="alert is-important">
Don't forget the leading asterisk (\*) in `*ngFor`. It is an essential part of the syntax.
Read more about `ngFor` and `*` in the [ngFor section](guide/built-in-directives#ngfor) of the [Built-in directives](guide/built-in-directives) page.
</div>
Notice the `hero` in the `ngFor` double-quoted instruction;
it is an example of a template input variable. Read
more about template input variables in the [microsyntax](guide/built-in-directives#microsyntax) section of
the [Built-in directives](guide/built-in-directives) page.
Angular duplicates the `<li>` for each item in the list, setting the `hero` variable
to the item (the hero) in the current iteration. Angular uses that variable as the
context for the interpolation in the double curly braces.
<div class="alert is-helpful">
In this case, `ngFor` is displaying an array, but `ngFor` can
repeat items for any [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) object.
</div>
Now the heroes appear in an unordered list.
<div class="lightbox">
<img src="generated/images/guide/displaying-data/hero-names-list.png" alt="After ngfor">
</div>
## Creating a class for the data
The app's code defines the data directly inside the component, which isn't best practice.
In a simple demo, however, it's fine.
At the moment, the binding is to an array of strings.
In real applications, most bindings are to more specialized objects.
To convert this binding to use specialized objects, turn the array
of hero names into an array of `Hero` objects. For that you'll need a `Hero` class:
<code-example language="sh" class="code-shell">
ng generate class hero
</code-example>
This command creates the following code.
<code-example path="displaying-data/src/app/hero.ts" header="src/app/hero.ts"></code-example>
You've defined a class with a constructor and two properties: `id` and `name`.
It might not look like the class has properties, but it does.
The declaration of the constructor parameters takes advantage of a TypeScript shortcut.
Consider the first parameter:
<code-example path="displaying-data/src/app/hero.ts" header="src/app/hero.ts (id)" region="id"></code-example>
That brief syntax does a lot:
* Declares a constructor parameter and its type.
* Declares a public property of the same name.
* Initializes that property with the corresponding argument when creating an instance of the class.
### Using the Hero class
After importing the `Hero` class, the `AppComponent.heroes` property can return a _typed_ array
of `Hero` objects:
<code-example path="displaying-data/src/app/app.component.3.ts" header="src/app/app.component.ts (heroes)" region="heroes"></code-example>
Next, update the template.
At the moment it displays the hero's `id` and `name`.
Fix that to display only the hero's `name` property.
<code-example path="displaying-data/src/app/app.component.3.ts" header="src/app/app.component.ts (template)" region="template"></code-example>
The display looks the same, but the code is clearer.
{@a ngIf}
## Conditional display with NgIf
Sometimes an app needs to display a view or a portion of a view only under specific circumstances.
Let's change the example to display a message if there are more than three heroes.
The Angular `ngIf` directive inserts or removes an element based on a _truthy/falsy_ condition.
To see it in action, add the following paragraph at the bottom of the template:
<code-example path="displaying-data/src/app/app.component.ts" header="src/app/app.component.ts (message)" region="message"></code-example>
<div class="alert is-important">
Don't forget the leading asterisk (\*) in `*ngIf`. It is an essential part of the syntax.
Read more about `ngIf` and `*` in the [ngIf section](guide/built-in-directives#ngIf) of the [Built-in directives](guide/built-in-directives) page.
</div>
The template expression inside the double quotes,
`*ngIf="heroes.length > 3"`, looks and behaves much like TypeScript.
When the component's list of heroes has more than three items, Angular adds the paragraph
to the DOM and the message appears.
If there are three or fewer items, Angular omits the paragraph, so no message appears.
For more information, see [template expression operators](guide/interpolation#template-expressions).
<div class="alert is-helpful">
Angular isn't showing and hiding the message. It is adding and removing the paragraph element from the DOM. That improves performance, especially in larger projects when conditionally including or excluding
big chunks of HTML with many data bindings.
</div>
Try it out. Because the array has four items, the message should appear.
Go back into <code>app.component.ts</code> and delete or comment out one of the elements from the heroes array.
The browser should refresh automatically and the message should disappear.
## Summary
Now you know how to use:
* **Interpolation** with double curly braces to display a component property.
* **ngFor** to display an array of items.
* A TypeScript class to shape the **model data** for your component and display properties of that model.
* **ngIf** to conditionally display a chunk of HTML based on a boolean expression.
Here's the final code:
<code-tabs>
<code-pane header="src/app/app.component.ts" path="displaying-data/src/app/app.component.ts" region="final">
</code-pane>
<code-pane header="src/app/hero.ts" path="displaying-data/src/app/hero.ts">
</code-pane>
<code-pane header="src/app/app.module.ts" path="displaying-data/src/app/app.module.ts">
</code-pane>
<code-pane header="main.ts" path="displaying-data/src/main.ts">
</code-pane>
</code-tabs>

View File

@ -4,7 +4,7 @@ An entry component is any component that Angular loads imperatively, (which mean
<div class="alert is-helpful">
To contrast the two types of components, there are components which are included in the template, which are declarative. Additionally, there are components which you load imperatively; that is, entry components.
To contrast the two types of components, there are components which are included in the template, which are declarative. Additionally, there are components which you load imperatively; that is, entry components.
</div>
@ -75,11 +75,10 @@ All router components must be entry components. Because this would require you t
## The `entryComponents` array
<div class="alert is-helpful">
Since 9.0.0 with Ivy, the `entryComponents` property is no longer necessary. See [deprecations guide](guide/deprecations#entryComponents).
Since 9.0.0 with Ivy, the `entryComponents` property is no longer necessary. See [deprecations guide](guide/deprecations#entryComponents).
</div>
Though the `@NgModule` decorator has an `entryComponents` array, most of the time

View File

@ -99,7 +99,7 @@ in the `$event` variable.
## Template statements have side effects
Though [template expressions](guide/interpolation#template-expressions) shouldn't have [side effects](guide/property-binding#avoid-side-effects), template
Though [template expressions](guide/interpolation#template-expressions) shouldn't have [side effects](guide/property-binding-best-practices#avoid-side-effects), template
statements usually do. The `deleteItem()` method does have
a side effect: it deletes an item.

View File

@ -627,10 +627,11 @@ The [npm package manager](https://docs.npmjs.com/getting-started/what-is-npm) is
Learn more about how Angular uses [Npm Packages](guide/npm-packages).
{@ ngc}
{@a ngc}
## ngc
`ngc` is a Typescript-to-Javascript transpiler that processes Angular decorators, metadata, and templates, and emits JavaScript code.
The most recent implementation is internally refered to as `ngtsc` because it's a minimalistic wrapper around the TypeScript compiler `tsc` that adds a transform for processing Angular code.
The most recent implementation is internally referred to as `ngtsc` because it's a minimalistic wrapper around the TypeScript compiler `tsc` that adds a transform for processing Angular code.
{@a O}

View File

@ -397,7 +397,7 @@ The following code example binds an observable of message strings
## Caching HTTP requests
To [communicate with backend services using HTTP](/guide/http "Communicating with backend services using HTTP"), the `HttpClient` service uses observables and offers the `HTTPClient.get()` method to fetch data from a server.
The aynchronous method sends an HTTP request, and returns an observable that emits the requested data for the response.
The asynchronous method sends an HTTP request, and returns an observable that emits the requested data for the response.
As shown in the previous section, you can use the impure `AsyncPipe` to accept an observable as input and subscribe to the input automatically.
You can also create an impure pipe to make and cache an HTTP request.

View File

@ -0,0 +1,65 @@
# Property binding best practices
By following a few guidelines, you can use property binding in a way that helps you minimize bugs and keep your code readable.
<div class="alert is-helpful">
See the <live-example name="property-binding"></live-example> for a working example containing the code snippets in this guide.
</div>
## Avoid side effects
Evaluation of a template expression should have no visible side effects.
Use the syntax for template expressions to help avoid side effects.
In general, the correct syntax prevents you from assigning a value to anything in a property binding expression.
The syntax also prevents you from using increment and decrement operators.
### An example of producing side effects
If you had an expression that changed the value of something else that you were binding to, that change of value would be a side effect.
Angular might or might not display the changed value.
If Angular does detect the change, it throws an error.
As a best practice, use only properties and methods that return values.
## Return the proper type
A template expression should evaluate to the type of value that the target property expects.
For example, return a string if the target property expects a string, a number if it expects a number, or an object if it expects an object.
### Passing in a string
In the following example, the `childItem` property of the `ItemDetailComponent` expects a string.
<code-example path="property-binding/src/app/app.component.html" region="model-property-binding" header="src/app/app.component.html"></code-example>
You can confirm this expectation by looking in the `ItemDetailComponent` where the `@Input()` type is `string`:
<code-example path="property-binding/src/app/item-detail/item-detail.component.ts" region="input-type" header="src/app/item-detail/item-detail.component.ts (setting the @Input() type)"></code-example>
The `parentItem` in `AppComponent` is a string, which means that the expression, `parentItem` within `[childItem]="parentItem"`, evaluates to a string.
<code-example path="property-binding/src/app/app.component.ts" region="parent-data-type" header="src/app/app.component.ts"></code-example>
If `parentItem` were some other type, you would need to specify `childItem` `@Input()` as that type as well.
### Passing in an object
In this example, `ItemListComponent` is a child component of `AppComponent` and the `items` property expects an array of objects.
<code-example path="property-binding/src/app/app.component.html" region="pass-object" header="src/app/app.component.html"></code-example>
In the `ItemListComponent` the `@Input()`, `items`, has a type of `Item[]`.
<code-example path="property-binding/src/app/item-list/item-list.component.ts" region="item-input" header="src/app/item-list.component.ts"></code-example>
Notice that `Item` is an object that it has two properties; an `id` and a `name`.
<code-example path="property-binding/src/app/item.ts" region="item-class" header="src/app/item.ts"></code-example>
In `app.component.ts`, `currentItems` is an array of objects in the same shape as the `Item` object in `items.ts`, with an `id` and a `name`.
<code-example path="property-binding/src/app/app.component.ts" region="pass-object" header="src/app.component.ts"></code-example>
By supplying an object in the same shape, you satisfy the expectations of `items` when Angular evaluates the expression `currentItems`.

View File

@ -1,8 +1,8 @@
# Property binding `[property]`
# Property binding
Use property binding to _set_ properties of target elements or
directive `@Input()` decorators.
Property binding in Angular helps you set values for properties of HTML elements or directives.
With property binding, you can do things such as toggle button functionality, set paths programatically, and share values between components.
<div class="alert is-helpful">
@ -10,36 +10,86 @@ See the <live-example></live-example> for a working example containing the code
</div>
## One-way in
## Prerequisites
Property binding flows a value in one direction,
from a component's property into a target element property.
To get the most out of property binding, you should be familiar with the following:
You can't use property
binding to read or pull values out of target elements. Similarly, you cannot use
property binding to call a method on the target element.
If the element raises events, you can listen to them with an [event binding](guide/event-binding).
* [Basics of components](guide/architecture-components)
* [Basics of templates](guide/glossary#template)
* [Binding syntax](guide/binding-syntax)
If you must read a target element property or call one of its methods,
see the API reference for [ViewChild](api/core/ViewChild) and
[ContentChild](api/core/ContentChild).
<hr />
## Examples
## Understanding the flow of data
The most common property binding sets an element property to a component
property value. An example is
binding the `src` property of an image element to a component's `itemImageUrl` property:
Property binding moves a value in one direction, from a component's property into a target element property.
<div class="alert is-helpful">
For more information on listening for events, see [Event binding](guide/event-binding).
</div>
To read a target element property or call one of its methods, see the API reference for [ViewChild](api/core/ViewChild) and [ContentChild](api/core/ContentChild).
## Binding to a property
To bind to an element's property, enclose it in square brackets, `[]`, which identifies the property as a target property.
A target property is the DOM property to which you want to assign a value.
For example, the target property in the following code is the image element's `src` property.
<code-example path="property-binding/src/app/app.component.html" region="property-binding" header="src/app/app.component.html"></code-example>
Here's an example of binding to the `colSpan` property. Notice that it's not `colspan`,
which is the attribute, spelled with a lowercase `s`.
<code-example path="property-binding/src/app/app.component.html" region="colSpan" header="src/app/app.component.html"></code-example>
In most cases, the target name is the name of a property, even when it appears to be the name of an attribute.
In this example, `src` is the name of the `<img>` element property.
For more details, see the [MDN HTMLTableCellElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement) documentation.
The brackets, `[]`, cause Angular to evaluate the right-hand side of the assignment as a dynamic expression.
Without the brackets, Angular treats the the right-hand side as a string literal and sets the property to that static value.
<code-example path="property-binding/src/app/app.component.html" region="no-evaluation" header="src/app.component.html"></code-example>
Omitting the brackets renders the string `parentItem`, not the value of `parentItem`.
## Setting an element property to a component property value
To bind the `src` property of an `<img>` element to a component's property, place the target, `src`, in square brackets followed by an equal sign and then the property.
The property here is `itemImageUrl`.
<code-example path="property-binding/src/app/app.component.html" region="property-binding" header="src/app/app.component.html"></code-example>
Declare the `itemImageUrl` property in the class, in this case `AppComponent`.
<code-example path="property-binding/src/app/app.component.ts" region="item-image" header="src/app/app.component.ts"></code-example>
{@a colspan}
#### `colspan` and `colSpan`
A common point of confusion is between the attribute, `colspan`, and the property, `colSpan`.
Notice that these two names differ by only a single letter.
If you wrote something like this:
<code-example language="html">
&lt;tr&gt;&lt;td colspan="{{1 + 1}}"&gt;Three-Four&lt;/td&gt;&lt;/tr&gt;
</code-example>
You'd get this error:
<code-example language="bash">
Template parse errors:
Can't bind to 'colspan' since it isn't a known native property
</code-example>
As the message says, the `<td>` element does not have a `colspan` property. This is true
because `colspan` is an attribute&mdash;`colSpan`, with a capital `S`, is the
corresponding property. Interpolation and property binding can set only *properties*, not attributes.
Instead, you'd use property binding and write it like this:
<code-example path="attribute-binding/src/app/app.component.html" region="colSpan" header="src/app/app.component.html"></code-example>
For more information about `colSpan` and `colspan`, see the [Attribute binding](guide/attribute-binding#colspan) guide.
Another example is disabling a button when the component says that it `isUnchanged`:
@ -54,175 +104,100 @@ for parent and child components to communicate:
<code-example path="property-binding/src/app/app.component.html" region="model-property-binding" header="src/app/app.component.html"></code-example>
## Binding targets
An element property between enclosing square brackets identifies the target property.
The target property in the following code is the image element's `src` property.
## Toggling button functionality
<code-example path="property-binding/src/app/app.component.html" region="property-binding" header="src/app/app.component.html"></code-example>
To disable a button's functionality depending on a Boolean value, bind the DOM `disabled` property to a property in the class that is `true` or `false`.
There's also the `bind-` prefix alternative:
<code-example path="property-binding/src/app/app.component.html" region="disabled-button" header="src/app/app.component.html"></code-example>
<code-example path="property-binding/src/app/app.component.html" region="bind-prefix" header="src/app/app.component.html"></code-example>
Because the value of the property `isUnchanged` is `true` in the `AppComponent`, Angular disables the button.
<code-example path="property-binding/src/app/app.component.ts" region="boolean" header="src/app/app.component.ts"></code-example>
In most cases, the target name is the name of a property, even
when it appears to be the name of an attribute.
So in this case, `src` is the name of the `<img>` element property.
## Setting a directive property
Element properties may be the more common targets,
but Angular looks first to see if the name is a property of a known directive,
as it is in the following example:
To set a property of a directive, place the directive within square brackets , such as `[ngClass]`, followed by an equal sign and the property.
Here, the property is `classes`.
<code-example path="property-binding/src/app/app.component.html" region="class-binding" header="src/app/app.component.html"></code-example>
Technically, Angular is matching the name to a directive `@Input()`,
one of the property names listed in the directive's `inputs` array
or a property decorated with `@Input()`.
Such inputs map to the directive's own properties.
To use the property, you must declare it in the class, which in this example is `AppComponent`.
The value of `classes` is `special`.
If the name fails to match a property of a known directive or element, Angular reports an “unknown directive” error.
<code-example path="property-binding/src/app/app.component.ts" region="directive-property" header="src/app/app.component.ts"></code-example>
<div class="alert is-helpful">
Angular applies the class `special` to the `<p>` element so that you can use `special` to apply CSS styles.
Though the target name is usually the name of a property,
there is an automatic attribute-to-property mapping in Angular for
several common attributes. These include `class`/`className`, `innerHtml`/`innerHTML`, and
`tabindex`/`tabIndex`.
## Bind values between components
</div>
## Avoid side effects
Evaluation of a template expression should have no visible side effects.
The expression language itself, or the way you write template expressions,
helps to a certain extent;
you can't assign a value to anything in a property binding expression
nor use the increment and decrement operators.
For example, you could have an expression that invoked a property or method that had
side effects. The expression could call something like `getFoo()` where only you
know what `getFoo()` does. If `getFoo()` changes something
and you happen to be binding to that something,
Angular may or may not display the changed value. Angular may detect the
change and throw a warning error.
As a best practice, stick to properties and to methods that return
values and avoid side effects.
## Return the proper type
The template expression should evaluate to the type of value
that the target property expects.
Return a string if the target property expects a string, a number if it
expects a number, an object if it expects an object, and so on.
In the following example, the `childItem` property of the `ItemDetailComponent` expects a string, which is exactly what you're sending in the property binding:
To set the model property of a custom component, place the target, here `childItem`, between square brackets `[]` followed by an equal sign and the property.
Here, the property is `parentItem`.
<code-example path="property-binding/src/app/app.component.html" region="model-property-binding" header="src/app/app.component.html"></code-example>
You can confirm this by looking in the `ItemDetailComponent` where the `@Input` type is set to a string:
<code-example path="property-binding/src/app/item-detail/item-detail.component.ts" region="input-type" header="src/app/item-detail/item-detail.component.ts (setting the @Input() type)"></code-example>
To use the target and the property, you must declare them in their respective classes.
Declare the target of `childItem` in its component class, in this case `ItemDetailComponent`.
For example, the following code declares the target of `childItem` in its component class, in this case `ItemDetailComponent`.
Then, the code contains an `@Input()` decorator with the `childItem` property so data can flow into it.
<code-example path="property-binding/src/app/item-detail/item-detail.component.ts" region="input-type" header="src/app/item-detail/item-detail.component.ts"></code-example>
Next, the code declares the property of `parentItem` in its component class, in this case `AppComponent`.
In this example the type of `childItem` is `string`, so `parentItem` needs to be a string.
Here, `parentItem` has the string value of `lamp`.
As you can see here, the `parentItem` in `AppComponent` is a string, which the `ItemDetailComponent` expects:
<code-example path="property-binding/src/app/app.component.ts" region="parent-data-type" header="src/app/app.component.ts"></code-example>
### Passing in an object
With this configuration, the view of `<app-item-detail>` uses the value of `lamp` for `childItem`.
The previous simple example showed passing in a string. To pass in an object,
the syntax and thinking are the same.
## Property binding and security
In this scenario, `ItemListComponent` is nested within `AppComponent` and the `items` property expects an array of objects.
<code-example path="property-binding/src/app/app.component.html" region="pass-object" header="src/app/app.component.html"></code-example>
The `items` property is declared in the `ItemListComponent` with a type of `Item` and decorated with `@Input()`:
<code-example path="property-binding/src/app/item-list/item-list.component.ts" region="item-input" header="src/app/item-list.component.ts"></code-example>
In this sample app, an `Item` is an object that has two properties; an `id` and a `name`.
<code-example path="property-binding/src/app/item.ts" region="item-class" header="src/app/item.ts"></code-example>
While a list of items exists in another file, `mock-items.ts`, you can
specify a different item in `app.component.ts` so that the new item will render:
<code-example path="property-binding/src/app/app.component.ts" region="pass-object" header="src/app.component.ts"></code-example>
You just have to make sure, in this case, that you're supplying an array of objects because that's the type of `Item` and is what the nested component, `ItemListComponent`, expects.
In this example, `AppComponent` specifies a different `item` object
(`currentItems`) and passes it to the nested `ItemListComponent`. `ItemListComponent` was able to use `currentItems` because it matches what an `Item` object is according to `item.ts`. The `item.ts` file is where
`ItemListComponent` gets its definition of an `item`.
## Remember the brackets
The brackets, `[]`, tell Angular to evaluate the template expression.
If you omit the brackets, Angular treats the string as a constant
and *initializes the target property* with that string:
<code-example path="property-binding/src/app/app.component.html" region="no-evaluation" header="src/app.component.html"></code-example>
Omitting the brackets will render the string
`parentItem`, not the value of `parentItem`.
## One-time string initialization
You *should* omit the brackets when all of the following are true:
* The target property accepts a string value.
* The string is a fixed value that you can put directly into the template.
* This initial value never changes.
You routinely initialize attributes this way in standard HTML, and it works
just as well for directive and component property initialization.
The following example initializes the `prefix` property of the `StringInitComponent` to a fixed string,
not a template expression. Angular sets it and forgets about it.
<code-example path="property-binding/src/app/app.component.html" region="string-init" header="src/app/app.component.html"></code-example>
The `[item]` binding, on the other hand, remains a live binding to the component's `currentItems` property.
## Property binding vs. interpolation
You often have a choice between interpolation and property binding.
The following binding pairs do the same thing:
<code-example path="property-binding/src/app/app.component.html" region="property-binding-interpolation" header="src/app/app.component.html"></code-example>
Interpolation is a convenient alternative to property binding in
many cases. When rendering data values as strings, there is no
technical reason to prefer one form to the other, though readability
tends to favor interpolation. However, *when setting an element
property to a non-string data value, you must use property binding*.
## Content security
Imagine the following malicious content.
Property binding can help keep content secure.
For example, consider the following malicious content.
<code-example path="property-binding/src/app/app.component.ts" region="malicious-content" header="src/app/app.component.ts"></code-example>
In the component template, the content might be used with interpolation:
The component template interpolates the content as follows:
<code-example path="property-binding/src/app/app.component.html" region="malicious-interpolated" header="src/app/app.component.html"></code-example>
Fortunately, Angular data binding is on alert for dangerous HTML. In the above case,
the HTML displays as is, and the Javascript does not execute. Angular **does not**
allow HTML with script tags to leak into the browser, neither with interpolation
nor property binding.
In the following example, however, Angular [sanitizes](guide/security#sanitization-and-security-contexts)
the values before displaying them.
<code-example path="property-binding/src/app/app.component.html" region="malicious-content" header="src/app/app.component.html"></code-example>
Interpolation handles the `<script>` tags differently than
property binding but both approaches render the
content harmlessly. The following is the browser output
of the `evilTitle` examples.
The browser doesn't process the HTML and instead displays it raw, as follows.
<code-example language="bash">
"Template &lt;script&gt;alert("evil never sleeps")&lt;/script&gt; Syntax" is the interpolated evil title.
</code-example>
Angular does not allow HTML with `<script>` tags, neither with [interpolation](guide/interpolation) nor property binding, which prevents the JavaScript from running.
In the following example, however, Angular [sanitizes](guide/security#sanitization-and-security-contexts) the values before displaying them.
<code-example path="property-binding/src/app/app.component.html" region="malicious-content" header="src/app/app.component.html"></code-example>
Interpolation handles the `<script>` tags differently than property binding, but both approaches render the content harmlessly.
The following is the browser output of the sanitized `evilTitle` example.
<code-example language="bash">
"Template Syntax" is the property bound evil title.
</code-example>
## Property binding and interpolation
Often [interpolation](guide/interpolation) and property binding can achieve the same results.
The following binding pairs do the same thing.
<code-example path="property-binding/src/app/app.component.html" region="property-binding-interpolation" header="src/app/app.component.html"></code-example>
You can use either form when rendering data values as strings, though interpolation is preferable for readability.
However, when setting an element property to a non-string data value, you must use property binding.
<hr />
## What's next
* [Property binding best practices](guide/property-binding-best-practices)

View File

@ -180,7 +180,7 @@ A form group tracks the status and changes for each of its controls, so if one o
<code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.html" region="formgroup" header="src/app/profile-editor/profile-editor.component.html (template form group)"></code-example>
Note that just as a form group contains a group of controls, the *profile form* `FormGroup` is bound to the `form` element with the `FormGroup` directive, creating a communication layer between the model and the form containing the inputs. The `formControlName` input provided by the `FormControlName` directive binds each individual input to the form control defined in `FormGroup`. The form controls communicate with their respective elements. They also communicate changes to the form group instance, which provides the source of truth for the model value.
Note that just as a form group contains a group of controls, the *profileForm* `FormGroup` is bound to the `form` element with the `FormGroup` directive, creating a communication layer between the model and the form containing the inputs. The `formControlName` input provided by the `FormControlName` directive binds each individual input to the form control defined in `FormGroup`. The form controls communicate with their respective elements. They also communicate changes to the form group instance, which provides the source of truth for the model value.
**Save form data**

View File

@ -1656,7 +1656,7 @@ _before_ the `AppRoutingModule`:
</code-tabs>
Remove the initial crisis center route from the `app-routing.module.ts` because now the `HeroesModule` and the `CrisisCenter` modules provide teh feature routes.
Remove the initial crisis center route from the `app-routing.module.ts` because now the `HeroesModule` and the `CrisisCenter` modules provide the feature routes.
The `app-routing.module.ts` file retains the top-level application routes such as the default and wildcard routes.

View File

@ -0,0 +1,133 @@
# Style Precedence
When there are multiple bindings to the same class name or style attribute, Angular uses a set of precedence rules to determine which classes or styles to apply to the element.
These rules specify an order for which style- and class-related bindings have priority.
This styling precedence is as follows, from the most specific with the highest priority to least specific with the lowest priorty:
1. Template bindings are the most specific because they apply to the element directly and exclusively, so they have the highest precedence.
<table width="100%">
<col width="40%"></col>
<col width="60%"></col>
<thead>
<tr>
<th>Binding type</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td>Property binding</td>
<td><code>&lt;div [class.foo]="hasFoo"&gt;</code><br><code>&lt;div [style.color]="color"&gt;</code></td>
</tr>
<tr>
<td>Map binding</td>
<td><code>&lt;div [class]="classExpression"&gt;</code><br><code>&lt;div [style]="styleExpression"&gt;</code></td>
</tr>
<tr>
<td>Static value</td>
<td><code>&lt;div class="foo"&gt;</code><br><code>&lt;div style="color: blue"&gt;</code></td>
</tr>
</tbody>
</table>
1. Directive host bindings are less specific because you can use directives in multiple locations, so they have a lower precedence than template bindings.
<table width="100%">
<col width="40%"></col>
<col width="60%"></col>
<thead>
<tr>
<th>Binding type</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td>Property binding</td>
<td><code>host: {'[class.foo]': 'hasFoo'}</code><br><code>host: {'[style.color]': 'color'}</code></td>
</tr>
<tr>
<td>Map binding</td>
<td><code>host: {'[class]': 'classExpr'}</code><br><code>host: {'[style]': 'styleExpr'}</code></td>
</tr>
<tr>
<td>Static value</td>
<td><code>host: {'class': 'foo'}</code><br><code>host: {'style': 'color: blue'}</code></td>
</tr>
</tbody>
</table>
1. Component host bindings have the lowest precedence.
<table width="100%">
<col width="40%"></col>
<col width="60%"></col>
<thead>
<tr>
<th>Binding type</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td>Property binding</td>
<td><code>host: {'[class.foo]': 'hasFoo'}</code><br><code>host: {'[style.color]': 'color'}</code></td>
</tr>
<tr>
<td>Map binding</td>
<td><code>host: {'[class]': 'classExpression'}</code><br><code>host: {'[style]': 'styleExpression'}</code></td>
</tr>
<tr>
<td>Static value</td>
<td><code>host: {'class': 'foo'}</code><br><code>host: {'style': 'color: blue'}</code></td>
</tr>
</tbody>
</table>
## Precedence and specificity
In the following example, binding to a specific class, as in `[class.special]`, takes precedence over a generic `[class]` binding.
Similarly, binding to a specific style, as in `[style.color]`, takes precedence over a generic `[style]` binding.
<code-example path="attribute-binding/src/app/app.component.html" region="basic-specificity" header="src/app/app.component.html"></code-example>
## Precedence and bindings from different sources
Specificity rules also apply to bindings even when they originate from different sources.
An element can have bindings that originate from its own template, from host bindings on matched directives, and from host bindings on matched components.
<code-example path="attribute-binding/src/app/app.component.html" region="source-specificity" header="src/app/app.component.html"></code-example>
## Precedence of bindings and static attributes
Bindings take precedence over static attributes because they are dynamic.
In the following case, `class` and `[class]` have similar specificity, but the `[class]` binding takes precedence.
<code-example path="attribute-binding/src/app/app.component.html" region="dynamic-priority" header="src/app/app.component.html"></code-example>
{@a styling-delegation}
## Delegating to styles with lower precedence
Higher precedence styles can defer to lower precedence styles using `undefined` values.
For example, consider the following template:
<code-example path="attribute-binding/src/app/app.component.html" region="style-delegation" header="src/app/app.component.html"></code-example>
Imagine that the `dirWithHostBinding` directive and the `comp-with-host-binding` component both have a `[style.width]` host binding.
<code-example path="attribute-binding/src/app/comp-with-host-binding.component.ts" region="hostbinding" header="src/app/comp-with-host-binding.component.ts and dirWithHostBinding.directive.ts"></code-example>
If `dirWithHostBinding` sets its binding to `undefined`, the `width` property falls back to the value of the `comp-with-host-binding` host binding.
<code-example header="dirWithHostBinding directive">
@HostBinding('style.width')
width = ''; // undefined
</code-example>
<div class="alert is-helpful">
If `dirWithHostBinding` sets its binding to `null`, Angular removes the `width` property entirely.
<code-example header="dirWithHostBinding">
@HostBinding('style.width')
width = null;
</code-example>
</div>

View File

@ -14,7 +14,7 @@ In the following example, the template statement `deleteHero()` appears in quote
<code-example path="template-syntax/src/app/app.component.html" region="context-component-statement" header="src/app/app.component.html"></code-example>
When the user clicks the **Delete hero** button, Angular calls the `deleteHero()` function in the component class.
When the user clicks the **Delete hero** button, Angular calls the `deleteHero()` method in the component class.
You can use template statements with elements, components, or directives in response to events.

View File

@ -479,6 +479,15 @@ using the `downgradeComponent()` method. The result is an AngularJS
<code-example path="upgrade-module/src/app/downgrade-static/app.module.ts" region="downgradecomponent" header="app.module.ts">
</code-example>
<div class="alert is-helpful">
By default, Angular change detection will also run on the component for every
AngularJS `$digest` cycle. If you wish to only have change detection run when
the inputs change, you can set `propagateDigest` to `false` when calling
`downgradeComponent()`.
</div>
Because `HeroDetailComponent` is an Angular component, you must also add it to the
`declarations` in the `AppModule`.

View File

@ -234,8 +234,8 @@ To fix this issue, listen to both the _Enter_ key and the _blur_ event.
## Put it all together
The previous page showed how to [display data](guide/displaying-data).
This page demonstrated event binding techniques.
This page demonstrated several event binding techniques.
Now, put it all together in a micro-app
that can display a list of heroes and add new heroes to the list.

View File

@ -0,0 +1,83 @@
# View encapsulation
In Angular, component CSS styles are encapsulated into the component's view and don't
affect the rest of the application.
To control how this encapsulation happens on a *per
component* basis, you can set the *view encapsulation mode* in the component metadata.
Choose from the following modes:
* `ShadowDom` view encapsulation uses the browser's native shadow DOM implementation (see
[Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM)
on the [MDN](https://developer.mozilla.org) site)
to attach a shadow DOM to the component's host element, and then puts the component
view inside that shadow DOM. The component's styles are included within the shadow DOM.
* `Native` view encapsulation uses a now deprecated version of the browser's native shadow DOM implementation - [learn about the changes](https://hayato.io/2016/shadowdomv1/).
* `Emulated` view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing
(and renaming) the CSS code to effectively scope the CSS to the component's view.
For details, see [Inspecting generated CSS](guide/view-encapsulation#inspect-generated-css) below.
* `None` means that Angular does no view encapsulation.
Angular adds the CSS to the global styles.
The scoping rules, isolations, and protections discussed earlier don't apply.
This is essentially the same as pasting the component's styles into the HTML.
To set the components encapsulation mode, use the `encapsulation` property in the component metadata:
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" header="src/app/quest-summary.component.ts"></code-example>
`ShadowDom` view encapsulation only works on browsers that have native support
for shadow DOM (see [Shadow DOM v1](https://caniuse.com/#feat=shadowdomv1) on the
[Can I use](http://caniuse.com) site). The support is still limited,
which is why `Emulated` view encapsulation is the default mode and recommended
in most cases.
{@a inspect-generated-css}
## Inspecting generated CSS
When using emulated view encapsulation, Angular preprocesses
all component styles so that they approximate the standard shadow CSS scoping rules.
In the DOM of a running Angular application with emulated view
encapsulation enabled, each DOM element has some extra attributes
attached to it:
<code-example format="">
&lt;hero-details _nghost-pmm-5>
&lt;h2 _ngcontent-pmm-5>Mister Fantastic&lt;/h2>
&lt;hero-team _ngcontent-pmm-5 _nghost-pmm-6>
&lt;h3 _ngcontent-pmm-6>Team&lt;/h3>
&lt;/hero-team>
&lt;/hero-detail>
</code-example>
There are two kinds of generated attributes:
* An element that would be a shadow DOM host in native encapsulation has a
generated `_nghost` attribute. This is typically the case for component host elements.
* An element within a component's view has a `_ngcontent` attribute
that identifies to which host's emulated shadow DOM this element belongs.
The exact values of these attributes aren't important. They are automatically
generated and you never refer to them in application code. But they are targeted
by the generated component styles, which are in the `<head>` section of the DOM:
<code-example format="">
[_nghost-pmm-5] {
display: block;
border: 1px solid black;
}
h3[_ngcontent-pmm-6] {
background-color: white;
border: 1px solid #777;
}
</code-example>
These styles are post-processed so that each selector is augmented
with `_nghost` or `_ngcontent` attribute selectors.
These extra selectors enable the scoping rules described in this page.

View File

@ -9,7 +9,7 @@ To understand the benefits of `NgZone`, it is important to have a clear grasp of
### Displaying and updating data in Angular
In Angular, you can [display data](guide/displaying-data) by binding controls in an HTML template to the properties of an Angular component.
In Angular, you can display data by binding controls in an HTML template to the properties of an Angular component.
<code-example path="displaying-data/src/app/app.component.1.ts" header="src/app/app.component.ts"></code-example>
@ -102,13 +102,13 @@ In Angular, this step is unnecessary. Whenever you update the data, your HTML is
To understand how change detection works, first consider when the application needs to update the HTML. Typically, updates occur for one of the following reasons:
1. Component initialization. For example, when bootstrapping an Angular application, Angular loads the bootstrap component and triggers the [ApplicationRef.tick()](api/core/ApplicationRef#tick) to call change detection and View Rendering. Just as in the [displaying data](guide/displaying-data) sample, the `AppComponent` is the bootstrap component. This component has the properties `title` and `myHero`, which the application renders in the HTML.
1. Component initialization. For example, when bootstrapping an Angular application, Angular loads the bootstrap component and triggers the [ApplicationRef.tick()](api/core/ApplicationRef#tick) to call change detection and View Rendering.
2. Event listener. The DOM event listener can update the data in an Angular component and also trigger change detection, as in the following example.
1. Event listener. The DOM event listener can update the data in an Angular component and also trigger change detection, as in the following example.
<code-example path="user-input/src/app/click-me.component.ts" region="click-me-component" header="src/app/click-me.component.ts"></code-example>
3. HTTP Data Request. You can also get data from a server through an HTTP request. For example:
1. HTTP Data Request. You can also get data from a server through an HTTP request. For example:
```typescript
@Component({

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 56 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 257 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -458,8 +458,8 @@
"name": "Sajeetharan Sinnathurai",
"picture": "sajee.jpg",
"twitter": "kokkisajee",
"website": "https://sajeetharan.herokuapp.com/",
"bio": "Sajeetharan is a Developer, Top contributor on stackoverflow for #Angular, ng-SriLanka organizer. He makes use of his extensive knowledge over the past years to contribute to community to make the world a better place.",
"website": "https://sajeetharan.com/",
"bio": "Sajeetharan is a Cloud Architect, Top contributor on stackoverflow for #Angular, ng-SriLanka organizer. He makes use of his extensive knowledge over the past years to contribute to community to make the world a better place.",
"groups": ["GDE"]
},
"lacolaco": {
@ -826,5 +826,30 @@
"website": "https://thekiba.io",
"bio": "Andrew is a software engineer using Angular and .NET. He spends most of his spare time staying up-to-date, helping other people, and experimenting with web tech.",
"groups": ["GDE"]
},
"fmalcher": {
"name": "Ferdinand Malcher",
"picture": "fmalcher.jpg",
"twitter": "fmalcher01",
"website": "https://angular.schule",
"bio": "Ferdinand is a developer, trainer, and international speaker from Leipzig, Germany. He is co-author of the German Angular book and loves to share knowledge that's why he writes books and blog posts, speaks at meetups and conferences, does Angular training and works as a consultant in his company \"Angular.Schule\".",
"groups": ["GDE"]
},
"johanneshoppe": {
"name": "Johannes Hoppe",
"picture": "johanneshoppe.jpg",
"twitter": "johanneshoppe",
"website": "https://angular.schule",
"bio": "Johannes works as a software architect and consultant for Angular. He is co-author of the German Angular book and a passionate speaker. With his company \"Angular.Schule\" he offers public Angular training and consulting. Johannes is head of the Angular Meetup in Heidelberg, Germany, and is engaged in a couple of open source projects.",
"groups": ["GDE"]
},
"jessicajaniuk": {
"name": "Jessica Janiuk",
"picture": "jessicajaniuk.jpg",
"twitter": "thepunderwoman",
"website": "https://github.com/jessicajaniuk",
"bio": "Jessica is a software engineer at Google. In her free time she is a historical fencer, astromech droid builder, photographer, pun purveyor, occasional cosplayer, and full time cat mom.",
"groups": ["Angular"],
"lead": "jelbourn"
}
}

View File

@ -46,7 +46,7 @@ Most Angular code can be written with just the latest JavaScript, using [types](
<h3>You can sit with us!</h3>
We want to hear from you. [Report problems or submit suggestions for future docs.](https://github.com/angular/angular/issues/new/choose "Angular GitHub repository new issue form")
We want to hear from you. [Report problems or submit suggestions for future docs](https://github.com/angular/angular/issues/new/choose "Angular GitHub repository new issue form").
Contribute to Angular docs by creating
[pull requests](https://github.com/angular/angular/pulls "Angular Github pull requests")

View File

@ -101,21 +101,26 @@
"title": "Components",
"tooltip": "Building dynamic views with data binding",
"children": [
{
"url": "guide/component-overview",
"title": "Overview",
"tooltip": "Overview of how to create Angular components."
},
{
"url": "guide/user-input",
"title": "User Input",
"tooltip": "User input triggers DOM events. Angular listens to those events with event bindings that funnel updated values back into your app's components and models."
},
{
"url": "guide/pipes",
"title": "Pipes",
"tooltip": "Pipes transform displayed values within a template."
},
{
"url": "guide/lifecycle-hooks",
"title": "Component Lifecycle",
"tooltip": "Angular calls lifecycle hook methods on directives and components as it creates, changes, and destroys them."
},
{
"url": "guide/view-encapsulation",
"title": "View Encapsulation",
"tooltip": "Describes how component CSS styles are encapsulated into a component's view."
},
{
"url": "guide/component-interaction",
"title": "Component Interaction",
@ -126,6 +131,11 @@
"title": "Component Styles",
"tooltip": "Add CSS styles that are specific to a component."
},
{
"url": "guide/inputs-outputs",
"title": "Inputs and Outputs",
"tooltip": "Introductory guide to sharing data between parent and child directives or components."
},
{
"url": "guide/dynamic-component-loader",
"title": "Dynamic Components",
@ -157,6 +167,11 @@
"title": "Template statements",
"tooltip": "Introductory guide to statements in templates that respond to events that components, directives, or elements raise."
},
{
"url": "guide/pipes",
"title": "Pipes",
"tooltip": "Pipes transform displayed values within a template."
},
{
"url": "guide/binding-syntax",
"title": "Binding syntax",
@ -187,11 +202,6 @@
"title": "Template reference variables",
"tooltip": "Introductory guide to referring to DOM elements within a template."
},
{
"url": "guide/inputs-outputs",
"title": "Inputs and Outputs",
"tooltip": "Introductory guide to sharing data between parent and child directives or components."
},
{
"url": "guide/template-expression-operators",
"title": "Template expression operators",
@ -412,6 +422,11 @@
"title": "Keeping Up-to-Date",
"tooltip": "Information about updating Angular applications and libraries to the latest version."
},
{
"url": "guide/property-binding-best-practices",
"title": "Property Binding Best Practices",
"tooltip": "Use property binding efficiently."
},
{
"title": "Testing",
"tooltip": "Testing your Angular apps.",
@ -604,11 +619,6 @@
"title": "Building a Template-driven Form",
"tooltip": "Create a template-driven form using directives and Angular template syntax."
},
{
"url": "guide/displaying-data",
"title": "Data binding",
"tooltip": "Property binding helps show app data in the UI."
},
{
"url": "guide/web-worker",
"title": "Web Workers",
@ -1004,6 +1014,11 @@
"title": "Stack Overflow",
"tooltip": "Stack Overflow: where the community answers your technical Angular questions."
},
{
"url": "https://discord.gg/angular",
"title": "Join Discord",
"tooltip": "Join the discussions at Angular Community Discord server."
},
{
"url": "https://gitter.im/angular/angular",
"title": "Gitter",

View File

@ -180,7 +180,7 @@ give it a `catchError()` operator.
</code-example>
The `catchError()` operator intercepts an **`Observable` that failed**.
It passes the error an error handler that can do what it wants with the error.
The operator then passes the error to the error handling function.
The following `handleError()` method reports the error and then returns an
innocuous result so that the application keeps working.

View File

@ -31,6 +31,7 @@
{"type": 301, "source": "/guide/quickstart", "destination": "/start"},
{"type": 301, "source": "/getting-started", "destination": "/start"},
{"type": 301, "source": "/getting-started/:rest*", "destination": "/start/:rest*"},
{"type": 301, "source": "/guide/displaying-data", "destination": "/start#template-syntax"},
// Renaming of Getting Started topics
{"type": 301, "source": "/start/data", "destination": "/start/start-data"},
@ -128,7 +129,8 @@
// The below paths are referenced in users projects generated by the CLI
{"type": 301, "source": "/config/tsconfig", "destination": "/guide/typescript-configuration"},
{"type": 301, "source": "/config/solution-tsconfig", "destination": "https://devblogs.microsoft.com/typescript/announcing-typescript-3-9/#solution-style-tsconfig"},
{"type": 301, "source": "/config/app-package-json", "destination": "/guide/strict-mode#non-local-side-effects-in-applications"}
{"type": 301, "source": "/config/app-package-json", "destination": "/guide/strict-mode#non-local-side-effects-in-applications"},
{"type": 301, "source": "/strict", "destination": "/guide/strict-mode"}
],
"rewrites": [
{

View File

@ -102,6 +102,9 @@
"!/guide/cli-quickstart",
"!/guide/cli-quickstart.html",
"!/guide/cli-quickstart/",
"!/guide/displaying-data",
"!/guide/displaying-data.html",
"!/guide/displaying-data/",
"!/guide/learning-angular",
"!/guide/learning-angular.html",
"!/guide/learning-angular/",
@ -148,6 +151,7 @@
"!/styleguide/**",
"!/testing",
"!/testing/**",
"!/config/**"
"!/config/**",
"!/strict"
]
}

View File

@ -23,7 +23,7 @@
"build-local-with-viewengine": "yarn ~~build",
"prebuild-local-with-viewengine-ci": "node scripts/switch-to-viewengine && yarn setup-local-ci",
"build-local-with-viewengine-ci": "yarn ~~build --progress=false",
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js ab97bc382",
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js cba6d86ca",
"lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint",
"test": "yarn check-env && ng test",
"pree2e": "yarn check-env && yarn update-webdriver",
@ -64,13 +64,14 @@
"tools-lint": "tslint --config \"tools/tslint.json\" --project \"tools/firebase-test-utils\"",
"tools-test": "./scripts/deploy-to-firebase.test.sh && yarn docs-test && yarn boilerplate:test && jasmine tools/ng-packages-installer/index.spec.js && yarn firebase-utils-test",
"preserve-and-sync": "yarn docs",
"serve-and-sync": "run-p \"start\" \"docs-watch --watch-only\"",
"serve-and-sync": "run-p \"docs-watch --watch-only\" \"start {@}\" --",
"boilerplate:add": "node ./tools/examples/example-boilerplate add",
"boilerplate:add:viewengine": "yarn boilerplate:add --viewengine",
"boilerplate:remove": "node ./tools/examples/example-boilerplate remove",
"boilerplate:test": "node tools/examples/test.js",
"generate-stackblitz": "node ./tools/stackblitz-builder/generateStackblitz",
"generate-zips": "node ./tools/example-zipper/generateZips",
"create-example": "node ./tools/examples/create-example.js",
"build-404-page": "node scripts/build-404-page",
"update-webdriver": "node ../scripts/webdriver-manager-update.js",
"~~audit-web-app": "node scripts/audit-web-app",
@ -153,7 +154,7 @@
"lunr": "^2.1.0",
"npm-run-all": "^4.1.5",
"protractor": "~5.4.4",
"puppeteer": "3.3.0",
"puppeteer": "5.1.0",
"rehype": "^6.0.0",
"rehype-slug": "^2.0.0",
"remark": "^9.0.0",
@ -172,6 +173,6 @@
"unist-util-visit-parents": "^1.1.1",
"watchr": "^3.0.1",
"xregexp": "^4.0.0",
"yargs": "^7.0.2"
"yargs": "^16.1.0"
}
}

View File

@ -782,7 +782,7 @@ describe('AppComponent', () => {
it('should grab focus when the / key is pressed', () => {
const searchBox: SearchBoxComponent = fixture.debugElement.query(By.directive(SearchBoxComponent)).componentInstance;
spyOn(searchBox, 'focus');
window.document.dispatchEvent(new KeyboardEvent('keyup', { 'key': '/' }));
window.document.dispatchEvent(new KeyboardEvent('keyup', { key: '/' }));
fixture.detectChanges();
expect(searchBox.focus).toHaveBeenCalled();
});
@ -791,7 +791,7 @@ describe('AppComponent', () => {
const searchBox: SearchBoxComponent = fixture.debugElement.query(By.directive(SearchBoxComponent)).componentInstance;
spyOn(searchBox, 'focus');
component.showSearchResults = true;
window.document.dispatchEvent(new KeyboardEvent('keyup', { 'key': 'Escape' }));
window.document.dispatchEvent(new KeyboardEvent('keyup', { key: 'Escape' }));
fixture.detectChanges();
expect(searchBox.focus).toHaveBeenCalled();
});
@ -968,23 +968,23 @@ describe('AppComponent', () => {
// Initially, `isTransitoning` is true.
expect(component.isTransitioning).toBe(true);
expect(toolbar.classes['transitioning']).toBe(true);
expect(toolbar.classes.transitioning).toBe(true);
triggerDocViewerEvent('docRendered');
fixture.detectChanges();
expect(component.isTransitioning).toBe(false);
expect(toolbar.classes['transitioning']).toBeFalsy();
expect(toolbar.classes.transitioning).toBeFalsy();
// While a document is being rendered, `isTransitoning` is set to true.
triggerDocViewerEvent('docReady');
fixture.detectChanges();
expect(component.isTransitioning).toBe(true);
expect(toolbar.classes['transitioning']).toBe(true);
expect(toolbar.classes.transitioning).toBe(true);
triggerDocViewerEvent('docRendered');
fixture.detectChanges();
expect(component.isTransitioning).toBe(false);
expect(toolbar.classes['transitioning']).toBeFalsy();
expect(toolbar.classes.transitioning).toBeFalsy();
});
it('should update the sidenav state as soon as a new document is inserted (but not before)', () => {
@ -1031,15 +1031,15 @@ describe('AppComponent', () => {
navigateTo('guide/pipes');
expect(component.pageId).toEqual('guide-pipes');
expect(container.properties['id']).toEqual('guide-pipes');
expect(container.properties.id).toEqual('guide-pipes');
navigateTo('news');
expect(component.pageId).toEqual('news');
expect(container.properties['id']).toEqual('news');
expect(container.properties.id).toEqual('news');
navigateTo('');
expect(component.pageId).toEqual('home');
expect(container.properties['id']).toEqual('home');
expect(container.properties.id).toEqual('home');
});
it('should not be affected by changes to the query', () => {
@ -1050,7 +1050,7 @@ describe('AppComponent', () => {
navigateTo('guide/other?search=http');
expect(component.pageId).toEqual('guide-other');
expect(container.properties['id']).toEqual('guide-other');
expect(container.properties.id).toEqual('guide-other');
});
});
@ -1125,7 +1125,7 @@ describe('AppComponent', () => {
function checkHostClass(type: string, value: string) {
const host = fixture.debugElement;
const classes: string = host.properties['className'];
const classes: string = host.properties.className;
const classArray = classes.split(' ').filter(c => c.indexOf(`${type}-`) === 0);
expect(classArray.length).toBeLessThanOrEqual(1, `"${classes}" should have only one class matching ${type}-*`);
expect(classArray).toEqual([`${type}-${value}`], `"${classes}" should contain ${type}-${value}`);
@ -1311,42 +1311,42 @@ class TestHttpClient {
// tslint:disable:quotemark
navJson = {
"TopBar": [
TopBar: [
{
"url": "features",
"title": "Features"
url: 'features',
title: 'Features',
},
{
"url": "no-title",
"title": "No Title"
url: 'no-title',
title: 'No Title',
},
],
"SideNav": [
SideNav: [
{
"title": "Core",
"tooltip": "Learn the core capabilities of Angular",
"children": [
title: 'Core',
tooltip: 'Learn the core capabilities of Angular',
children: [
{
"url": "guide/pipes",
"title": "Pipes",
"tooltip": "Pipes transform displayed values within a template."
url: 'guide/pipes',
title: 'Pipes',
tooltip: 'Pipes transform displayed values within a template.',
},
{
"url": "guide/bags",
"title": "Bags",
"tooltip": "Pack your bags for a code adventure."
}
]
url: 'guide/bags',
title: 'Bags',
tooltip: 'Pack your bags for a code adventure.',
},
],
},
{
"url": "api",
"title": "API",
"tooltip": "Details of the Angular classes and values."
}
url: 'api',
title: 'API',
tooltip: 'Details of the Angular classes and values.',
},
],
"docVersions": TestHttpClient.docVersions,
docVersions: TestHttpClient.docVersions,
"__versionInfo": TestHttpClient.versionInfo,
__versionInfo: TestHttpClient.versionInfo,
};
get(url: string) {

View File

@ -147,7 +147,7 @@ export class AppComponent implements OnInit {
// Compute the version picker list from the current version and the versions in the navigation map
combineLatest([
this.navigationService.versionInfo,
this.navigationService.navigationViews.pipe(map(views => views['docVersions'])),
this.navigationService.navigationViews.pipe(map(views => views.docVersions)),
]).subscribe(([versionInfo, versions]) => {
// TODO(pbd): consider whether we can lookup the stable and next versions from the internet
const computedVersions: NavigationNode[] = [
@ -167,10 +167,10 @@ export class AppComponent implements OnInit {
});
this.navigationService.navigationViews.subscribe(views => {
this.footerNodes = views['Footer'] || [];
this.sideNavNodes = views['SideNav'] || [];
this.topMenuNodes = views['TopBar'] || [];
this.topMenuNarrowNodes = views['TopBarNarrow'] || this.topMenuNodes;
this.footerNodes = views.Footer || [];
this.sideNavNodes = views.SideNav || [];
this.topMenuNodes = views.TopBar || [];
this.topMenuNarrowNodes = views.TopBarNarrow || this.topMenuNodes;
});
this.navigationService.versionInfo.subscribe(vi => this.versionInfo = vi);

View File

@ -223,77 +223,77 @@ class TestApiService {
// tslint:disable:quotemark
const apiSections: ApiSection[] = [
{
"name": "common",
"title": "common",
"path": "api/common",
"deprecated": false,
"items": [
name: 'common',
title: 'common',
path: 'api/common',
deprecated: false,
items: [
{
"name": "class_1",
"title": "Class 1",
"path": "api/common/class_1",
"docType": "class",
"stability": "experimental",
"securityRisk": false,
name: 'class_1',
title: 'Class 1',
path: 'api/common/class_1',
docType: 'class',
stability: 'experimental',
securityRisk: false,
},
{
"name": "class_2",
"title": "Class 2",
"path": "api/common/class_2",
"docType": "class",
"stability": "stable",
"securityRisk": false,
name: 'class_2',
title: 'Class 2',
path: 'api/common/class_2',
docType: 'class',
stability: 'stable',
securityRisk: false,
},
{
"name": "directive_1",
"title": "Directive 1",
"path": "api/common/directive_1",
"docType": "directive",
"stability": "stable",
"securityRisk": true,
name: 'directive_1',
title: 'Directive 1',
path: 'api/common/directive_1',
docType: 'directive',
stability: 'stable',
securityRisk: true,
},
{
"name": "pipe_1",
"title": "Pipe 1",
"path": "api/common/pipe_1",
"docType": "pipe",
"stability": "stable",
"securityRisk": true,
name: 'pipe_1',
title: 'Pipe 1',
path: 'api/common/pipe_1',
docType: 'pipe',
stability: 'stable',
securityRisk: true,
},
]
],
},
{
"name": "core",
"title": "core",
"path": "api/core",
"deprecated": false,
"items": [
name: 'core',
title: 'core',
path: 'api/core',
deprecated: false,
items: [
{
"name": "class_3",
"title": "Class 3",
"path": "api/core/class_3",
"docType": "class",
"stability": "experimental",
"securityRisk": false,
name: 'class_3',
title: 'Class 3',
path: 'api/core/class_3',
docType: 'class',
stability: 'experimental',
securityRisk: false,
},
{
"name": "function_1",
"title": "Function 1",
"path": "api/core/function 1",
"docType": "function",
"stability": "deprecated",
"securityRisk": true,
name: 'function_1',
title: 'Function 1',
path: 'api/core/function 1',
docType: 'function',
stability: 'deprecated',
securityRisk: true,
},
{
"name": "const_1",
"title": "Const 1",
"path": "api/core/const_1",
"docType": "const",
"stability": "stable",
"securityRisk": false,
}
]
}
name: 'const_1',
title: 'Const 1',
path: 'api/core/const_1',
docType: 'const',
stability: 'stable',
securityRisk: false,
},
],
},
];
function getApiSections() { return apiSections; }

View File

@ -67,7 +67,7 @@ export class ApiService implements OnDestroy {
* API sections is an array of Angular top modules and metadata about their API documents (items).
* Updates `sections` observable
*
* @param {string} [src] - Name of the api list JSON file
* @param [src] - Name of the api list JSON file
*/
fetchSections(src?: string) {
// TODO: get URL by configuration?

View File

@ -20,13 +20,13 @@ export class PrettyPrinter {
}
private getPrettyPrintOne(): Promise<PrettyPrintOne> {
const ppo = (window as any)['prettyPrintOne'];
const ppo = (window as any).prettyPrintOne;
return ppo ? Promise.resolve(ppo) :
// `prettyPrintOne` is not on `window`, which means `prettify.js` has not been loaded yet.
// Import it; ad a side-effect it will add `prettyPrintOne` on `window`.
import('assets/js/prettify.js' as any)
.then(
() => (window as any)['prettyPrintOne'],
() => (window as any).prettyPrintOne,
err => {
const msg = `Cannot get prettify.js from server: ${err.message}`;
this.logger.error(new Error(msg));
@ -37,9 +37,9 @@ export class PrettyPrinter {
/**
* Format code snippet as HTML
* @param {string} code - the code snippet to format; should already be HTML encoded
* @param {string} [language] - The language of the code to render (could be javascript, html, typescript, etc)
* @param {string|number} [linenums] - Whether to display line numbers:
* @param code - the code snippet to format; should already be HTML encoded
* @param [language] - The language of the code to render (could be javascript, html, typescript, etc)
* @param [linenums] - Whether to display line numbers:
* - false: don't display
* - true: do display
* - number: do display but start at the given number

View File

@ -63,7 +63,7 @@ describe('ContributorListComponent', () => {
it('should set the query to the "GDE" group when user selects "GDE"', () => {
component = getComponent();
component.selectGroup('GDE');
expect(locationService.searchResult['group']).toBe('GDE');
expect(locationService.searchResult.group).toBe('GDE');
});
it('should set the query to the first group when user selects unknown name', () => {
@ -71,7 +71,7 @@ describe('ContributorListComponent', () => {
component.selectGroup('GDE'); // a legit group that isn't the first
component.selectGroup('foo'); // not a legit group name
expect(locationService.searchResult['group']).toBe('Angular');
expect(locationService.searchResult.group).toBe('Angular');
});
//// Test Helpers ////

View File

@ -29,7 +29,7 @@ export class ContributorListComponent implements OnInit {
private locationService: LocationService) { }
ngOnInit() {
const groupName = this.locationService.search()['group'] || '';
const groupName = this.locationService.search().group || '';
// no need to unsubscribe because `contributors` completes
this.contributorService.contributors
.subscribe(grps => {

View File

@ -63,7 +63,7 @@ describe('ResourceListComponent', () => {
it('should set the query to the "education" category when user selects "education"', () => {
component = getComponent();
component.selectCategory('education');
expect(locationService.searchResult['category']).toBe('education');
expect(locationService.searchResult.category).toBe('education');
});
it('should set the query to the first category when user selects unknown name', () => {
@ -71,7 +71,7 @@ describe('ResourceListComponent', () => {
component.selectCategory('education'); // a legit group that isn't the first
component.selectCategory('foo'); // not a legit group name
expect(locationService.searchResult['category']).toBe('development');
expect(locationService.searchResult.category).toBe('development');
});
//// Test Helpers ////

View File

@ -20,7 +20,7 @@ export class ResourceListComponent implements OnInit {
}
ngOnInit() {
const category = this.locationService.search()['category'] || '';
const category = this.locationService.search().category || '';
// Not using async pipe because cats appear twice in template
// No need to unsubscribe because categories observable completes.
this.resourceService.categories.subscribe(cats => {

View File

@ -86,62 +86,61 @@ describe('ResourceService', () => {
});
function getTestResources() {
// tslint:disable:quotemark
return {
"Cat 3": {
"order": 3,
"subCategories": {
"Cat3 SubCat1": {
"order": 2,
"resources": {
"Cat3 SubCat1 Res1": {
"desc": "Meetup in Barcelona, Spain. ",
"title": "Angular Beers",
"url": "http://www.meetup.com/AngularJS-Beers/"
'Cat 3': {
order: 3,
subCategories: {
'Cat3 SubCat1': {
order: 2,
resources: {
'Cat3 SubCat1 Res1': {
desc: 'Meetup in Barcelona, Spain. ',
title: 'Angular Beers',
url: 'http://www.meetup.com/AngularJS-Beers/',
},
"Cat3 SubCat1 Res2": {
"desc": "Angular Camps in Barcelona, Spain.",
"title": "Angular Camp",
"url": "http://angularcamp.org/"
}
}
'Cat3 SubCat1 Res2': {
desc: 'Angular Camps in Barcelona, Spain.',
title: 'Angular Camp',
url: 'http://angularcamp.org/',
},
},
},
"Cat3 SubCat2": {
"order": 1,
"resources": {
"Cat3 SubCat2 Res1": {
"desc": "A community index of components and libraries",
"title": "Catalog of Angular Components & Libraries",
"url": "https://a/b/c"
}
}
},
}
},
"Cat 1": {
"order": 1,
"subCategories": {
"Cat1 SubCat1": {
"order": 1,
"resources": {
"S S S": {
"desc": "SSS",
"title": "Sssss",
"url": "http://s/s/s"
'Cat3 SubCat2': {
order: 1,
resources: {
'Cat3 SubCat2 Res1': {
desc: 'A community index of components and libraries',
title: 'Catalog of Angular Components & Libraries',
url: 'https://a/b/c',
},
"A A A": {
"desc": "AAA",
"title": "Aaaa",
"url": "http://a/a/a"
},
"Z Z Z": {
"desc": "ZZZ",
"title": "Zzzzz",
"url": "http://z/z/z"
}
}
},
},
},
}
},
'Cat 1': {
order: 1,
subCategories: {
'Cat1 SubCat1': {
order: 1,
resources: {
'S S S': {
desc: 'SSS',
title: 'Sssss',
url: 'http://s/s/s',
},
'A A A': {
desc: 'AAA',
title: 'Aaaa',
url: 'http://a/a/a',
},
'Z Z Z': {
desc: 'ZZZ',
title: 'Zzzzz',
url: 'http://z/z/z',
},
},
},
},
},
};
}

View File

@ -86,7 +86,7 @@ describe('NavigationService', () => {
];
beforeEach(() => {
navService.navigationViews.subscribe(views => view = views['sideNav']);
navService.navigationViews.subscribe(views => view = views.sideNav);
httpMock.expectOne({}).flush({sideNav});
});
@ -254,7 +254,7 @@ describe('NavigationService', () => {
{...v, ...{ tooltip: v.title + '.'}})
);
navService.navigationViews.subscribe(views => actualDocVersions = views['docVersions']);
navService.navigationViews.subscribe(views => actualDocVersions = views.docVersions);
});
it('should extract the docVersions', () => {

View File

@ -41,7 +41,7 @@ export class SearchBoxComponent implements AfterViewInit {
* When we first show this search box we trigger a search if there is a search query in the URL
*/
ngAfterViewInit() {
const query = this.locationService.search()['search'];
const query = this.locationService.search().search;
if (query) {
this.query = this.decodeQuery(query);
this.doSearch();

View File

@ -26,7 +26,7 @@ function createIndex(loadIndexFn: IndexLoader): lunr.Index {
// The lunr typings are missing QueryLexer so we have to add them here manually.
const queryLexer = (lunr as any as { QueryLexer: { termSeparator: RegExp } }).QueryLexer;
queryLexer.termSeparator = lunr.tokenizer.separator = /\s+/;
return lunr(/** @this */function() {
return lunr(function() {
this.ref('path');
this.field('topics', { boost: 15 });
this.field('titleWords', { boost: 10 });
@ -44,7 +44,7 @@ function handleMessage(message: { data: WebWorkerMessage }): void {
const payload = message.data.payload;
switch (type) {
case 'load-index':
makeRequest(SEARCH_TERMS_URL, function(searchInfo: PageInfo[]) {
makeRequest(SEARCH_TERMS_URL, (searchInfo: PageInfo[]) => {
index = createIndex(loadIndex(searchInfo));
postMessage({ type, id, payload: true });
});
@ -94,7 +94,7 @@ function queryIndex(query: string): PageInfo[] {
results = index.search(query + ' ' + titleQuery);
}
// Map the hits into info about each page to be returned as results
return results.map(function(hit) { return pages[hit.ref]; });
return results.map(hit => pages[hit.ref]);
}
} catch (e) {
// If the search query cannot be parsed the index throws an error

View File

@ -11,7 +11,7 @@ export class Deployment {
* The deployment mode set from the environment provided at build time;
* or overridden by the `mode` query parameter: e.g. `...?mode=archive`
*/
mode: string = this.location.search()['mode'] || environment.mode;
mode: string = this.location.search().mode || environment.mode;
constructor(private location: LocationService) {}
}

View File

@ -14,7 +14,7 @@ export class GaService {
private previousUrl: string;
constructor(@Inject(WindowToken) private window: Window) {
this.ga('create', environment['gaId'] , 'auto');
this.ga('create', environment.gaId , 'auto');
}
locationChanged(url: string) {
@ -34,7 +34,7 @@ export class GaService {
}
ga(...args: any[]) {
const gaFn = (this.window as any)['ga'];
const gaFn = (this.window as any).ga;
if (gaFn) {
gaFn(...args);
}

View File

@ -100,7 +100,7 @@ export class LocationService {
/**
* Handle user's anchor click
*
* @param anchor {HTMLAnchorElement} - the anchor element clicked
* @param anchor The anchor element clicked
* @param button Number of the mouse button held down. 0 means left or none
* @param ctrlKey True if control key held down
* @param metaKey True if command or window key held down

View File

@ -13,14 +13,13 @@ import { Logger } from 'app/shared/logger.service';
* 1. Checks for available ServiceWorker updates once instantiated.
* 2. Re-checks every 6 hours.
* 3. Whenever an update is available, it activates the update.
*
* @property
* `updateActivated` {Observable<string>} - Emit the version hash whenever an update is activated.
*/
@Injectable()
export class SwUpdatesService implements OnDestroy {
private checkInterval = 1000 * 60 * 60 * 6; // 6 hours
private onDestroy = new Subject<void>();
/** Emit the version hash whenever an update is activated. */
updateActivated: Observable<string>;
constructor(appRef: ApplicationRef, private logger: Logger, private swu: SwUpdate) {

View File

@ -38,7 +38,11 @@
margin: 0;
clear: left;
}
.actions {
display: flex;
color: $blue;
@include font-size(14);
}
.show-all {
display: initial;
}

View File

@ -105,9 +105,7 @@
li {
box-sizing: border-box;
@include font-size(12);
@include line-height(16);
padding: 3px 0 3px 12px;
padding: 7px 0 7px 12px;
position: relative;
transition: all 0.3s ease-in-out;
@ -129,6 +127,7 @@
color: lighten($darkgray, 10);
overflow: visible;
@include font-size(12);
@include line-height(16);
display: table-cell;
}
@ -168,11 +167,11 @@
}
&:first-child:before {
top: 13px;
top: 15px;
}
&:last-child:before {
bottom: calc(100% - 14px);
bottom: calc(100% - 15px);
}
&:not(.active):hover a:before {

View File

@ -177,6 +177,7 @@
/getting-started/forms /start/start-forms
/getting-started/deployment /start/start-deployment
/guide/cli-quickstart /start
/guide/displaying-data /start#template-syntax
/guide/learning-angular /start
/guide/learning-angular.html /start
/guide/metadata /guide/aot-compiler

Some files were not shown because too many files have changed in this diff Show More