Compare commits

...

160 Commits

Author SHA1 Message Date
Joey Perrott de4f913662 release: cut the v11.0.0-rc.2 release 2020-11-04 12:43:49 -08:00
Kristiyan Kostadinov 96ad439d48 test(compiler-cli): resolve test failure (#39568)
Narrows down an assertion in one of our tests so it's less prone to failure due to
extra commas.

PR Close #39568
2020-11-04 12:02:10 -08:00
Aristeidis Bampakos 6959620002 docs: fix typos in the "Attribute Binding" guide (#39562)
PR Close #39562
2020-11-04 11:42:45 -08:00
Andrew Kushnir 43b4940c9d fix(forms): remove validators while cleaning up a control (#39234)
Prior to this commit, the `cleanUpControl` function (responsible for cleaning up control instance)
was not taking validators into account. As a result, these validators remain registered on a detached
form control instance, thus causing memory leaks. This commit updates the `cleanUpControl` function
logic to also run validators cleanup.

As a part of this change, the logic to setup and cleanup validators was refactored and moved to
separate functions (with completely opposite behavior), so that they can be reused in the future.

This commit doesn't add the `cleanUpControl` calls to all possible places, it just fixes the cases
where this function is being called, but doesn't fully perform a cleanup. The `cleanUpControl`
function calls will be added to other parts of code (to avoid more memory leaks) in a followup PR.

PR Close #39234
2020-11-04 10:58:25 -08:00
santoshyadavdev e9889da457 docs: correct the formatting (#39534)
PR Close #39534
2020-11-04 10:54:04 -08:00
Joey Perrott 450830cf1a fix(dev-infra): run caretaker checks asyncronously (#39086)
Run each check in the caretaker check process asyncronously.

PR Close #39086
2020-11-03 16:33:00 -08:00
GeopJr 7ef72d192b docs: fix Android 10 codename (#39399)
Change Android 10's codename from "X" to "Q"
PR Close #39399
2020-11-03 16:10:57 -08:00
Joey Perrott 6817377590 feat(dev-infra): provide tooling to check what branches a pr targets (#39504)
Create a command in the `ng-dev` toolset that allows user's to check
what branches a PR will merge into based on its targeting.

PR Close #39504
2020-11-03 14:55:25 -08:00
George Kalpakas e8654f943c build(docs-infra): upgrade cli command docs sources to c8f3ce348 (#39546)
Updating [angular#11.0.x](https://github.com/angular/angular/tree/11.0.x) from
[cli-builds#11.0.x](https://github.com/angular/cli-builds/tree/11.0.x).

##
Relevant changes in
[commit range](https://github.com/angular/cli-builds/compare/d5c1851de...c8f3ce348):

**Modified**
- help/generate.json
- help/new.json

PR Close #39546
2020-11-03 14:54:55 -08:00
Kristiyan Kostadinov b0bbc1f232 fix(compiler-cli): generating invalid setClassMetadata call in ES5 for class with custom decorator (#39527)
When a class with a custom decorator is transpiled to ES5, it looks something like this:

```
var SomeClass = (function() {
  function SomeClass() {...};
  var SomeClass_1 = __decorate([Decorator()], SomeClass);
  SomeClass = SomeClass_1;
  return SomeClass;
})();
```

The problem is that if the class also has an Angular decorator that refers to the class itself
(e.g. `{provide: someToken, useClass: SomeClass}`), the generated `setClassMetadata` code will
be emitted after the IIFE, but will still refer to the intermediate `SomeClass_1` variable from
inside the IIFE. This happens, because we generate the `setClassMetadata` call directly from
the source AST which contains identifiers that TS will rename when it emits the ES5 code.

These changes resolve the issue by looking through the metadata AST and cloning any `Identifier`
that is referring to the class. Since TS doesn't have references to the clone, it won't rename
it when transpiling to ES5.

Fixes #39509.

PR Close #39527
2020-11-03 14:53:00 -08:00
Joey Perrott b6064c2782 fix(dev-infra): run fetches in the git client in quiet mode (#39503)
When fetch is run in normal mode, the `git-fetch-pack` plumbing command
outputs progress to stderr.  Since this is unnecessary progress
information for ng-dev usages, it should be suppressed instead.

PR Close #39503
2020-11-02 16:41:48 -08:00
Joey Perrott e34c87e114 ci: only check testing directories within packages/ for fw-testing (#39536)
The fw-testing group should only match on testing directories within the
framework packages, previously it was also matching in other areas of
the codebase.

PR Close #39536
2020-11-02 16:39:45 -08:00
Pete Bacon Darwin a0b6548a94 build(docs-infra): ensure that deployment works on CI (#39535)
The actual "main" part of the script that is executed was using
an uninitialized variable. This is fixed and a test is added to
check.

PR Close #39535
2020-11-02 12:24:36 -08:00
Eduard Bondarenko 40f38ce7df docs: update forwardRef example (#39519)
Replace the deprecated api ReflectiveInjector.resolveAndCreat with Injector.create

PR Close #39519
2020-11-02 11:40:18 -08:00
George Kalpakas d386fb3e86 build(docs-infra): upgrade firebase-tools to v8.14.1 (#39470)
This commit upgrades `firebase-tools` (used to deploy angular.io to
Firebase hosting) to the latest version. This gives us access to the
latest fixes/improvements and also new features, such as
[version cloning][1].

[1]:
https://firebase.google.com/docs/hosting/manage-hosting-resources#cli-commands-cloning

PR Close #39470
2020-11-02 07:57:54 -08:00
George Kalpakas f868dcb9e8 build(docs-infra): deploy angular.io to new Firebase sites (#39470)
Previously, the documentation for each major Angular version was hosted
on each own Firebase project. This required creating a new project for
each major release and increased the administrative/maintenance cost.

Now that Firebase supports hosting [multiple websites][1] as part of the
same project, we are switching to deploying all major versions to sites
created on `angular-io` project.

This is part of the work needed to prepare angular.io for our
[new versioning/branching process][2] (also tracked in #39366).

[1]: https://firebase.google.com/docs/hosting/multisites
[2]: https://docs.google.com/document/d/197kVillDwx-RZtSVOBtPb4BBIAw0E9RT3q3v6DZkykU

PR Close #39470
2020-11-02 07:57:54 -08:00
George Kalpakas ad4f0fd85c refactor(docs-infra): break up deploy-to-firebase.js script into functions (#39470)
This commit breaks up the code in `deploy-to-firebase.js` script, that
we use for deploying angular.io to production, to smaller functions
(instead of a monolithic block). This makes the script easier to
maintain and also makes testing individual operations easier.

The commit also updates the `deploy-to-firebase.spec.js` spec file to
take advantage of the standalone functions to speed up testing by
calling the corresponding function instead of having to spawn a new
process and run the `deploy-to-firebase.js` script with the `--dry-run`
flag.

NOTE: Before updating the tests, I verified that the updated
      `deploy-to-firebase.js` script passed the old tests.

PR Close #39470
2020-11-02 07:57:54 -08:00
George Kalpakas 8d0c1bdabf build(docs-infra): add support for RC deployments to deployment script (#39470)
This commit updates the angular.io deployment script
(`deploy-to-firebase.js`) to support deploying release-candidate
versions.

This is part of the work needed to prepare angular.io for our
[new versioning/branching process][1] (also tracked in #39366).

[1]: https://docs.google.com/document/d/197kVillDwx-RZtSVOBtPb4BBIAw0E9RT3q3v6DZkykU

PR Close #39470
2020-11-02 07:57:54 -08:00
George Kalpakas 47244dbd00 build(docs-infra): add new angular.io build configuration for release-candidates (#39470)
This commit adds a new build configuration/deployment mode (`rc`) for
deploying release-candidate versions to angular.io.

This is part of the work needed to prepare angular.io for our
[new versioning/branching process][1] (also tracked in #39366).

[1]: https://docs.google.com/document/d/197kVillDwx-RZtSVOBtPb4BBIAw0E9RT3q3v6DZkykU

PR Close #39470
2020-11-02 07:57:54 -08:00
George Kalpakas e5caf1189a refactor(docs-infra): use Sass mixin to simplify the creation of deployment mode themes (#39470)
Different deployment modes (such as `archive` and `next`) are identified
by the different colors used in prominent elements of the page, such as
the topbar and the footer.

Previously, the necessary styles for creating such a deployment mode
"theme" were duplicated for each mode.

This commit simplifies the creation/modification of a deployment mode
theme by introducing a Sass mixin that generates the necessary styles
(when provided with necessary theme colors).

PR Close #39470
2020-11-02 07:57:54 -08:00
George Kalpakas 37128ca1f7 test(docs-infra): ensure deploy-to-firebase tests pass locally (#39470)
Previously, the `deploy-to-firebase.js` script and the accompanying
`deploy-to-firebase.spec.js` spec file were using the `origin` remote
alias in certain commands. This works fine on CI, where `origin` points
to the `angular/angular` GitHub repo, but might not work locally.

This commit ensures that the correct remote is used by explicitly
specifying it by the URL, thus ensuring that the tests will behave
identically on CI and locally.

PR Close #39470
2020-11-02 07:57:53 -08:00
George Kalpakas ce14f37a58 build(docs-infra): switch deploy-to-firebase.sh script to JS (#39470)
This commit switches the `deploy-to-firebase.sh` script, that we use for
deploying angular.io to production, from Bash to JavaScript. This makes
the script easier to maintain.

For the same reasons, it also switches the `deploy-to-firebase.test.sh`
script, that we use for testing the `deploy-to-firebase` script, from
Bash to JavaScript (using jasmine as the test runner).

Finally, this commit also updates ShellJS to the latest version to get
better error messages (including the actual error) when `exec()` fails.

NOTE: Before switching the test script to JS, I verified that the new
      `deploy-to-firebase.js` script passed the tests with the old
      `deploy-to-firebase.test.sh` script.

PR Close #39470
2020-11-02 07:57:53 -08:00
JoostK 5c13c67d66 perf(core): do not recurse into modules that have already been registered (#39514)
When registering an NgModule based on its id, all transitively imported
NgModules are also registered. This commit introduces a visited set to
avoid traversing into NgModules that are reachable from multiple import
paths multiple times.

Fixes #39487

PR Close #39514
2020-11-02 07:51:19 -08:00
JoostK 83565229fa test(compiler-cli): remove spurious console.error call from a test (#39321)
Reporting the source file text to the console was left as a debugging
artifact.

PR Close #39321
2020-11-02 07:50:41 -08:00
JoostK 1ac05001a1 perf(compiler-cli): only generate template context declaration when used (#39321)
The variable declaration for a template context is only needed when it
is referenced from somewhere, so the TCB operation to generate the
declaration is marked as optional.

PR Close #39321
2020-11-02 07:50:41 -08:00
JoostK 67ea7b6098 fix(compiler-cli): report missing pipes when fullTemplateTypeCheck is disabled (#39320)
Even if `fullTemplateTypeCheck` is disabled should missing pipes still
be reported, as was the case in View Engine.

Fixes #38195

PR Close #39320
2020-10-30 18:01:52 -07:00
Andrew Scott b2f3952946 fix(router): Ensure all outlets are used when commands have a prefix (#39456)
When there is a primary outlet present in the outlets map and the object is also prefixed
with some other commands, the current logic only uses the primary outlet and ignores
the others. This change ensures that all outlets are respected at the
segment level when prefixed with other commands.

PR Close #39456
2020-10-30 16:23:05 -07:00
Andrew Scott 3abf95dca9 refactor(router): Small refactor of createUrlTree and extra tests (#39456)
This commit has a small refactor of some methods in create_url_tree.ts
and adds some test cases, including two that will fail at the moment but
should pass. A follow-up commit will make use of the refactorings to fix
the test with minimal changes.

PR Close #39456
2020-10-30 16:23:04 -07:00
Alan Agius eb625b993e docs: update CLI workspace config documentation (#39427)
- Improves JSON formatting
- Add reference to font optimization
- Removes `="true"` from boolean command line args.
These are redundant and it can be confusing to why
boolean values need to be provided via a CLI.

PR Close #39427
2020-10-30 12:39:30 -07:00
Kristiyan Kostadinov a8e0db73ba fix(compiler): preserve this.$event and this.$any accesses in expressions (#39323)
Currently expressions `$event.foo()` and `this.$event.foo()`, as well as `$any(foo)` and
`this.$any(foo)`, are treated as the same expression by the compiler, because `this` is considered
the same implicit receiver as when the receiver is omitted. This introduces the following issues:

1. Any time something called `$any` is used, it'll be stripped away, leaving only the first parameter.
2. If something called `$event` is used anywhere in a template, it'll be preserved as `$event`,
rather than being rewritten to `ctx.$event`, causing the value to undefined at runtime. This
applies to listener, property and text bindings.

These changes resolve the first issue and part of the second one by preserving anything that
is accessed through `this`, even if it's one of the "special" ones like `$any` or `$event`.
Furthermore, these changes only expose the `$event` global variable inside event listeners,
whereas previously it was available everywhere.

Fixes #30278.

PR Close #39323
2020-10-30 10:49:15 -07:00
Andrew Kushnir feda78e1c8 fix(common): change the week-numbering year format from r -> Y (#39495)
This commit updates the week-numbering year format from `r` -> `Y` based on the description in
http://www.unicode.org/reports/tr35/tr35-dates.html#dfst-year.

Note: this is not a breaking change, since the week-numbering year format was introduced in
v11.0.0-next.3 (https://github.com/angular/angular/commit/984ed39195d8291f0da0c2747a45761144e6daa2)
and the major version that contains that change was not released yet.

PR Close #39495
2020-10-30 10:24:44 -07:00
Andrew Kushnir 3091534af2 docs: tView.preOrderHooks and tView.preOrderCheckHooks docs update (#39497)
This commit updates the docs for the `tView.preOrderHooks` and `tView.preOrderCheckHooks` TView
fields. Current docs are not up-to-date as it was pointed out in #39439.

Closes #39439.

PR Close #39497
2020-10-29 16:25:40 -07:00
Kristiyan Kostadinov 669c4f7ced refactor(compiler): clean up i18n attribute generation logic (#39498)
This is follow-up from [an earlier discussion](https://github.com/angular/angular/pull/39408#discussion_r511908358).
After some testing, it looks like the type of `Element.attributes` was correct in specifying that it
only has `TextAttribute` instances. This means that the extra checks that filter out `BoundAttribute`
instances from the array isn't necessary. There is another loop a bit further down that actually
extracts the bound i18n attributes.

PR Close #39498
2020-10-29 16:07:50 -07:00
JiaLiPassion 3b6497b981 fix(core): markDirty() should only mark flags when really scheduling tick. (#39316)
Close #39296

Fix an issue that `markDirty()` will not trigger change detection.

The case is for example we have the following component.

```
export class AppComponent implements OnInit {
  constructor(private router: Router) {}

  ngOnInit() {
    this.router.events
      .pipe(filter((e) => e instanceof NavigationEnd))
      .subscribe(() => ɵmarkDirty(this));
  }
}

export class CounterComponent implements OnInit, OnDestroy {
  ngOnInit() {
    this.countSubject.pipe(takeUntil(this.destroy)).subscribe((count) => {
      this.count = count;
      ɵmarkDirty(this);
    });
  }
```

Then the app navigate from `AppComponent` to `CounterComponent`,
so there are 2 `markDirty()` call at in a row.

The `1st` call is from `AppComponent` when router changed, the
`2nd` call is from `CounterComponent.ngOnInit()`.

And the `markDirty()->scheduleTick()` code look like this

```
function scheduleTick(rootContext, flags) {
    const nothingScheduled = rootContext.flags === 0 /* Empty */;
    rootContext.flags |= flags;
    if (nothingScheduled && rootContext.clean == _CLEAN_PROMISE) {
      rootContext.schedule(() => {
	...
        if (rootContext.flags & RootContextFlags.DetectChanges)
          rootContext.flags &= ~RootContextFlags.DetectChanges;
          tickContext();

        rootContext.clean = _CLEAN_PROMISE;
        ...
      });
```

So in this case, the `1st` markDirty() will
1. set rootContext.flags = 1
2. before `tickContext()`, reset rootContext.flags = 0
3. inside `tickContext()`, it will call `CounterComponent.ngOnint()`,
   so the `2nd` markDirty() is called.
4. and the `2nd` scheduleTick is called, `nothingScheduled` is true,
   but rootContext.clean is not `_CLEAN_PROMISE` yet, since the `1st` markDirty tick
   is still running.
5. So nowhere will reset the `rootContext.flags`.
6. then in the future, any other `markDirty()` call will not trigger the tick, since
   `nothingScheduled` is always false.

So `nothingScheduled` means no tick is scheduled, `rootContext.clean === _CLEAN_PROMISE`
means no tick is running.
So we should set the flags to `rootContext` only when `no tick is scheudled or running`.

PR Close #39316
2020-10-29 16:07:11 -07:00
JiaLiPassion 0e60dc5597 release: cut the zone.js-0.11.3 release (#39440)
PR Close #39440
2020-10-29 15:40:29 -07:00
Igor Minar e45da28ed5 build: update to CLI 11.0.0-rc.1 (#39432)
This release fixed the previously found size regressions.

PR Close #39432
2020-10-29 13:47:12 -07:00
Igor Minar 5bb5069836 build: update to @angular/cli@11.0.0-rc.0 (#39432)
This updates just the cli packages, the material and cdk packages
will be updated separately.

PR Close #39432
2020-10-29 13:47:12 -07:00
Andrew Kushnir ec416d0210 ci: update NgBot config to include more labels that indicate that ticket is triaged (#39494)
This commit updates the config of NgBot to treat tickets that have "needs clarification" or
"needs reproduction" labels on them as triaged.

PR Close #39494
2020-10-29 12:25:48 -07:00
Michael Ziluck e7f262d691 docs(forms): update ngModel documentation (#39481)
This commit improves the ngModel docs, specifically:
- clarifies purpose of the name attribute in ngModelOptions
- clarifies on the interaction with a parent form or lack thereof
- fix inconsistency with analogy for two-way binding
- cleans up some typos and extra wordiness
- clarifies language around common properties
- adds missing preposition to commit message format origins
PR Close #39481
2020-10-29 11:18:55 -07:00
Joey Perrott 8ea0ee918d fix(dev-infra): update generated ng-dev compiled output (#39474)
Update to the new ng-dev generated script.

PR Close #39474
2020-10-29 09:55:28 -07:00
Joey Perrott 6f2b69d94e fix(dev-infra): clean up output of caretaker check command (#39474)
Suppress the logging of the git command executed during the caretaker
check process.

PR Close #39474
2020-10-29 09:55:28 -07:00
Joey Perrott 89835fe8fa feat(dev-infra): allow suppression of GitClients verbose logging (#39474)
Some usages of the `GitClient` are better served by suppressing the
logging of lines that express what commands are being run. Many usages
of `GitClient` are contained within tools which are best served by
keeping the output clean as mostly read actions are occurring.

PR Close #39474
2020-10-29 09:55:28 -07:00
Joey Perrott b0e114e51d build: create yarn command for running local version of ng-dev (#39474)
For better development experience of the dev-infra work, the `ng-dev:dev`
command runs the transpiled version of `ng-dev` making iterative
development easier.

PR Close #39474
2020-10-29 09:55:27 -07:00
Shadab Ansari eccf9d68b8 docs: Match browser name with custom launcher name (#39480)
The browser being launched needs to match the custom launcher name.
Otherwise Karma would still trigger the original Chrome executable without the flags.

PR Close #39480
2020-10-29 08:39:15 -07:00
Alan Agius b8c71c45de docs: rename ng xi18n to ng extract-i18n (#39337)
In Angular CLI version 11, xi18n has been changed from `ng xi18n` to `ng extract-i18n`.

PR Close #39337
2020-10-28 14:42:27 -07:00
Kapunahele Wong daab797f7d docs: move template ref vars doc to concepts section clarify, add scope section, and update headers (#31195)
Fixes #31186. This commit adds more context about the behavior
of template reference variables in nested templates and moves
doc into concepts section.

PR Close #31195
2020-10-28 14:41:45 -07:00
David Shevitz 7c52fc690d docs: archive user-input topic (#39309)
PR Close #39309
2020-10-28 14:41:09 -07:00
Alex Rickabaugh bf05c979a7 release: cut the v11.0.0-rc.1 release 2020-10-28 14:03:23 -07:00
Jessica Janiuk ddc070e778 docs(core): add jessicajaniuk to pullapprove list (#39473)
This just adds jessicajessica to the pullapprove.yml file

PR Close #39473
2020-10-28 11:14:50 -07:00
Thibaut ACKERMANN d746804985 docs(router): Fix ActivationEnd link (#39469)
ActivationEnd goes to ActivationEnd and not to ActivationStart section

PR Close #39469
2020-10-28 11:06:06 -07:00
JiaLiPassion 17fe000879 docs(zone.js): update release doc (#39442)
In the current release doc, we are using some shortcut of `git` command
such as `git ci` `git co`, so in this PR we are updating them
to the normal command, so these commands will work event without
these shortcuts.

PR Close #39442
2020-10-28 10:59:49 -07:00
Joey Perrott 3870d5e629 build: add PullApprove: disable as a caretaker note label (#39430)
Add the label `PullApprove: disable` as a caretaker note label to
prompt caretakers to confirm that the PullApprove disabling is
intentional.

PR Close #39430
2020-10-28 10:59:11 -07:00
Joey Perrott 112f7e9b58 ci: allow for disabling PullApprove on a single PR via adding a label (#39430)
Alowing for disabling PullApprove on a single PR via adding a label allows
for an escape hatch if PullApprove is not acting as expected, or for cases
where reviews can be stepped over in obvious situations, such as a revert.

PR Close #39430
2020-10-28 10:59:11 -07:00
Deborah Kurata 2bc8b807c4 docs: Correct a few typographical errors. (#39405)
PR Close #39405
2020-10-28 10:58:27 -07:00
Aristeidis Bampakos 65d1ed38e0 docs: update Learning Angular book edition (#39400)
Update the resource Learning Angular book into the third edition

PR Close #39400
2020-10-28 10:57:43 -07:00
Oliver Schlegel 75110f7487 docs: Fix typo in changelog (#39223)
PR Close #39223
2020-10-28 10:56:20 -07:00
Gustav Bylund 2632510f87 docs: fix links to Material examples (#39093)
Also uses fixed git hashes so the line numbers won't get outdated in the
future

PR Close #39093
2020-10-28 10:53:17 -07:00
Carlos Caballero f61ac8a60e docs: add carlos caballero to GDE resources (#37976)
PR Close #37976
2020-10-28 10:52:35 -07:00
twerske 366be11150 refactor(core): add top 10 runtime error codes (#39188)
adds RuntimeError and code enum to improve debugging experience
refactor ExpressionChangedAfterItHasBeenCheckedError to code NG0100
refactor CyclicDependency to code NG0200
refactor No Provider to code NG0201
refactor MultipleComponentsMatch to code NG0300
refactor ExportNotFound to code NG0301
refactor PipeNotFound to code NG0302
refactor BindingNotKnown to code NG0303
refactor NotKnownElement to code NG0304

PR Close #39188
2020-10-28 10:05:02 -07:00
Andrew Kushnir 899218de1f refactor(forms): move common validators-related logic to the AbstractControlDirective class (#38280)
This commit refactors validators-related logic that is common across most of the directives.

A couple notes on this refactoring:
* common logic was moved to the `AbstractControlDirective` class (including `validator` and
`asyncValidator` getters)
* sync/async validators are now composed in `AbstractControlDirective` class eagerly when validators
are set with `_setValidators` and `_setAsyncValidators` calls and the result is stored in directive
instance (thus getters return cached versions of validator fn). This is needed to make sure composed
validator function remains the same (retains its identity) for a given directive instance, so that
this function can be added and later removed from an instance of an AbstractControl-based class
(like `FormControl`). Preserving validator function is required to perform proper cleanup (in followup
PRs) of the AbstractControl-based classes when a directive is destroyed.

PR Close #38280
2020-10-28 09:48:21 -07:00
Joey Perrott 399f491894 ci: bust cache of stored node_modules on CircleCI (#39461)
Update the cache keys used on CircleCI to bust the cache used in attempt
to address issue with tests on aio that are not reproducable locally.

Note: Going back to v1 as the cache version as caches are only held
for 15 days so we can safely return back to `v1` as the prefix

PR Close #39461
2020-10-27 14:53:10 -07:00
Nhan Nguyen 910fa51e76 docs: add install Firebase CLI step before using its commands (#39079)
PR Close #39079
2020-10-27 14:29:06 -07:00
JiaLiPassion f184578e2e docs(core): update a typo in the comment of ngZoneEventCoalescing (#39423)
PR Close #39423
2020-10-27 14:27:16 -07:00
ayazhafiz d76beda439 fix(compiler): do not throw away render3 AST on errors (#39413)
Currently render3's `parseTemplate` throws away the parsed AST and
returns an empty list of HTML nodes if HTML->R3 translation failed. This
is not preferrable in some contexts like that of a language service,
where we would like a well-formed AST even if it is has errors.

PR Close #39413
2020-10-27 13:37:20 -07:00
Pete Bacon Darwin 72e0c6b8be Revert "perf(ngcc): allow immediately reporting a stale lock file (#37250)" (#39435)
This reverts commit 561c0f81a0.

The original commit provided a quick escape from an already terminal
situation by killing the process if the PID in the lockfile was not
found in the list of processes running on the current machine.

But this broke use-cases where the node_modules was being shared between
multiple machines (or more commonly Docker containers on the same actual
machine).

Fixes #38875

PR Close #39435
2020-10-27 13:36:28 -07:00
Kristiyan Kostadinov bf1caa7ad1 fix(compiler): treat i18n attributes with no bindings as static attributes (#39408)
Currently `i18n` attributes are treated the same no matter if they have data bindings or not. This
both generates more code since they have to go through the `ɵɵi18nAttributes` instruction and
prevents the translated attributes from being injected using the `@Attribute` decorator.

These changes makes it so that static translated attributes are treated in the same way as regular
static attributes and all other `i18n` attributes go through the old code path.

Fixes #38231.

PR Close #39408
2020-10-27 13:31:30 -07:00
pmartijena 4b26a05dbc docs: fix grammatical errors and typos (#38868)
Fixed run on sentences, grammatical errors, and made "ivy" "Ivy" everywhere for consistency.
PR Close #38868
2020-10-27 13:18:02 -07:00
Alex Rickabaugh 70daf10b86 refactor(compiler-cli): API to get directives/pipes in scope (#39278)
This commit introduces two new methods to the TemplateTypeChecker, which
retrieve the directives and pipes that are "in scope" for a given component
template. The metadata returned by this API is minimal, but enough to power
autocompletion of selectors and attributes in templates.

PR Close #39278
2020-10-27 13:17:14 -07:00
Alex Rickabaugh 1bfc44d48a refactor(compiler-cli): cache Symbols in the TemplateTypeCheckerImpl (#39278)
This commit introduces caching of `Symbol`s produced by the template type-
checking infrastructure, in the same way that autocompletion results are
now cached.

PR Close #39278
2020-10-27 13:17:14 -07:00
Alex Rickabaugh 2a0a287121 refactor(compiler-cli): move global completion into new CompletionEngine (#39278)
This commit refactors the previously introduced `getGlobalCompletions()` API
for the template type-checker in a couple ways:

 * The return type is adjusted to use a `Map` instead of an array, and
   separate out the component context completion position. This allows for a
   cleaner integration in the language service.
 * A new `CompletionEngine` class is introduced which powers autocompletion
   for a single component, and can cache completion results.
 * The `CompletionEngine` for each component is itself cached on the
   `TemplateTypeCheckerImpl` and is invalidated when the component template
   is overridden or reset.

This refactoring simplifies the `TemplateTypeCheckerImpl` class by
extracting the autocompletion logic, enables caching for better performance,
and prepares for the introduction of other autocompletion APIs.

PR Close #39278
2020-10-27 13:17:14 -07:00
Joey Perrott 523a451a68 build: add husky ignored files to .gitignore (#39388)
Ahead of upgrading to husky v5, adding the shell file location
to .gitignore to prevent it from randomly showing up when devs
checkout older branches.  Beginning in v5, husky places its
shell files in a directory at `.husky/_` so these are placed
in the .gitignore to prevent being commited or tracked.

PR Close #39388
2020-10-27 11:07:22 -07:00
Alan Agius 13063c45d5 ci: add alan-agius4 to docs-cli in pullapprove configuration (#39448)
Add alan-agius4 to `docs-cli` group in pullapprove configuration.

PR Close #39448
2020-10-27 10:49:09 -07:00
George Kalpakas 89c6d109e1 build(docs-infra): upgrade cli command docs sources to d5c1851de (#39446)
Updating [angular#11.0.x](https://github.com/angular/angular/tree/11.0.x) from
[cli-builds#11.0.x](https://github.com/angular/cli-builds/tree/11.0.x).

##
Relevant changes in
[commit range](https://github.com/angular/cli-builds/compare/deec40756...d5c1851de):

**Modified**
- help/build.json

##
Relevant changes in
[commit range](https://github.com/angular/cli-builds/compare/deec40756...d5c1851de) since PR #39407:

**Modified**
- help/build.json

##
Closes #39407

PR Close #39446
2020-10-27 10:48:31 -07:00
imkikus 6c79598eb6 docs: fix more typos in component overview (#39445)
PR Close #39445
2020-10-27 10:47:36 -07:00
AleksanderBodurri 65abf7effa docs: fix typo in initializeInputAndOutputAliases docstring (#39438)
PR Close #39438
2020-10-27 10:46:38 -07:00
Andrew Kushnir d1840eed36 refactor(core): remove expandoStartIndex workaround (#39416)
This commit removes a workaround to calculate the `expandoStartIndex` value. That workaround was needed
because the `expandoStartIndex` was updated previously, so it pointed at the wrong location. The problem
was fixed in PR #39301 and the workaround is no longer needed.

PR Close #39416
2020-10-27 10:45:53 -07:00
JoostK cc329325ac fix(core): do not error when ngDevMode is undeclared (#39415)
In production mode, the `ngDevMode` global may not have been declared.
This is typically not a problem, as optimizers should have removed all
usages of the `ngDevMode` variables. This does however require the
bundler/optimizer to have been configured in a certain way, as to allow
for `ngDevMode` guarded code to be removed.

As an example, Terser can be configured to remove the `ngDevMode`
guarded code using the following configuration:

```js
const terserOptions = {
  // ...
  compress: {
    // ...
    global_defs: require('@angular/compiler-cli').GLOBAL_DEFS_FOR_TERSER,
  }
}
```

(Taken from https://github.com/angular/angular/issues/31595#issuecomment-519129090)

If this is not done, however, the bundle should still work (albeit with
larger code size due to missed tree-shaking opportunities). This commit
adds a check for whether `ngDevMode` has been declared, as it is a
top-level statement that executes before `ngDevMode` has been initialized.

Fixes #31595

PR Close #39415
2020-10-27 10:45:19 -07:00
Pete Bacon Darwin 32163ef355 fix(localize): render placeholder types in extracted XLIFF files (#39398)
The previous ViewEngine extraction tooling added `ctype` and `type`
attributes to XLIFF 1.2 and 2.0 translation files, respectively.

This commit adds this to the new $localize based extraction tooling.
Since the new extraction tooling works from the compiled output rather
than having direct access to the template content, the placeholder types
must be inferred from the name of the placeholder.  This is considered
reasonable, since it already does this to compute opening and closing
tag placeholders.

Fixes #38791

PR Close #39398
2020-10-27 10:42:16 -07:00
Andrew Kushnir 97b4653cab refactor(core): remove unused i18n placeholder for projection (#39172)
Runtime i18n logic doesn't distinguish `<ng-content>` tag placeholders and regular element tag
placeholders in i18n messages, so there is no need to have a special marker for projection-based
placeholders and element markers can be used instead.

PR Close #39172
2020-10-27 10:39:38 -07:00
AleksanderBodurri 291322fd53 docs(forms): add section under Validators.pattern detailing use of global and sticky flags gotcha (#39055)
Due to how the global and sticky flag make RegExp objects stateful,
adds section detailing how it is not recommended
to use these flags for control validations.

PR Close #39055
2020-10-27 10:38:49 -07:00
Kapunahele Wong a94852c97d docs: edit event-binding doc copy and headers (#38903)
PR Close #38903
2020-10-27 10:37:31 -07:00
Jethro Lee 758c52b3bf docs: move placement of help note in tutorial (#38508)
PR Close #38508
2020-10-27 10:37:00 -07:00
Joey Perrott a4ea0bbe67 fix(dev-infra): ensure hashbang is present in both published and local ng-devs (#39443)
The node hash bang was incidentally removed in the published ng-dev, it should
be included to allow for the command to be run without having to specify node.

PR Close #39443
2020-10-27 09:28:39 -07:00
Kiran Kumaar Sathyanarayana 3fbf32534c docs: fix typo in component overview (#39425)
Fixes #39424

PR Close #39425
2020-10-26 10:53:07 -07:00
Pete Bacon Darwin f5710c6902 fix(localize): serialize all the message locations to XLIFF (#39411)
Previously only the first message, for each id, was serialized
which meant that additional message location information
was lost.

Now all the message locations are included in the serialized
messages.

Fixes #39330

PR Close #39411
2020-10-26 10:52:31 -07:00
George Kalpakas e8e3771002 build(docs-infra): ignore doc.basePath when generating keywords for each document (#39409)
The `generateKeywords` dgeni processor automatically generates keywords
for each document by extracting words from each string property of a
`doc` object.

This commit adds `basePath` to the list of ignored properties, so that
it is _not_ considered when generating keywords. `basePath` mostly
contains the path to some root directory (such as
`/home/circleci/ng/packages`) and as such it does not contain useful
keywords.

For example, searching for `circleci` will match all API docs, because
it happens to be in the `basePath`:
https://v10.angular.io/?search=circleci

PR Close #39409
2020-10-26 10:52:01 -07:00
George Kalpakas 8bc295ffc3 build(docs-infra): upgrade cli command docs sources to deec40756 (#39407)
Updating [angular#11.0.x](https://github.com/angular/angular/tree/11.0.x) from
[cli-builds#11.0.x](https://github.com/angular/cli-builds/tree/11.0.x).

##
Relevant changes in
[commit range](https://github.com/angular/cli-builds/compare/35611e878...deec40756):

**Modified**
- help/generate.json

##
Relevant changes in
[commit range](https://github.com/angular/cli-builds/compare/35611e878...deec40756) since PR #39381:

**Modified**
- help/generate.json

##
Closes #39381

PR Close #39407
2020-10-26 10:51:36 -07:00
Andrew Kushnir f1a1a205d6 docs: improve DefaultValueAccessor directive docs (#39404)
This commit improves the DefaultValueAccessor directive docs by:
- adding the `ngDefaultControl` as a search keyword to the description
- adding an example of the `ngDefaultControl` usage

Closes #35375.

PR Close #39404
2020-10-26 10:50:43 -07:00
Aristeidis Bampakos b73d59e241 docs: use SimpleChanges in component interaction guide (#39342)
Use the SimpleChanges interface in the example of component interaction guide

PR Close #39342
2020-10-26 10:47:33 -07:00
JiaLiPassion 6669571884 fix(zone.js): remove global declaration (#37861)
Close #37531

Remove `global` declaration in `zone.ts` to avoid compile error when
upgrade to `@types/node` v12.12.68. Since the new type of global become
`NodeJS.global & typeof globalThis` and not compatible with `zone.ts` declaration.

PR Close #37861
2020-10-23 15:19:49 -07:00
Joey Perrott 84e09a06e3 fix(bazel): only providing stamping information if the --stamp flag is used (#39392)
Previously the volatile status file was always provided to the ng_rollup
action which prevented it from being cacheable remotely.  This change to
only provide this file as an input when the --stamp flag is used will allow
for the action to be remotely cached and prevent needing to run the action
on every CI run.

PR Close #39392
2020-10-23 15:18:15 -07:00
Pete Bacon Darwin ef28295bf7 refactor(compiler-cli): support namespaced references (#39346)
The compiler uses a `Reference` abstraction to refer to TS nodes
that it needs to refer to from other parts of the source. Such
references keep track of any identifiers that represent the referenced
node.

Prior to this commit, the compiler (and specifically `ReferenceEmitter`
classes) assumed that the reference identifiers are always free standing.
In other words a reference identifier would be an expression like
`FooDirective` in the expression `class FooDirective {}`.

But in UMD/CommonJS source, a reference can actually refer to an "exports"
declaration of the form `exports.FooDirective = ...`.
In such cases the `FooDirective` identifier is not free-standing
since it is part of a property access, so the `ReferenceEmitter`
should take this into account when emitting an expression that
refers to such a `Reference`.

This commit changes the `LocalIdentifierStrategy` reference emitter
so that if the `node` being referenced is not a declaration itself and
is in the current file, then it should be used directly, rather than
trying to use one of its identifiers.

PR Close #39346
2020-10-23 15:17:16 -07:00
Pete Bacon Darwin fc2e3cc84d fix(ngcc): capture UMD/CommonJS inner class implementation node correctly (#39346)
Previously, UMD/CommonJS class inline declarations of the form:

```ts
exports.Foo = (function() { function Foo(); return Foo; })();
```

were capturing the whole IIFE as the implementation, rather than
the inner class (i.e. `function Foo() {}` in this case). This caused
the interpreter to break when it was trying to access such an export,
since it would try to evaluate the IIFE rather than treating it as a class
declaration.

PR Close #39346
2020-10-23 15:17:16 -07:00
Joey Perrott 084b082f5c fix(core): update expected size for cli-hello-world-ivy-i18n integration test (#39402)
Update the expected size for cli-hello-world-ivy-i18n after changes to i18n.

PR Close #39402
2020-10-23 10:34:35 -07:00
Krishnabisht07 dbc9547643 docs: template files should have .html extension (#39384)
Fixes a typo in the component guide

PR Close #39384
2020-10-22 14:06:31 -07:00
Kapunahele Wong 8144ea5cc9 docs: move hierarchical injectors to reference section (#39383)
PR Close #39383
2020-10-22 14:04:49 -07:00
George Kalpakas 91e2851f5d build(docs-infra): upgrade cli command docs sources to 35611e878 (#39381)
Updating [angular#11.0.x](https://github.com/angular/angular/tree/11.0.x) from
[cli-builds#11.0.x](https://github.com/angular/cli-builds/tree/11.0.x).

##
Relevant changes in
[commit range](https://github.com/angular/cli-builds/compare/edfbf4ba4...35611e878):

**Modified**
- help/update.json

**Renamed**
- help/extract-i18n.json

PR Close #39381
2020-10-22 13:52:40 -07:00
George Kalpakas 6c7e16ab08 build: update lock-closed GitHub action to latest version (#39371)
This commit updates the version of the `dev-infra/lock-closed` GitHub
action to the latest version, that includes the fix from
angular/dev-infra#80.

PR Close #39371
2020-10-22 13:46:25 -07:00
AleksanderBodurri 54366c3590 docs: update broken akita link in aio dev resources page (#39335)
fixes #39331

PR Close #39335
2020-10-22 13:43:55 -07:00
twerske 252ef62e41 refactor(core): group provider and circular errors (#39251)
group together similar error messages as part of error code efforts
ProviderNotFound & NodeInjector grouped into throwProviderNotFoundError
Cyclic dependency errors grouped into throwCyclicDependencyError

PR Close #39251
2020-10-22 13:42:36 -07:00
ayazhafiz 6b7ca5956a test(compiler): Demonstrate recoverable parsing of unterminated pipes (#39113)
There is no actionable change in this commit other than to pretty-print
EOF tokens. Actual parsing of unterminated pipes is already supported,
this just adds a test for it.

Part of #38596

PR Close #39113
2020-10-22 13:41:52 -07:00
Joey Perrott 1e91958b69 refactor(dev-infra): create ng-dev executable locally in the repo (#39089)
Rather than running ng-dev via ts-node, going forward ng-dev is generated and run
locally via node.  Additionally, the generated file is tested on each commit to
ensure that the local generated version stays up to date.

PR Close #39089
2020-10-22 13:36:16 -07:00
Misko Hevery 9309a51368 refactor(core): Improve tree shakability of i18n code. (#39301)
`TNode.insertBeforeIndex` is only populated when i18n is present. This
change puts all code which reads `insertBeforeIndex` behind a
dynamically loaded functions which are set only when i18n code executes.

PR Close #39301
2020-10-22 09:35:49 -07:00
Misko Hevery 44f245a0c3 docs(core): Add documentation on debugging size regression failures (#39301)
PR Close #39301
2020-10-22 09:35:49 -07:00
Misko Hevery 298c9822f0 refactor(core): Replace ExpandoInstructions with HostBindingOpCodes (#39301)
The `ExpandoInstructions` was unnecessarily convoluted way to solve the
problem of calling the `HostBindingFunction`s on components and
directives. The code was complicated and hard to fallow.

The replacement is a simplified way to achieve the same thing, which
is also more efficient in space and speed.

PR Close #39301
2020-10-22 09:35:49 -07:00
Misko Hevery 13f9120b92 refactor(core): clean up circular dependencies (#39233)
Moved code from `interfaces/i18n.ts` which was causing circular dependencies

PR Close #39233
2020-10-21 18:33:01 -07:00
Misko Hevery a92b5317bf refactor(core): Use ~x instead of -x which can result in -0 (#39233)
`expandoInstructions` uses negative numbers by `-x`. This has lead to
issues in the paste as `-0` is processed as float rather than integer
leading to de-optimization.

PR Close #39233
2020-10-21 18:33:01 -07:00
Misko Hevery 61e98f8352 refactor(core): Consistent use of HEADER_OFFSET (in ɵɵ* instructions only) (#39233)
IMPORTANT: `HEADER_OFFSET` should only be refereed to the in the `ɵɵ*` instructions to translate
instruction index into `LView` index. All other indexes should be in the `LView` index space and
there should be no need to refer to `HEADER_OFFSET` anywhere else.

PR Close #39233
2020-10-21 18:33:01 -07:00
Misko Hevery f2fea8c94f refactor(core): cleanup i18n/icu data structures (#39233)
- Made `*OpCodes` array branded for safer type checking.
- Simplify `I18NRemoveOpCodes` encoding.
- Broke out  `IcuCreateOpCodes` from `I18nMutableOpCodes`.

PR Close #39233
2020-10-21 18:33:01 -07:00
Misko Hevery 3fcbdc5c25 refactor(core): rename COMMENT_MARKER to ICU_MARKER (#39233)
`COMMENT_MARKER` is a generic name which does not make it obvious that
it is used for ICU use case. `ICU_MARKER` is more explicit as it is used
exclusively with ICUs.

PR Close #39233
2020-10-21 18:33:01 -07:00
Misko Hevery cd2bf969f4 refactor(core): Rename debugMatch to matchDebug for consistency (#39233)
Previous function name `debugMatch` was not consistent with other match
functions.

PR Close #39233
2020-10-21 18:33:00 -07:00
Misko Hevery 279de9f0ff refactor(core): Create TNodeType.Text to display full template in TView debug (#39233)
When looking at `TView` debug template only Element nodes were displayed
as `TNode.Element` was used for both `RElement` and `RText`.
Additionally no text was stored in `TNode.value`. The result was that
the whole template could not be reconstructed. This refactoring creates
`TNodeType.Text` and store the text value in `TNode.value`.

The refactoring also changes `TNodeType` into flag-like structure make
it more efficient to check many different types at once.

PR Close #39233
2020-10-21 18:33:00 -07:00
Misko Hevery 7d43ca9dfe refactor(core): Remove hack where we TIcu was stored in tagName (#39233)
Remove casting where we stored `TIcu` in `TNode.tagName` which was of
type `string` rather than `TIcu'. (renamed to `TNode.value` in previous
commit.)

PR Close #39233
2020-10-21 18:33:00 -07:00
Misko Hevery 4e29200dfc refactor(core): Change TName.tagName to a more generic value name. (#39233)
This is a pre-requisite for making the `TNode.value` a generic storage
mechanism for attaching data to `TNode`.

PR Close #39233
2020-10-21 18:33:00 -07:00
Misko Hevery 0992b678f0 fix(core): Store ICU state in LView rather than in TView (#39233)
Before this refactoring/fix the ICU would store the current selected
index in `TView`. This is incorrect, since if ICU is in `ngFor` it will
cause issues in some circumstances. This refactoring properly moves the
state to `LView`.

closes #37021
closes #38144
closes #38073

PR Close #39233
2020-10-21 18:33:00 -07:00
Misko Hevery c83a389aea refactor(core): move i18n_spec.ts into i18n subfolder (#39233)
`i18n_spec.ts` file was incorrectly in the `render3` folder rather than `render3/i18n`

PR Close #39233
2020-10-21 18:33:00 -07:00
Misko Hevery f875b0d9b6 refactor(core): Change TemplateFixture to named parameters (#39233)
`TemplateFixture` used to have positional parameters and many tests got
hard to read as number of parameters reach 10+ with many of them `null`.
This refactoring changes `TemplateFixture` to take named parameters
which improves usability and readability in tests.

PR Close #39233
2020-10-21 18:33:00 -07:00
Joey Perrott 7f79e77c66 build: update bazelversion (#39351)
Updates to the latest version of bazel

PR Close #39351
2020-10-21 11:59:44 -07:00
Andrew Kushnir 08a4c5b5df release: cut the v11.0.0-rc.0 release 2020-10-21 18:35:45 +00:00
Keen Yee Liau b4e8399144 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
2020-10-21 09:41:58 -07:00
George Kalpakas d8c9f42689 build(docs-infra): upgrade cli command docs sources to edfbf4ba4 (#39361)
Updating [angular#11.0.x](https://github.com/angular/angular/tree/11.0.x) from
[cli-builds#11.0.x](https://github.com/angular/cli-builds/tree/11.0.x).

##
Relevant changes in
[commit range](https://github.com/angular/cli-builds/compare/d00915917...edfbf4ba4):

**Modified**
- help/build.json
- help/generate.json
- help/serve.json
- help/update.json
- help/xi18n.json

PR Close #39361
2020-10-21 08:28:04 -07:00
Arnaud Bernard 8b36487cbc 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:33 -07:00
Alan Agius 63b8c04372 docs: add strictInputAccessModifiers to strict mode guide (#39353)
This change also remove the duplicate mention of strictTemplates

PR Close #39353
2020-10-21 08:24:47 -07:00
Kapunahele Wong e30c6519d3 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:45 -07:00
Bjarki ac53101fc6 build: upgrade karma to version 4.4.0 (#39180)
Upgrade the karma dependency to version 4.4.0 in the root package.json
and in integration tests. Compared to version 4.3.0, which most of the
packages were previously depending on, it has the following changes:

Bug Fixes
- runner: remove explicit error on all tests failed

Features
- client: Add trusted types support
- Preprocessor can return Promise
- config: add failOnSkippedTests option.
- config: clientDisplayNone sets client elements display none.
- deps: Remove core-js dependency.

The motivation for upgrading the package is the Trusted Types support
that it adds, which is necessary to enable Trusted Types in Angular's
unit tests.

PR Close #39180
2020-10-20 16:27:56 -07:00
Kristiyan Kostadinov 161b278b6f fix(router): incorrect signature for createUrlTree (#39347)
The type of the `navigationExtras` param was accidetally changed to the wrong symbol
in https://github.com/angular/angular/commit/783a5bd7bbae35562e21aaa27771c54091fb9812.
These changes revert it to the correct one.

PR Close #39347
2020-10-20 13:36:13 -07:00
Joey Perrott 3738233f16 fix(common): update locales using new CLDR data (#39343)
Update the derived locales based on the new CLDR data.

PR Close #39343
2020-10-20 13:22:38 -07:00
Joey Perrott 38a3c31ada build: update to cldr v37 (#39343)
Update to use a newer version of CLDR data, version 37.

PR Close #39343
2020-10-20 13:22:38 -07:00
Dave Shevitz 595062e415 docs: Add Component Overview topic to angular.io (#39186)
PR Close #39186
2020-10-20 10:47:47 -07:00
Joey Perrott f341da8a43 build: revert back to downloading cldr-data directly rather than via npm (#39341)
Revert back to downloading cldr-data directly as the npm package seems
to no longer be maintained and additionally, it carries a ~350mb cost
in our node modules that is unnecessarily downloaded by most developers
and on CI.

PR Close #39341
2020-10-20 10:46:20 -07:00
George Kalpakas 44913944a9 build(docs-infra): upgrade cli command docs sources to d00915917 (#39339)
Updating [angular#11.0.x](https://github.com/angular/angular/tree/11.0.x) from
[cli-builds#11.0.x](https://github.com/angular/cli-builds/tree/11.0.x).

##
Relevant changes in
[commit range](https://github.com/angular/cli-builds/compare/2c78d4463...d00915917):

**Modified**
- help/deploy.json

PR Close #39339
2020-10-20 08:49:54 -07:00
Jessica Janiuk 5167eead45 docs: add Jessica Janiuk to contributors.json (#39253)
PR Close #39253
2020-10-19 16:25:19 -07:00
Andrew Kushnir 736e0644b0 refactor(compiler): remove support for TypeScript 3.9 (#39313)
This commit removes TypeScript 3.9 support.

BREAKING CHANGE:

TypeScript 3.9 is no longer supported, please upgrade to TypeScript 4.0.

PR Close #39313
2020-10-19 14:34:46 -07:00
George Kalpakas e0322282e6 build(docs-infra): upgrade cli command docs sources to 2c78d4463 (#39319)
Updating [angular#11.0.x](https://github.com/angular/angular/tree/11.0.x) from
[cli-builds#11.0.x](https://github.com/angular/cli-builds/tree/11.0.x).

##
Relevant changes in
[commit range](https://github.com/angular/cli-builds/compare/a88d21174...2c78d4463):

**Modified**
- help/generate.json
- help/new.json

PR Close #39319
2020-10-19 14:33:49 -07:00
Josh Wiegand 51301b9f4b docs: clarify grammatical error (#39279)
The sentence is grammatically incorrect. The new sentence fixes the error.
PR Close #39279
2020-10-19 14:32:44 -07:00
Joey Perrott d3087be237 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:18 -07:00
Aristeidis Bampakos aba1cb4672 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:33 -07:00
Keen Yee Liau 726c5ef679 Revert "test(language-service): Make project service a singleton (#39308)" (#39322)
This reverts commit 1b21350e17.

PR Close #39322
2020-10-19 09:25:19 -07:00
Johannes Hoppe d30911c4eb docs: add Johannes Hoppe to GDE resources (#34694)
PR Close #34694
2020-10-19 08:04:59 -07:00
Ferdinand Malcher e7f9e6fdac docs: add Ferdinand Malcher to GDE resources (#34694)
PR Close #34694
2020-10-19 08:04:59 -07:00
Vlasis Charalampous 8a744d5246 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:09 -07:00
Joey Perrott 6c9c70a0e4 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:24 -07:00
Keen Yee Liau d2ea9b05d8 test(language-service): Make project service a singleton (#39308)
Constructing a project service is expensive. Making it a singleton could
speed up tests considerably.

On my MacBook Pro, test execution went from 24.4s to 14.5s (~40% improvement).

PR Close #39308
2020-10-16 12:34:16 -07:00
Keen Yee Liau 60b4135795 test(language-service): wrap setup() in beforeAll to speed up fit() test (#39305)
Test harness `setup()` is expensive, in the order of ~2.5 seconds.

We could speed up `fit()` tests considerably if `setup()` is wrapped
in `beforeAll()` to avoid running it unnecessarily.

PR Close #39305
2020-10-16 12:33:36 -07:00
JiaLiPassion a0fde29f80 release: cut the zone.js-0.11.2 release to fix several new issues (#39298)
PR Close #39298
2020-10-16 10:18:55 -07:00
George Kalpakas 09de939694 build(docs-infra): upgrade cli command docs sources to a88d21174 (#39303)
Updating [angular#11.0.x](https://github.com/angular/angular/tree/11.0.x) from
[cli-builds#11.0.x](https://github.com/angular/cli-builds/tree/11.0.x).

##
Relevant changes in
[commit range](https://github.com/angular/cli-builds/compare/d807b8240...a88d21174):

**Modified**
- help/generate.json

PR Close #39303
2020-10-16 10:07:09 -07:00
Kapunahele Wong 13847816d3 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:18 -07:00
Aristeidis Bampakos 63a915b023 docs: Typos fixes in built-in directives guide (#38520)
PR Close #38520
2020-10-16 10:05:29 -07:00
Pete Bacon Darwin fdbc61111d 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:42 -07:00
mcalmus f541e5f39d 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:25 -07:00
Jessica Janiuk 20b801e707 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:24 -07:00
James Davies bed8c1c814 docs: Very minor spelling mistake (#39299)
1659: teh -> the
PR Close #39299
2020-10-15 17:00:21 -07:00
Andrew Scott 6acddb9518 refactor(language-service): Return directive defs when input name is part of selector (#39243)
When an input name is part of the directive selector, it would be good to return the directive as well
when performing 'go to definition' or 'go to type definition'. As an example, this would allow
'go to type definition' for ngIf to take the user to the NgIf directive.
'Go to type definition' would otherwise return no results because the
input is a generic type. This would also be the case for all primitive
input types.

PR Close #39243
2020-10-15 14:17:24 -07:00
Nicholas Papadopoulos 5e1c7e69e6 docs: fix typo at console.log (#39252)
PR Close #39252
2020-10-15 14:15:38 -07:00
CharaLagou 61cd1b685a docs(core): fix typo in the "Template statements" guide (#39244)
PR Close #39244
2020-10-15 14:14:28 -07:00
Joey Perrott b05af6dd53 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:33 -07:00
Stefanie Fluin cd4388e523 docs: update readme (#32084)
PR Close #32084
2020-10-15 14:08:20 -07:00
David Shevitz 9269ad9626 docs: Move pipes documentation from Components to Templates (#38983)
PR Close #38983
2020-10-15 14:07:30 -07:00
David Shevitz c1e0776d39 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:30 -07:00
Joey Perrott 14f15ecd38 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:17:42 -07:00
428 changed files with 21840 additions and 7930 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
3.5.1
3.6.0
# [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
-4
View File
@@ -6,10 +6,6 @@
# 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=120000
build --local_cpu_resources=32
+18 -11
View File
@@ -22,16 +22,16 @@ version: 2.1
# **NOTE 1 **: If you change the cache key prefix, also sync the cache_key_fallback to match.
# **NOTE 2 **: Keep the static part of the cache key as prefix to enable correct fallbacks.
# See https://circleci.com/docs/2.0/caching/#restoring-cache for how prefixes work in CircleCI.
var_3: &cache_key v7-angular-node-12-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }}
var_3: &cache_key v1-angular-node-12-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }}
# We invalidate the cache if the Bazel version changes because otherwise the `bazelisk` cache
# 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_4: &cache_key_fallback v1-angular-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.
var_5: &components_repo_unit_tests_cache_key v9-angular-components-09e68db8ed5b1253f2fe38ff954ef0df019fc25a
var_6: &components_repo_unit_tests_cache_key_fallback v9-angular-components-
var_5: &components_repo_unit_tests_cache_key v1-angular-components-09e68db8ed5b1253f2fe38ff954ef0df019fc25a
var_6: &components_repo_unit_tests_cache_key_fallback v1-angular-components-
# Workspace initially persisted by the `setup` job, and then enhanced by `build-npm-packages` and
# `build-ivy-npm-packages`.
@@ -748,19 +748,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
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:
+6
View File
@@ -165,6 +165,12 @@ triage:
-
- "discussion"
- "comp: *"
-
- "needs clarification"
- "comp: *"
-
- "needs reproduction"
- "comp: *"
# options for the triage PR plugin
triagePR:
+1 -1
View File
@@ -10,6 +10,6 @@ jobs:
if: github.repository == 'angular/angular'
runs-on: ubuntu-latest
steps:
- uses: angular/dev-infra/github-actions/lock-closed@414834b2b24dd2df37c6ed00808387ee6fd91b66
- uses: angular/dev-infra/github-actions/lock-closed@0fc6f4d839e93312ed0dd9a2be88d4c11e947a0b
with:
lock-bot-key: ${{ secrets.LOCK_BOT_PRIVATE_KEY }}
+6
View File
@@ -48,3 +48,9 @@ baseline.json
# Ignore .history for the xyz.local-history VSCode extension
.history
# CLDR data
tools/gulp-tasks/cldr/cldr-data/
# Husky
.husky/_
+2
View File
@@ -16,6 +16,8 @@ export const format: FormatConfig = {
'!.yarn/**',
// Do not format d.ts files as they are generated
'!**/*.d.ts',
// Do not format generated ng-dev script
'!dev-infra/ng-dev.js',
]
},
'buildifier': true
+1 -1
View File
@@ -12,7 +12,7 @@ export const merge: DevInfraMergeConfig['merge'] = async api => {
githubApiMerge: false,
claSignedLabel: 'cla: yes',
mergeReadyLabel: /^action: merge(-assistance)?/,
caretakerNoteLabel: 'action: merge-assistance',
caretakerNoteLabel: /^(action: merge-assistance)|(PullApprove: disable)/,
commitMessageFixupLabel: 'commit message fixup',
// We can pick any of the NPM packages as we are in a monorepo where all packages are
// published together with the same version and branching.
+16 -1
View File
@@ -103,6 +103,8 @@ meta:
github_api_version: "shadow-cat-preview"
pullapprove_conditions:
# For PRs which are still being worked on, either still in draft mode or indicated through WIP in
# title or label, PullApprove stays in a pending state until its ready for review.
- condition: "'WIP' not in title"
unmet_status: pending
explanation: "Waiting to send reviews as PR is WIP"
@@ -112,6 +114,10 @@ pullapprove_conditions:
- condition: "not draft"
unmet_status: pending
explanation: "Waiting to send reviews as PR is in draft"
# Disable PullApprove on specific PRs by adding the `PullApprove: disable` label
- condition: "'PullApprove: disable' not in labels"
unmet_status: success
explanation: "PullApprove skipped because of 'PullApprove: disable' label"
groups:
@@ -186,6 +192,7 @@ groups:
- IgorMinar # Igor Minar
- jbogarthyde # Judy Bogart
- jelbourn # Jeremy Elbourn
- jessicajaniuk # Jessica Janiuk
- JiaLiPassion # Jia Li
- JoostK # Joost Koehoorn
- josephperrott # Joey Perrott
@@ -323,6 +330,8 @@ 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/**',
@@ -368,6 +377,7 @@ groups:
'aio/content/guide/built-in-template-functions.md',
'aio/content/examples/built-in-template-functions/**',
'aio/content/guide/event-binding.md',
'aio/content/guide/event-binding-concepts.md',
'aio/content/examples/event-binding/**',
'aio/content/guide/interpolation.md',
'aio/content/examples/interpolation/**',
@@ -377,6 +387,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',
@@ -405,6 +416,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',
@@ -418,6 +430,7 @@ groups:
- atscott
- ~kara # do not request reviews from Kara, but allow her to approve PRs
- mhevery
- jessicajaniuk
# OOO as of 2020-09-28 - pkozlowski-opensource
@@ -644,7 +657,7 @@ groups:
- *can-be-global-docs-approved
- >
contains_any_globs(files.exclude('packages/compiler-cli/**'), [
'**/testing/**',
'packages/**/testing/**',
'aio/content/guide/testing.md',
'aio/content/guide/test-debugging.md',
'aio/content/guide/testing-attribute-directives.md',
@@ -1011,6 +1024,7 @@ groups:
])
reviewers:
users:
- alan-agius4
- clydin
- IgorMinar
- mgechev
@@ -1120,6 +1134,7 @@ groups:
'docs/SAVED_REPLIES.md',
'docs/TOOLS.md',
'docs/TRIAGE_AND_LABELS.md',
'docs/images/**',
'goldens/*',
'modules/*',
'packages/*',
+77 -11
View File
@@ -1,3 +1,75 @@
<a name="11.0.0-rc.2"></a>
# 11.0.0-rc.2 (2020-11-04)
### Bug Fixes
* **common:** change the week-numbering year format from `r` -> `Y` ([#39495](https://github.com/angular/angular/issues/39495)) ([feda78e](https://github.com/angular/angular/commit/feda78e))
* **compiler:** preserve this.$event and this.$any accesses in expressions ([#39323](https://github.com/angular/angular/issues/39323)) ([a8e0db7](https://github.com/angular/angular/commit/a8e0db7)), closes [#30278](https://github.com/angular/angular/issues/30278)
* **compiler-cli:** generating invalid setClassMetadata call in ES5 for class with custom decorator ([#39527](https://github.com/angular/angular/issues/39527)) ([b0bbc1f](https://github.com/angular/angular/commit/b0bbc1f)), closes [#39509](https://github.com/angular/angular/issues/39509)
* **compiler-cli:** report missing pipes when `fullTemplateTypeCheck` is disabled ([#39320](https://github.com/angular/angular/issues/39320)) ([67ea7b6](https://github.com/angular/angular/commit/67ea7b6)), closes [#38195](https://github.com/angular/angular/issues/38195)
* **core:** markDirty() should only mark flags when really scheduling tick. ([#39316](https://github.com/angular/angular/issues/39316)) ([3b6497b](https://github.com/angular/angular/commit/3b6497b)), closes [#39296](https://github.com/angular/angular/issues/39296)
* **forms:** remove validators while cleaning up a control ([#39234](https://github.com/angular/angular/issues/39234)) ([43b4940](https://github.com/angular/angular/commit/43b4940))
* **router:** Ensure all outlets are used when commands have a prefix ([#39456](https://github.com/angular/angular/issues/39456)) ([b2f3952](https://github.com/angular/angular/commit/b2f3952))
### Performance Improvements
* **compiler-cli:** only generate template context declaration when used ([#39321](https://github.com/angular/angular/issues/39321)) ([1ac0500](https://github.com/angular/angular/commit/1ac0500))
* **core:** do not recurse into modules that have already been registered ([#39514](https://github.com/angular/angular/issues/39514)) ([5c13c67](https://github.com/angular/angular/commit/5c13c67)), closes [#39487](https://github.com/angular/angular/issues/39487)
<a name="11.0.0-rc.1"></a>
# 11.0.0-rc.1 (2020-10-28)
### Bug Fixes
* **bazel:** only providing stamping information if the --stamp flag is used ([#39392](https://github.com/angular/angular/issues/39392)) ([84e09a0](https://github.com/angular/angular/commit/84e09a0))
* **compiler:** do not throw away render3 AST on errors ([#39413](https://github.com/angular/angular/issues/39413)) ([d76beda](https://github.com/angular/angular/commit/d76beda))
* **compiler:** treat i18n attributes with no bindings as static attributes ([#39408](https://github.com/angular/angular/issues/39408)) ([bf1caa7](https://github.com/angular/angular/commit/bf1caa7)), closes [#38231](https://github.com/angular/angular/issues/38231)
* **core:** do not error when `ngDevMode` is undeclared ([#39415](https://github.com/angular/angular/issues/39415)) ([cc32932](https://github.com/angular/angular/commit/cc32932))
* **core:** Store ICU state in `LView` rather than in `TView` ([#39233](https://github.com/angular/angular/issues/39233)) ([0992b67](https://github.com/angular/angular/commit/0992b67)), closes [#37021](https://github.com/angular/angular/issues/37021) [#38144](https://github.com/angular/angular/issues/38144) [#38073](https://github.com/angular/angular/issues/38073)
* **core:** update expected size for cli-hello-world-ivy-i18n integration test ([#39402](https://github.com/angular/angular/issues/39402)) ([084b082](https://github.com/angular/angular/commit/084b082))
* **localize:** render placeholder types in extracted XLIFF files ([#39398](https://github.com/angular/angular/issues/39398)) ([32163ef](https://github.com/angular/angular/commit/32163ef)), closes [#38791](https://github.com/angular/angular/issues/38791)
* **localize:** serialize all the message locations to XLIFF ([#39411](https://github.com/angular/angular/issues/39411)) ([f5710c6](https://github.com/angular/angular/commit/f5710c6)), closes [#39330](https://github.com/angular/angular/issues/39330)
* **ngcc:** capture UMD/CommonJS inner class implementation node correctly ([#39346](https://github.com/angular/angular/issues/39346)) ([fc2e3cc](https://github.com/angular/angular/commit/fc2e3cc))
<a name="11.0.0-rc.0"></a>
# 11.0.0-rc.0 (2020-10-21)
### Bug Fixes
* **common:** update locales using new CLDR data ([#39343](https://github.com/angular/angular/issues/39343)) ([3738233](https://github.com/angular/angular/commit/3738233))
* **compiler:** promote constants in templates to Trusted Types ([#39211](https://github.com/angular/angular/issues/39211)) ([6e18d2d](https://github.com/angular/angular/commit/6e18d2d))
* **core:** guard reading of global `ngDevMode` for undefined. ([#36055](https://github.com/angular/angular/issues/36055)) ([f541e5f](https://github.com/angular/angular/commit/f541e5f))
* **language-service:** [Ivy] create compiler only when program changes ([#39231](https://github.com/angular/angular/issues/39231)) ([8f1317f](https://github.com/angular/angular/commit/8f1317f))
* **ngcc:** ensure that "inline exports" can be interpreted correctly ([#39267](https://github.com/angular/angular/issues/39267)) ([822b838](https://github.com/angular/angular/commit/822b838))
* **platform-server:** Resolve absolute URL from baseUrl ([#39334](https://github.com/angular/angular/issues/39334)) ([b4e8399](https://github.com/angular/angular/commit/b4e8399))
* **router:** incorrect signature for createUrlTree ([#39347](https://github.com/angular/angular/issues/39347)) ([161b278](https://github.com/angular/angular/commit/161b278))
### Code Refactoring
* **compiler:** remove support for TypeScript 3.9 ([#39313](https://github.com/angular/angular/issues/39313)) ([736e064](https://github.com/angular/angular/commit/736e064))
### 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.
* **compiler:** TypeScript 3.9 is no longer supported, please upgrade to TypeScript 4.0.
<a name="11.0.0-next.6"></a>
# 11.0.0-next.6 (2020-10-14)
@@ -102,14 +174,10 @@ to resolve the type-check errors.
* **forms:** Directives in the `@angular/forms` package used to have `any[]` as a type of `validators` and
`asyncValidators` arguments in constructors. Now these arguments are properly typed, so if your
code relies on directive constructor types it may require some updates to improve type safety.
* **forms:** Type of AbstractFormControl.parent now includes null
`null` is now included in the types of .parent. If you don't already have a check for this case,
the TypeScript compiler might compain. A v11 migration exists which adds the not-null assertion
operator where necessary.
In an unlikely case your code was testing the parnet against undefined with sitrct equality,
you'll need to change this to `=== null` instead, since the parent is not explicily initialized
* **forms:** Type of AbstractFormControl.parent now includes null. `null` is now included in the types of .parent. If you don't already have a check for this case,
the TypeScript compiler might complain. A v11 migration exists which adds the non-null assertion
operator where necessary. In an unlikely case your code was testing the parent against undefined with strict equality,
you'll need to change this to `=== null` instead, since the parent is now explicitly initialized
with `null` instead of being left `undefined`.
@@ -312,9 +380,7 @@ then your code will not longer compile. If you need to mutate the array, you
should now take a copy (e.g. by calling `slice()`) and mutate the copy.
* **common:** When passing a date-time formatted string to the `DatePipe` in a format that contains
fractions of a millisecond, the milliseconds will now always be rounded down rather than
to the nearest millisecond.
Most applications will not be affected by this change. If this is not the desired behaviour
to the nearest millisecond. Most applications will not be affected by this change. If this is not the desired behaviour
then consider pre-processing the string to round the millisecond part before passing
it to the `DatePipe`.
+3 -3
View File
@@ -209,7 +209,7 @@ To ensure consistency throughout the source code, keep these rules in mind as yo
## <a name="commit"></a> Commit Message Format
*This specification is inspired and supersedes the [AngularJS commit message format][commit-message-format].*
*This specification is inspired by and supersedes the [AngularJS commit message format][commit-message-format].*
We have very precise rules over how our Git commit messages must be formatted.
This format leads to **easier to read commit history**.
@@ -248,7 +248,7 @@ Any line of the commit message cannot be longer than 100 characters.
│ 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.
@@ -309,7 +309,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
+135 -11
View File
@@ -1,27 +1,151 @@
[![CircleCI](https://circleci.com/gh/angular/angular/tree/master.svg?style=shield)](https://circleci.com/gh/angular/workflows/angular/tree/master)
[![Discord](https://img.shields.io/discord/463752820026376202.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/angular)
[![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"
+2 -2
View File
@@ -81,14 +81,14 @@ 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.5.1/configs/ubuntu16_04_clang/versions.bzl
# https://github.com/bazelbuild/bazel-toolchains/blob/3.6.0/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
# the same Clang and JDK installed. Clang is needed because of the dependency on
# @com_google_protobuf. Java is needed for the Bazel's test executor Java tool.
digest = "sha256:f743114235a43355bf8324e2ba0fa6a597236fe06f7bc99aaa9ac703631c306b",
digest = "sha256:dddaaddbe07a61c2517f9b08c4977fc23c4968fcb6c0b8b5971e955d2de7a961",
env = clang_env(),
registry = "marketplace.gcr.io",
# We can't use the default "ubuntu16_04" RBE image provided by the autoconfig because we need
+2 -1
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.
@@ -6,4 +6,4 @@ TODO (gkalpak): Add docs. Mention:
Relevant files: `aio/aio-builds-setup/scripts/test.sh`
- Deploying from CI.
Relevant files: `.circleci/config.yml`, `scripts/ci/deploy.sh`, `aio/scripts/build-artifacts.sh`,
`aio/scripts/deploy-to-firebase.sh`
`aio/scripts/deploy-to-firebase.js`
+12
View File
@@ -81,6 +81,15 @@
],
"serviceWorker": true
},
"rc": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.rc.ts"
}
],
"serviceWorker": true
},
"stable": {
"fileReplacements": [
{
@@ -116,6 +125,9 @@
"next": {
"browserTarget": "site:build:next"
},
"rc": {
"browserTarget": "site:build:rc"
},
"stable": {
"browserTarget": "site:build:stable"
},
+2
View File
@@ -32,6 +32,8 @@
**/karma-test-shim.js
**/browser-test-shim.js
**/node_modules
**/yarn.lock
**/package-lock.json
# built files
*.map
@@ -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');
});
@@ -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. -->
@@ -7,4 +7,8 @@ import { Component } from '@angular/core';
})
export class AppComponent {
progress = 0;
setProgress($event: Event) {
this.progress = +($event.target as HTMLInputElement).value;
}
}
@@ -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 -->
@@ -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';
}
@@ -11,6 +11,9 @@ export class CompWithHostBindingComponent {
@HostBinding('style.color')
color = 'green';
// #docregion hostbinding
@HostBinding('style.width')
width = '200px';
// #enddocregion hostbinding
}
@@ -1,6 +1,6 @@
/* tslint:disable:forin */
// #docregion
import { Component, Input, OnChanges, SimpleChange } from '@angular/core';
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
@Component({
selector: 'app-version-child',
@@ -17,7 +17,7 @@ export class VersionChildComponent implements OnChanges {
@Input() minor: number;
changeLog: string[] = [];
ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
ngOnChanges(changes: SimpleChanges) {
const log: string[] = [];
for (const propName in changes) {
const changedProp = changes[propName];
@@ -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!');
});
});
@@ -0,0 +1 @@
<app-component-overview></app-component-overview>
@@ -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!');
});
});
@@ -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';
}
@@ -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 { }
@@ -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 {
}
@@ -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 {
}
@@ -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 {
}
@@ -0,0 +1 @@
<p>component-overview works!</p>
@@ -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();
});
});
@@ -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
@@ -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>
@@ -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));
@@ -0,0 +1,8 @@
{
"description": "Component Overview",
"files":[
"!**/*.d.ts",
"!**/*.js"
],
"tags":["overview", "component"]
}
@@ -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
@@ -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: ', []],
]);
});
@@ -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;
@@ -0,0 +1,14 @@
h3 {
font-weight: 700;
}
pre, .wrapper {
background-color: rgb(240, 250, 250);
padding: 1rem;
border: 1px solid #444;
}
input {
margin: .5rem;
padding: .5rem;
}
@@ -39,8 +39,7 @@
<h2>Reference variables, forms, and NgForm</h2>
<!-- #docregion ngForm -->
<form #itemForm="ngForm" (ngSubmit)="onSubmit(itemForm)">
<label for="name"
>Name <input class="form-control" name="name" ngModel required />
<label for="name">Name <input class="form-control" name="name" ngModel required />
</label>
<button type="submit">Submit</button>
</form>
@@ -53,3 +52,60 @@
<p>JSON: {{ itemForm.form.value | json }}</p>
<hr />
<h2>Template Reference Variable Scope</h2>
<p>This section demonstrates in which situations you can access local template reference variables (<code>#ref</code>).</p>
<h3>Accessing in a child template</h3>
<!-- Accessing a template reference variable from an inner template
works as the context is inherited. Try changing the text in the
input to see how it is immediately reflected through the template
reference variable. -->
<div class="example">
<!-- #docregion template-ref-vars-scope1 -->
<input #ref1 type="text" [(ngModel)]="firstExample" />
<span *ngIf="true">Value: {{ ref1.value }}</span>
<!-- #enddocregion template-ref-vars-scope1 -->
</div>
<!-- In this case there's a "hidden" ng-template around the
span and the definition of the variable is outside of it. Thus, you access a template variable from a parent template (which is logical as the context is inherited). -->
<p>Here's the desugared syntax:</p>
<pre><code [innerText]="desugared1"></code></pre>
<h3>Accessing from outside parent template. (Doesn't work.)</h3>
<!-- Accessing the template reference variable from outside the parent template does
not work. The value to the right is empty and changing the
value of the input will have no effect. -->
<div class="example">
<!-- #docregion template-ref-vars-scope2 -->
<input *ngIf="true" #ref2 type="text" [(ngModel)]="secondExample" />
<!-- <span>Value: {{ ref2?.value }}</span> -->
<!-- uncomment the above and the app breaks -->
<!-- #enddocregion template-ref-vars-scope2 -->
</div>
<p>Here's the desugared syntax:</p>
<pre><code [innerText]="desugared2"></code></pre>
<h3>*ngFor and template reference variable scope</h3>
<!-- The template is instantiated twice because *ngFor iterates
over the two items in the array, so it's impossible to define what ref2 is referencing. -->
<pre><code [innerText]="ngForExample"></code></pre>
<h3>Accessing a on an <code>ng-template</code></h3>
See the console output to see that when you declare the variable on an <code>ng-template</code>, the variable refers to a <code>TemplateRef</code> instance, which represents the template.
<!-- #docregion template-ref -->
<ng-template #ref3></ng-template>
<button (click)="log(ref3)">Log type of #ref</button>
<!-- #enddocregion template-ref -->
@@ -8,7 +8,38 @@ import { NgForm } from '@angular/forms';
styleUrls: ['./app.component.css']
})
export class AppComponent {
@ViewChild('itemForm') form: NgForm;
public firstExample = 'Hello, World!';
public secondExample = 'Hello, World!';
public ref2 = '';
public desugared1 = `
<input #ref1 type="text" [(ngModel)]="firstExample" /><!-- A new template! -->
<ng-template [ngIf]="true">
<!-- … and it works -->
<span>Value: {{ ref1.value }}</span>
</ng-template>`
;
public desugared2 = `<ng-template [ngIf]="true">
<!-- The reference, ref2, is defined within a template -->
<input #ref2 type="text" [(ngModel)]="secondExample" />
</ng-template>
<!-- Attempting to access ref2 from outside the above template doesn't work. -->
<span>Value: {{ ref2?.value }}</span>`;
public ngForExample = `<ng-container *ngFor="let i of [1,2]">
<input #ref type="text" [value]="i" />
</ng-container>
<!-- The template is instantiated twice because *ngFor iterates
over the two items in the array, so it's impossible to define what ref2 is referencing.-->
{{ ref.value }}`;
@ViewChild('itemForm', { static: false }) form: NgForm;
get submitMessage() { return this._submitMessage; }
private _submitMessage = ''; // tslint:disable-line: variable-name
@@ -25,4 +56,7 @@ export class AppComponent {
console.warn(`Faxing ${value} ...`);
}
log(ref3: any) {
console.warn(ref3.constructor);
}
}
@@ -4,7 +4,7 @@ import { Component, ContentChildren, Directive, EventEmitter,
HostBinding, HostListener,
OnInit, OnChanges, OnDestroy,
Pipe, PipeTransform,
SimpleChange } from '@angular/core';
SimpleChanges } from '@angular/core';
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';
@@ -309,7 +309,7 @@ export class MyIfChildComponent implements OnInit, OnChanges, OnDestroy {
this.changeLog.push('ngOnDestroy called');
}
ngOnChanges(changes: {[propertyName: string]: SimpleChange}) {
ngOnChanges(changes: SimpleChanges) {
for (const propName in changes) {
this.ngOnChangesCounter += 1;
const prop = changes[propName];
+1 -1
View File
@@ -70,7 +70,7 @@ When authoring Angular components, you should re-use these native elements direc
For example, instead of creating a custom element for a new variety of button, you can create a component that uses an attribute selector with a native `<button>` element.
This most commonly applies to `<button>` and `<a>`, but can be used with many other types of element.
You can see examples of this pattern in Angular Material: [`MatButton`](https://github.com/angular/components/blob/master/src/material/button/button.ts#L66-L68), [`MatTabNav`](https://github.com/angular/components/blob/master/src/material/tabs/tab-nav-bar/tab-nav-bar.ts#L67), [`MatTable`](https://github.com/angular/components/blob/master/src/material/table/table.ts#L17).
You can see examples of this pattern in Angular Material: [`MatButton`](https://github.com/angular/components/blob/50d3f29b6dc717b512dbd0234ce76f4ab7e9762a/src/material/button/button.ts#L67-L69), [`MatTabNav`](https://github.com/angular/components/blob/50d3f29b6dc717b512dbd0234ce76f4ab7e9762a/src/material/tabs/tab-nav-bar/tab-nav-bar.ts#L139), [`MatTable`](https://github.com/angular/components/blob/50d3f29b6dc717b512dbd0234ce76f4ab7e9762a/src/material/table/table.ts#L22).
### Using containers for native elements
+3 -3
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
+2 -5
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.
+1 -1
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.
+93 -146
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, we bind 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.
+1 -1
View File
@@ -80,7 +80,7 @@ Angular supports most recent browsers. This includes the following specific vers
</td>
<td>
X (10.0), Pie (9.0), Oreo (8.0), Nougat (7.0)
Q (10.0), Pie (9.0), Oreo (8.0), Nougat (7.0)
</td>
</tr>
+2 -2
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>
+182
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.html`
* 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 your 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-hello-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 you 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 architectural 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).
@@ -196,7 +196,7 @@ which *is* what parent means.
2. Angular throws a cyclic dependency error if you omit the `@SkipSelf` decorator.
`Cannot instantiate cyclic dependency! (BethComponent -> Parent -> BethComponent)`
`NG0200: Circular dependency in DI detected for BethComponent. Dependency path: BethComponent -> Parent -> BethComponent`
Here's *Alice*, *Barry*, and family in action.
-312
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>
@@ -0,0 +1,31 @@
# How event binding works
In an event binding, Angular configures an event handler for the target event.
You can use event binding with your own custom events.
When the component or directive raises the event, the handler executes the template statement.
The template statement performs an action in response to the event.
## Handling events
A common way to handle events is to pass the event object, `$event`, to the method handling the event.
The `$event` object often contains information the method needs, such as a user's name or an image URL.
The target event determines the shape of the `$event` object.
If the target event is a native DOM element event, then `$event` is a [DOM event object](https://developer.mozilla.org/en-US/docs/Web/Events), with properties such as `target` and `target.value`.
In the following example the code sets the `<input>` `value` property by binding to the `name` property.
<code-example path="event-binding/src/app/app.component.html" region="event-binding-3" header="src/app/app.component.html"></code-example>
With this example, the following actions occur:
1. The code binds to the `input` event of the `<input>` element, which allows the code to listen for changes.
1. When the user makes changes, the component raises the `input` event.
1. The binding executes the statement within a context that includes the DOM event object, `$event`.
1. Angular retrieves the changed text by following the path `$event.target.value` and updates the `name` property.
If the event belongs to a directive or component, `$event` has the shape that the directive or component produces.
+37 -79
View File
@@ -1,7 +1,6 @@
# Event binding `(event)`
# Event binding
Event binding allows you to listen for certain events such as
keystrokes, mouse movements, clicks, and touches.
Event binding allows you to listen for and respond to user actions such as keystrokes, mouse movements, clicks, and touches.
<div class="alert is-helpful">
@@ -9,100 +8,59 @@ See the <live-example></live-example> for a working example containing the code
</div>
Angular event binding syntax consists of a **target event** name
within parentheses on the left of an equal sign, and a quoted
template statement on the right.
The following event binding listens for the button's click events, calling
the component's `onSave()` method whenever a click occurs:
## Binding to events
To bind to an event you use the Angular event binding syntax.
This syntax consists of a target event name within parentheses to the left of an equal sign, and a quoted template statement to the right.
In the following example, the target event name is `click` and the template statement is `onSave()`.
<code-example language="html" header="Event binding syntax">
&lt;button (click)="onSave()"&gt;Save&lt;button&gt;
</code-example>
The event binding listens for the button's click events and calls the component's `onSave()` method whenever a click occurs.
<div class="lightbox">
<img src='generated/images/guide/template-syntax/syntax-diagram.svg' alt="Syntax diagram">
</div>
## Target event
As above, the target is the button's click event.
<code-example path="event-binding/src/app/app.component.html" region="event-binding-1" header="src/app/app.component.html"></code-example>
Alternatively, use the `on-` prefix, known as the canonical form:
<code-example path="event-binding/src/app/app.component.html" region="event-binding-2" header="src/app/app.component.html"></code-example>
Element events may be the more common targets, but Angular looks first to see if the name matches an event property
of a known directive, as it does in the following example:
<code-example path="event-binding/src/app/app.component.html" region="custom-directive" header="src/app/app.component.html"></code-example>
If the name fails to match an element event or an output property of a known directive,
Angular reports an “unknown directive” error.
## *$event* and event handling statements
In an event binding, Angular sets up an event handler for the target event.
When the event is raised, the handler executes the template statement.
The template statement typically involves a receiver, which performs an action
in response to the event, such as storing a value from the HTML control
into a model.
The binding conveys information about the event. This information can include data values such as an event object, string, or number named `$event`.
The target event determines the shape of the `$event` object.
If the target event is a native DOM element event, then `$event` is a
[DOM event object](https://developer.mozilla.org/en-US/docs/Web/Events),
with properties such as `target` and `target.value`.
Consider this example:
<code-example path="event-binding/src/app/app.component.html" region="event-binding-3" header="src/app/app.component.html"></code-example>
This code sets the `<input>` `value` property by binding to the `name` property.
To listen for changes to the value, the code binds to the `input`
event of the `<input>` element.
When the user makes changes, the `input` event is raised, and the binding executes
the statement within a context that includes the DOM event object, `$event`.
To update the `name` property, the changed text is retrieved by following the path `$event.target.value`.
If the event belongs to a directive&mdash;recall that components
are directives&mdash;`$event` has whatever shape the directive produces.
## Custom events with `EventEmitter`
Directives typically raise custom events with an Angular [EventEmitter](api/core/EventEmitter).
The directive creates an `EventEmitter` and exposes it as a property.
The directive calls `EventEmitter.emit(payload)` to fire an event, passing in a message payload, which can be anything.
Parent directives listen for the event by binding to this property and accessing the payload through the `$event` object.
[Directives](guide/built-in-directives) typically raise custom events with an Angular [EventEmitter](api/core/EventEmitter) as follows.
1. The directive creates an `EventEmitter` and exposes it as a property.
1. The directive then calls `EventEmitter.emit(data)` to emit an event, passing in message data, which can be anything.
1. Parent directives listen for the event by binding to this property and accessing the data through the `$event` object.
Consider an `ItemDetailComponent` that presents item information and responds to user actions.
Although the `ItemDetailComponent` has a delete button, it doesn't know how to delete the hero. It can only raise an event reporting the user's delete request.
Although the `ItemDetailComponent` has a delete button, it doesn't contain the functionality to delete the hero.
It can only raise an event reporting the user's delete request.
Here are the pertinent excerpts from that `ItemDetailComponent`:
<code-example path="event-binding/src/app/item-detail/item-detail.component.html" header="src/app/item-detail/item-detail.component.html (template)" region="line-through"></code-example>
The component defines a `deleteRequest` property that returns an `EventEmitter`.
When the user clicks **Delete**, the component invokes the `delete()` method, telling the `EventEmitter` to emit an `Item` object.
<code-example path="event-binding/src/app/item-detail/item-detail.component.ts" header="src/app/item-detail/item-detail.component.ts (deleteRequest)" region="deleteRequest"></code-example>
The component defines a `deleteRequest` property that returns an `EventEmitter`.
When the user clicks *delete*, the component invokes the `delete()` method,
telling the `EventEmitter` to emit an `Item` object.
Now imagine a hosting parent component that binds to the `deleteRequest` event
of the `ItemDetailComponent`.
The hosting parent component binds to the `deleteRequest` event of the `ItemDetailComponent` as follows.
<code-example path="event-binding/src/app/app.component.html" header="src/app/app.component.html (event-binding-to-component)" region="event-binding-to-component"></code-example>
When the `deleteRequest` event fires, Angular calls the parent component's
`deleteItem()` method, passing the *item-to-delete* (emitted by `ItemDetail`)
in the `$event` variable.
When the `deleteRequest` event fires, Angular calls the parent component's `deleteItem()` method with the item.
## Template statements have side effects
### Determining an event target
Though [template expressions](guide/interpolation#template-expressions) shouldn't have [side effects](guide/property-binding#avoid-side-effects), template
statements usually do. The `deleteItem()` method does have
a side effect: it deletes an item.
To determine an event target, Angular checks if the name of the target event matches an event property of a known directive.
In the following example, Angular checks to see if `myClick` is an event on the custom `ClickDirective`.
Deleting an item updates the model, and depending on your code, triggers
other changes including queries and saving to a remote server.
These changes propagate through the system and ultimately display in this and other views.
<code-example path="event-binding/src/app/app.component.html" region="custom-directive" header="src/app/app.component.html"></code-example>
If the target event name, `myClick` fails to match an element event or an output property of `ClickDirective`, Angular reports an "unknown directive" error.
<hr />
## What's next
For more information on how event binding works, see [How event binding works](guide/event-binding-concepts).
+11 -17
View File
@@ -327,7 +327,7 @@ You can also nest different clauses together, such as the `plural` and `select`
## Work with translation files
After preparing a template for translation, use the Angular CLI `xi18n` command to extract the marked text in the template into a _source language_ file.
After preparing a template for translation, use the Angular CLI `extract-i18n` command to extract the marked text in the template into a _source language_ file.
The marked text includes text marked with `i18n` and attributes marked with `i18n-`*attribute* as described in the previous section.
Follow these steps:
@@ -344,12 +344,12 @@ You can optionally change the location, format, and name.
To extract the source language file, open a terminal window, change to the root directory of your app project, and run the following CLI command:
<code-example language="sh" class="code-shell">
ng xi18n
ng extract-i18n
</code-example>
The `xi18n` command creates a source language file named `messages.xlf` in your project's root directory using the [XML Localization Interchange File Format (XLIFF, version 1.2)](https://en.wikipedia.org/wiki/XLIFF "Wikipedia page about XLIFF").
The `extract-i18n` command creates a source language file named `messages.xlf` in your project's root directory using the [XML Localization Interchange File Format (XLIFF, version 1.2)](https://en.wikipedia.org/wiki/XLIFF "Wikipedia page about XLIFF").
Use the following `xi18n` command options to change the source language file location, format, and file name:
Use the following `extract-i18n` command options to change the source language file location, format, and file name:
* `--output-path`: Change the location.
* `--format`: Change the format.
@@ -358,25 +358,19 @@ Use the following `xi18n` command options to change the source language file loc
Note: The `--i18n-locale` option is deprecated.
Angular 9 uses the source locale configured in your app's [workspace configuration](guide/workspace-config "Angular workspace configuration") file (`angular.json`).
<div class="alert is-helpful">
The ng xi18n extraction mechanism uses the ViewEngine compiler, which is not able to cope with some code syntax that the Ivy compiler can handle. A fix for this issue is currently under development. To follow or contribute to this fix see [PR 32912](https://github.com/angular/angular/pull/32912).
</div>
#### Change the source language file location
To create a file in the `src/locale` directory, specify the output path as an option, as shown in the following example:
<code-example language="sh" class="code-shell">
ng xi18n --output-path src/locale
ng extract-i18n --output-path src/locale
</code-example>
{@a other-formats}
#### Change the source language file format
The `xi18n` command can read and write files in three translation formats:
The `extract-i18n` command can read and write files in three translation formats:
* XLIFF 1.2 (default)
* XLIFF 2
@@ -385,9 +379,9 @@ The `xi18n` command can read and write files in three translation formats:
Specify the translation format explicitly with the `--format` command option, as shown in the following examples:
<code-example language="sh" class="code-shell">
ng xi18n --format=xlf
ng xi18n --format=xlf2
ng xi18n --format=xmb
ng extract-i18n --format=xlf
ng extract-i18n --format=xlf2
ng extract-i18n --format=xmb
</code-example>
<div class="alert is-helpful">
@@ -403,14 +397,14 @@ To change the name of the source language file generated by the extraction tool,
the `--outFile` command option:
<code-example language="sh" class="code-shell">
ng xi18n --out-file source.xlf
ng extract-i18n --out-file source.xlf
</code-example>
{@a localization-folder}
### Create a translation file for each language
The `ng xi18n` command (with no options) generates a source language file named `messages.xlf` in the project `src` folder.
The `ng extract-i18n` command (with no options) generates a source language file named `messages.xlf` in the project `src` folder.
Create *translation* files for each language by copying the source language file.
To avoid confusion with multiple translations, you should organize the language translation files by locale in a dedicated `locale` folder under `src/`.
Use a filename extension that matches the associated locale, such as `messages.fr.xlf`.
@@ -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`.
+136 -161
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)
+1 -1
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.
+1 -1
View File
@@ -8,7 +8,7 @@ Additionally, applications that use these stricter settings are easier to static
Specifically, the `strict` flag does the following:
* Enables [`strict` mode in TypeScript](https://www.staging-typescript.org/tsconfig#strict), as well as other strictness flags recommended by the TypeScript team. Specifically, `forceConsistentCasingInFileNames`, `noImplicitReturns`, `noFallthroughCasesInSwitch`.
* Turns on strict Angular compiler flags [`strictTemplates`](guide/angular-compiler-options#stricttemplates), [`strictInjectionParameters`](guide/angular-compiler-options#strictinjectionparameters) and [`strictTemplates`](guide/angular-compiler-options#stricttemplates).
* Turns on strict Angular compiler flags [`strictTemplates`](guide/angular-compiler-options#stricttemplates), [`strictInjectionParameters`](guide/angular-compiler-options#strictinjectionparameters) and [`strictInputAccessModifiers`](guide/template-typecheck#troubleshooting-template-errors).
* [Bundle size budgets](guide/build#configuring-size-budgets) have been reduced by ~75%.
You can apply these settings at the workspace and project level.
+133
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>
+114 -29
View File
@@ -1,7 +1,15 @@
# Template reference variables (`#var`)
# Template variables
A **template reference variable** is often a reference to a DOM element within a template.
It can also refer to a directive (which contains a component), an element, [TemplateRef](api/core/TemplateRef), or a <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components" title="MDN: Web Components">web component</a>.
Template variables help you use data from one part of a template in another part of the template.
With template variables, you can perform tasks such as respond to user input or finely tune your application's forms.
A template variable can refer to the following:
* a DOM element within a template
* a directive
* an element
* [TemplateRef](api/core/TemplateRef)
* a <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components" title="MDN: Web Components">web component</a>
<div class="alert is-helpful">
@@ -9,61 +17,138 @@ See the <live-example></live-example> for a working example containing the code
</div>
Use the hash symbol (#) to declare a reference variable.
The following reference variable, `#phone`, declares a `phone` variable on an `<input>` element.
## Syntax
In the template, you use the hash symbol, `#`, to declare a template variable.
The following template variable, `#phone`, declares a `phone` variable on an `<input>` element.
<code-example path="template-reference-variables/src/app/app.component.html" region="ref-var" header="src/app/app.component.html"></code-example>
You can refer to a template reference variable anywhere in the component's template.
You can refer to a template variable anywhere in the component's template.
Here, a `<button>` further down the template refers to the `phone` variable.
<code-example path="template-reference-variables/src/app/app.component.html" region="ref-phone" header="src/app/app.component.html"></code-example>
Angular assigns each template reference variable a value based on where you declare the variable:
## How Angular assigns values to template variables
Angular assigns a template variable a value based on where you declare the variable:
* If you declare the variable on a component, the variable refers to the component instance.
* If you declare the variable on a standard HTML tag, the variable refers to the element.
* If you declare the variable on an `<ng-template>` element, the variable refers to a `TemplateRef` instance, which represents the template.
For more information on `<ng-template>`, see the [ng-template](guide/structural-directives#the-ng-template) section of [Structural directives](guide/structural-directives).
* If the variable specifies a name on the right-hand side, such as `#var="ngModel"`, the variable refers to the directive or component on the element with a matching `exportAs` name.
<!-- What does the second half of this mean?^^ Can we explain this more fully? Could I see a working example? -kw -->
<h3 class="no-toc">How a reference variable gets its value</h3>
### Using `NgForm` with template variables
In most cases, Angular sets the reference variable's value to the element on which it is declared.
In most cases, Angular sets the template variable's value to the element on which it occurs.
In the previous example, `phone` refers to the phone number `<input>`.
The button's click handler passes the `<input>` value to the component's `callPhone()` method.
The `NgForm` directive can change that behavior and set the value to something else. In the following example, the template reference variable, `itemForm`, appears three times separated
by HTML.
The `NgForm` directive demonstrates getting a reference to a different value by reference a directive's `exportAs` name.
In the following example, the template variable, `itemForm`, appears three times separated by HTML.
<code-example path="template-reference-variables/src/app/app.component.html" region="ngForm" header="src/app/hero-form.component.html"></code-example>
The reference value of `itemForm`, without the `ngForm` attribute value, would be
the [HTMLFormElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement).
There is, however, a difference between a `Component` and a `Directive` in that a `Component`
will be referenced without specifying the attribute value, and a `Directive` will not
change the implicit reference (that is, the element).
Without the `ngForm` attribute value, the reference value of `itemForm` would be
the [HTMLFormElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement), `<form>`.
There is, however, a difference between a `Component` and a `Directive` in that Angular references a `Component` without specifying the attribute value, and a `Directive` does not change the implicit reference, or the element.
<!-- What is the train of thought from talking about a form element to the difference between a component and a directive? Why is the component directive conversation relevant here? -kw -->
With `NgForm`, `itemForm` is a reference to the [NgForm](api/forms/NgForm "API: NgForm") directive with the ability to track the value and validity of every control in the form.
Unlike the native `<form>` element, the `NgForm` directive has a `form` property.
The `NgForm` `form` property allows you to disable the submit button if the `itemForm.form.valid` is invalid.
## Template variable scope
However, with `NgForm`, `itemForm` is a reference to the [NgForm](api/forms/NgForm "API: NgForm")
directive with the ability to track the value and validity of every control in the form.
You can refer to a template variable anywhere within its surrounding template.
[Structural directives](guide/built-in-directives), such as `*ngIf` and `*ngFor`, or `<ng-template>` act as a template boundary.
You cannot access template variables outside of these boundaries.
The native `<form>` element doesn't have a `form` property, but the `NgForm` directive does, which allows disabling the submit button
if the `itemForm.form.valid` is invalid and passing the entire form control tree
to the parent component's `onSubmit()` method.
<div class="alert is-helpful">
<h3 class="no-toc">Template reference variable considerations</h3>
Define a variable only once in the template so the runtime value remains predictable.
A template _reference_ variable (`#phone`) is not the same as a template _input_ variable (`let phone`) such as in an [`*ngFor`](guide/built-in-directives#template-input-variable).
See [_Structural directives_](guide/structural-directives#template-input-variable) for more information.
</div>
The scope of a reference variable is the entire template. So, don't define the same variable name more than once in the same template as the runtime value will be unpredictable.
### Accessing in a nested template
### Alternative syntax
An inner template can access template variables that the outer template defines.
You can use the `ref-` prefix alternative to `#`.
This example declares the `fax` variable as `ref-fax` instead of `#fax`.
In the following example, changing the text in the `<input>` changes the value in the `<span>` because Angular immediately updates changes through the template variable, `ref1`.
<code-example path="template-reference-variables/src/app/app.component.html" region="template-ref-vars-scope1" header="src/app/app.component.html"></code-example>
<code-example path="template-reference-variables/src/app/app.component.html" region="ref-fax" header="src/app/app.component.html"></code-example>
In this case, there is an implied `<ng-template>` around the `<span>` and the definition of the variable is outside of it.
Accessing a template variable from the parent template works because the child template inherits the context from the parent template.
Rewriting the above code in a more verbose form explicitly shows the `<ng-template>`.
```html
<input #ref1 type="text" [(ngModel)]="firstExample" />
<!-- New template -->
<ng-template [ngIf]="true">
<!-- Since the context is inherited, the value is available to the new template -->
<span>Value: {{ ref1.value }}</span>
</ng-template>
```
However, accessing a template variable from outside the parent template doesn't work.
```html
<input *ngIf="true" #ref2 type="text" [(ngModel)]="secondExample" />
<span>Value: {{ ref2?.value }}</span> <!-- doesn't work -->
```
The verbose form shows that `ref2` is outside the parent template.
```
<ng-template [ngIf]="true">
<!-- The reference is defined within a template -->
<input #ref2 type="text" [(ngModel)]="secondExample" />
</ng-template>
<!-- ref2 accessed from outside that template doesn't work -->
<span>Value: {{ ref2?.value }}</span>
```
Consider the following example that uses `*ngFor`.
```
<ng-container *ngFor="let i of [1,2]">
<input #ref type="text" [value]="i" />
</ng-container>
{{ ref.value }}
```
Here, `ref.value` doesn't work.
The structural directive, `*ngFor` instantiates the template twice because `*ngFor` iterates over the two items in the array.
It is impossible to define what the `ref.value` reference signifies.
With structural directives, such as `*ngFor` or `*ngIf`, there is no way for Angular to know if a template is ever instantiated.
As a result, Angular isn't able to access the value and returns an error.
### Accessing a template variable within `<ng-template>`
When you declare the variable on an `<ng-template>`, the variable refers to a `TemplateRef` instance, which represents the template.
<code-example path="template-reference-variables/src/app/app.component.html" region="template-ref" header="src/app/app.component.html"></code-example>
In this example, clicking the button calls the `log()` function, which outputs the value of `#ref3` to the console.
Because the `#ref` variable is on an `<ng-template>`, the value is `TemplateRef`.
The following is the expanded browser console output of the `TemplateRef()` function with the name of `TemplateRef`.
<code-example language="sh">
&#9660; ƒ TemplateRef()
name: "TemplateRef"
__proto__: Function
</code-example>
+1 -1
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.
+1 -1
View File
@@ -238,7 +238,7 @@ We'll be using [Headless Chrome](https://developers.google.com/web/updates/2017/
* In the Karma configuration file, `karma.conf.js`, add a custom launcher called ChromeHeadlessCI below browsers:
```
browsers: ['Chrome'],
browsers: ['ChromeHeadlessCI'],
customLaunchers: {
ChromeHeadlessCI: {
base: 'ChromeHeadless',
+14 -2
View File
@@ -1,5 +1,17 @@
# User input
<div class="callout is-critical">
<header>Marked for archiving</header>
To ensure that you have the best experience possible, this topic is marked for archiving until we determine
that it clearly conveys the most accurate information possible.
In the meantime, this topic might be helpful: [Event binding](guide/event-binding).
If you think this content should not be archived, please file a [GitHub issue](https://github.com/angular/angular/issues/new?template=3-docs-bug.md).
</div>
User actions such as clicking a link, pushing a button, and entering
text raise DOM events.
This page explains how to bind those events to component event handlers using the Angular
@@ -234,8 +246,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.
+54 -16
View File
@@ -149,7 +149,7 @@ See [Build target](#build-target) below for more information.
* The `architect/lint` section configures defaults for options of the `ng lint` command, which performs code analysis on project source files. The default linting tool for Angular is [TSLint](https://palantir.github.io/tslint/).
* The `architect/extract-i18n` section configures defaults for options of the `ng-xi18n` tool used by the `ng xi18n` command, which extracts marked message strings from source code and outputs translation files.
* The `architect/extract-i18n` section configures defaults for options of the `ng extract-i18n` command, which extracts marked message strings from source code and outputs translation files.
* The `architect/server` section configures defaults for creating a Universal app with server-side rendering, using the `ng run <project>:server` command.
@@ -241,8 +241,16 @@ For example, the default asset paths can be represented in more detail using the
<code-example language="json">
"assets": [
{ "glob": "**/*", "input": "src/assets/", "output": "/assets/" },
{ "glob": "favicon.ico", "input": "src/", "output": "/" }
{
"glob": "**/*",
"input": "src/assets/",
"output": "/assets/"
},
{
"glob": "favicon.ico",
"input": "src/",
"output": "/"
}
]
</code-example>
@@ -253,7 +261,11 @@ For example, the following configuration copies assets from a node package:
<code-example language="json">
"assets": [
{ "glob": "**/*", "input": "./node_modules/some-package/images", "output": "/some-package/" },
{
"glob": "**/*",
"input": "./node_modules/some-package/images",
"output": "/some-package/"
}
]
</code-example>
@@ -265,7 +277,12 @@ The following example uses the `ignore` field to exclude certain files in the as
<code-example language="json">
"assets": [
{ "glob": "**/*", "input": "src/assets/", "ignore": ["**/*.svg"], "output": "/assets/" },
{
"glob": "**/*",
"input": "src/assets/",
"ignore": ["**/*.svg"],
"output": "/assets/"
}
]
</code-example>
@@ -284,10 +301,18 @@ For example, the following object values create and name a bundle that contains
<code-example language="json">
"styles": [
{ "input": "src/external-module/styles.scss", "inject": false, "bundleName": "external-module" }
{
"input": "src/external-module/styles.scss",
"inject": false,
"bundleName": "external-module"
}
],
"scripts": [
{ "input": "src/external-module/main.js", "inject": false, "bundleName": "external-module" }
{
"input": "src/external-module/main.js",
"inject": false,
"bundleName": "external-module"
}
]
</code-example>
@@ -341,25 +366,38 @@ See also [Using runtime-global libraries inside your app](guide/using-libraries#
### Optimization and source map configuration
The `optimization` and `sourceMap` command options are simple Boolean flags.
You can supply an object as a configuration value for either of these to provide more detailed instruction.
The `optimization` and `sourceMap` browser builder options can be either a Boolean or an Object for more fine-grained configuration.
In this section we will explain how to fine tune these options.
* The flag `--optimization="true"` applies to both scripts and styles. You can supply a value such as the following to apply optimization to one or the other:
* The `optimization` option applies to scripts, styles and fonts. You can supply a value such as the following to apply optimization to one or the other:
<code-example language="json">
"optimization": { "scripts": true, "styles": false }
"optimization": {
"scripts": true,
"styles": false,
"fonts": true
}
</code-example>
* The flag `--sourceMap="true"` outputs source maps for both scripts and styles.
You can configure the option to apply to one or the other.
You can also choose to output hidden source maps, or resolve vendor package source maps.
For example:
<div class="alert is-important">
Fonts optimization requires internet access.
When enabled, render blocking requests will be reduced by inlining external Google fonts and icons in the application's HTML index file.
</div>
* The `sourceMap` option applies for both scripts and styles. You can also choose to output hidden source maps, or resolve vendor package source maps:
<code-example language="json">
"sourceMap": { "scripts": true, "styles": false, "hidden": true, "vendor": true }
"sourceMap": {
"scripts": true,
"styles": false,
"hidden": true,
"vendor": true
}
</code-example>
+4 -4
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: 24 KiB

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

+33
View File
@@ -829,5 +829,38 @@
"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"
},
"caballerog": {
"name": "Carlos Caballero",
"picture": "carloscaballero.jpg",
"twitter": "Carlillo",
"website": "http://carloscaballero.io",
"bio": "Carlos Caballero is a computer science engineer and a PhD in Computer Science from the University of Málaga. He earned his masters in Software Engineering and Artificial Intelligence. He is a full-time teacher in vocational training. He has written several teaching books and more than a dozen research articles in the first international journals.",
"groups": ["GDE"]
}
}
+4 -4
View File
@@ -126,7 +126,7 @@
"akita": {
"desc": "Akita is a state management pattern, built on top of RxJS, which takes the idea of multiple data stores from Flux and the immutable updates from Redux, along with the concept of streaming data, to create the Observable Data Store model.",
"title": "Akita",
"url": "https://netbasal.gitbook.io/akita/"
"url": "https://datorama.github.io/akita/docs/angular/architecture"
},
"ab": {
"desc": "The official library for Firebase and Angular",
@@ -453,9 +453,9 @@
"order": 1,
"resources": {
"-KLIzGEp8Mh5W-FkiQnL": {
"desc": "Your quick, no-nonsense guide to building real-world apps with Angular",
"title": "Learning Angular - Second Edition",
"url": "https://www.packtpub.com/web-development/learning-angular-second-edition"
"desc": "A no-nonsense beginner's guide to building web applications with Angular and TypeScript",
"title": "Learning Angular - Third Edition",
"url": "https://www.packtpub.com/product/learning-angular-third-edition/9781839210662"
},
"3ab": {
"desc": "More than 15 books from O'Reilly about Angular",
+28 -23
View File
@@ -102,14 +102,9 @@
"tooltip": "Building dynamic views with data binding",
"children": [
{
"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/component-overview",
"title": "Overview",
"tooltip": "Overview of how to create Angular components."
},
{
"url": "guide/lifecycle-hooks",
@@ -167,6 +162,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",
@@ -192,11 +192,6 @@
"title": "Two-way binding",
"tooltip": "Introductory guide to sharing data between a class and a template."
},
{
"url": "guide/template-reference-variables",
"title": "Template reference variables",
"tooltip": "Introductory guide to referring to DOM elements within a template."
},
{
"url": "guide/template-expression-operators",
"title": "Template expression operators",
@@ -239,11 +234,6 @@
"title": "Angular Dependency Injection",
"tooltip": "Angular's dependency injection system creates and delivers dependent services to Angular-created classes."
},
{
"url": "guide/hierarchical-dependency-injection",
"title": "Hierarchical Injectors",
"tooltip": "An injector tree parallels the component tree and supports nested dependencies."
},
{
"url": "guide/dependency-injection-providers",
"title": "DI Providers",
@@ -417,6 +407,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.",
@@ -609,11 +604,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",
@@ -777,6 +767,16 @@
"url": "guide/architecture-next-steps",
"title": "Next Steps",
"tooltip": "Beyond the basics."
},
{
"url": "guide/event-binding-concepts",
"title": "How event binding works",
"tooltip": "About event binding."
},
{
"url": "guide/template-reference-variables",
"title": "Template variables",
"tooltip": "Introductory guide to referring to DOM elements within a template."
}
]
},
@@ -917,6 +917,11 @@
"tooltip": "How observables compare to promises and other message passing techniques."
}
]
},
{
"url": "guide/hierarchical-dependency-injection",
"title": "Hierarchical Injectors",
"tooltip": "An injector tree parallels the component tree and supports nested dependencies."
}
]
},
+2 -2
View File
@@ -101,10 +101,10 @@ This section walks you through using the cart service to add a product to the ca
<code-example header="src/app/product-details/product-details.component.html" path="getting-started/src/app/product-details/product-details.component.html">
</code-example>
<div class="alert is-helpful">
The line, `<h4>{{ product.price | currency }}</h4>` uses the `currency` pipe to transform `product.price` from a number to a currency string. A pipe is a way you can transform data in your HTML template. For more information about Angular pipes, see [Pipes](guide/pipes "Pipes").
The line, `<h4>{{ product.price | currency }}</h4>`, uses the `currency` pipe to transform `product.price` from a number to a currency string. A pipe is a way you can transform data in your HTML template. For more information about Angular pipes, see [Pipes](guide/pipes "Pipes").
</div>
+1
View File
@@ -63,6 +63,7 @@ One of the easiest ways to get your site live is to host it using Firebase.
1. Sign up for a firebase account on [Firebase](https://firebase.google.com/ "Firebase web site").
1. Create a new project, giving it any name you like.
1. Add the `@angular/fire` schematics that will handle your deployment using `ng add @angular/fire`.
1. Install [Firebase CLI](https://firebase.google.com/docs/cli) globally using `npm install -g firebase-tools`.
1. Connect your CLI to your Firebase account and initialize the connection to your project using `firebase login` and `firebase init`.
1. Follow the prompts to select the `Firebase` project you are creating for hosting.
- Select the `Hosting` option on the first prompt.
+6
View File
@@ -86,6 +86,12 @@ The product details component handles the display of each product. The Angular R
<code-example header="src/app/product-details/product-details.component.html" path="getting-started/src/app/product-details/product-details.component.html" region="details">
</code-example>
<div class="alert is-helpful">
The line, `<h4>{{ product.price | currency }}</h4>`, uses the `currency` pipe to transform `product.price` from a number to a currency string. A pipe is a way you can transform data in your HTML template. For more information about Angular pipes, see [Pipes](guide/pipes "Pipes").
</div>
Now, when users click on a name in the product list, the router navigates them to the distinct URL for the product, swaps out the product list component for the product details component, and displays the product details.
<div class="lightbox">
+1 -1
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.
+1
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"},
+3
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/",
+7 -6
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 d807b8240",
"extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js c8f3ce348",
"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",
@@ -49,7 +49,7 @@
"example-use-local": "node tools/ng-packages-installer overwrite ./tools/examples/shared --debug --force",
"example-use-npm": "node tools/ng-packages-installer restore ./tools/examples/shared",
"example-check-local": "node tools/ng-packages-installer check ./tools/examples/shared",
"deploy-production": "scripts/deploy-to-firebase.sh",
"deploy-production": "node scripts/deploy-to-firebase",
"check-env": "yarn ~~check-env",
"postcheck-env": "yarn aio-check-local",
"payload-size": "scripts/payload.sh",
@@ -62,7 +62,7 @@
"redirects-test": "node tests/deployment/unit/test",
"firebase-utils-test": "node tools/firebase-test-utils/test",
"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",
"tools-test": "yarn docs-test && yarn boilerplate:test && jasmine tools/ng-packages-installer/index.spec.js && jasmine scripts/deploy-to-firebase.spec.js && yarn firebase-utils-test",
"preserve-and-sync": "yarn docs",
"serve-and-sync": "run-p \"docs-watch --watch-only\" \"start {@}\" --",
"boilerplate:add": "node ./tools/examples/example-boilerplate add",
@@ -71,6 +71,7 @@
"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",
@@ -127,7 +128,7 @@
"eslint": "^3.19.0",
"eslint-plugin-jasmine": "^2.2.0",
"find-free-port": "^2.0.0",
"firebase-tools": "^7.11.0",
"firebase-tools": "^8.14.1",
"fs-extra": "^2.1.2",
"globby": "^6.1.0",
"hast-util-is-element": "^1.0.0",
@@ -160,7 +161,7 @@
"remark-html": "^8.0.0",
"rimraf": "^2.6.1",
"semver": "^5.3.0",
"shelljs": "^0.7.7",
"shelljs": "^0.8.4",
"tree-kill": "^1.1.0",
"ts-node": "^8.4.1",
"tslint": "~6.1.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"
}
}
+209
View File
@@ -0,0 +1,209 @@
#!/bin/env node
//
// WARNING: `CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN` should NOT be printed.
//
'use strict';
const {cd, cp, exec: _exec, set} = require('shelljs');
set('-e');
// Constants
const REPO_SLUG = 'angular/angular';
const NG_REMOTE_URL = `https://github.com/${REPO_SLUG}.git`;
// Exports
module.exports = {
computeDeploymentInfo,
computeInputVars,
getLatestCommit,
};
// Run
if (require.main === module) {
const isDryRun = process.argv[2] === '--dry-run';
const inputVars = computeInputVars(process.env);
const deploymentInfo = computeDeploymentInfo(inputVars);
if (deploymentInfo.skipped) {
console.log(deploymentInfo.reason);
} else {
console.log(
`Git branch : ${inputVars.currentBranch}\n` +
`Build/deploy mode : ${deploymentInfo.deployEnv}\n` +
`Firebase project : ${deploymentInfo.projectId}\n` +
`Firebase site : ${deploymentInfo.siteId}\n` +
`Deployment URLs : ${deploymentInfo.deployedUrl}\n` +
` https://${deploymentInfo.siteId}.web.app/`);
if (!isDryRun) {
deploy({...inputVars, ...deploymentInfo});
}
}
}
// Helpers
function computeDeploymentInfo(
{currentBranch, currentCommit, isPullRequest, repoName, repoOwner, stableBranch}) {
// Do not deploy if we are running in a fork.
if (`${repoOwner}/${repoName}` !== REPO_SLUG) {
return skipDeployment(`Skipping deploy because this is not ${REPO_SLUG}.`);
}
// Do not deploy if this is a PR. PRs are deployed in the `aio_preview` CircleCI job.
if (isPullRequest) {
return skipDeployment('Skipping deploy because this is a PR build.');
}
// Do not deploy if the current commit is not the latest on its branch.
const latestCommit = getLatestCommit(currentBranch);
if (currentCommit !== latestCommit) {
return skipDeployment(
`Skipping deploy because ${currentCommit} is not the latest commit (${latestCommit}).`);
}
// The deployment mode is computed based on the branch we are building.
const currentBranchMajorVersion = computeMajorVersion(currentBranch);
const deploymentInfoPerTarget = {
next: {
deployEnv: 'next',
projectId: 'angular-io',
siteId: 'next-angular-io-site',
deployedUrl: 'https://next.angular.io/',
},
rc: {
deployEnv: 'rc',
projectId: 'angular-io',
siteId: 'rc-angular-io-site',
deployedUrl: 'https://rc.angular.io/',
},
stable: {
deployEnv: 'stable',
projectId: 'angular-io',
siteId: `v${currentBranchMajorVersion}-angular-io-site`,
deployedUrl: 'https://angular.io/',
},
archive: {
deployEnv: 'archive',
projectId: 'angular-io',
siteId: `v${currentBranchMajorVersion}-angular-io-site`,
deployedUrl: `https://v${currentBranchMajorVersion}.angular.io/`,
},
};
if (currentBranch === 'master') {
return deploymentInfoPerTarget.next;
} else if (currentBranch === stableBranch) {
return deploymentInfoPerTarget.stable;
} else {
const stableBranchMajorVersion = computeMajorVersion(stableBranch);
// Find the branch that has highest minor version for the given `currentBranchMajorVersion`.
const mostRecentMinorVersionBranch =
// List the branches that start with the major version.
getRemoteRefs(`refs/heads/${currentBranchMajorVersion}.*.x`)
// Extract the version number.
.map(line => line.split('/')[2])
// Sort by the minor version.
.sort((a, b) => a.split('.')[1] - b.split('.')[1])
// Get the highest version.
.pop();
// Do not deploy if it is not the latest branch for the given major version.
// NOTE: At this point, we know the current branch is not the stable branch.
if (currentBranch !== mostRecentMinorVersionBranch) {
return skipDeployment(
`Skipping deploy of branch "${currentBranch}" to Firebase.\n` +
'There is a more recent branch with the same major version: ' +
`"${mostRecentMinorVersionBranch}"`);
}
return (currentBranchMajorVersion < stableBranchMajorVersion) ?
// This is the latest minor version for a major that is less than the stable major version:
// Deploy as `archive`.
deploymentInfoPerTarget.archive :
// This is the latest minor version for a major that is equal or greater than the stable
// major version, but not the stable version itself:
// Deploy as `rc`.
deploymentInfoPerTarget.rc;
}
// We should never get here.
throw new Error('Failed to determine deployment info.');
}
function computeInputVars({
CI_AIO_MIN_PWA_SCORE: minPwaScore,
CI_BRANCH: currentBranch,
CI_COMMIT: currentCommit,
CI_PULL_REQUEST,
CI_REPO_NAME: repoName,
CI_REPO_OWNER: repoOwner,
CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN: firebaseToken,
CI_STABLE_BRANCH: stableBranch,
}) {
return {
currentBranch,
currentCommit,
firebaseToken,
isPullRequest: CI_PULL_REQUEST !== 'false',
minPwaScore,
repoName,
repoOwner,
stableBranch,
};
}
function computeMajorVersion(branchName) {
return +branchName.split('.', 1)[0];
}
function deploy(
{currentCommit, deployedUrl, deployEnv, firebaseToken, minPwaScore, projectId, siteId}) {
cd(`${__dirname}/..`);
console.log('\n\n\n==== Build the AIO app. ====\n');
yarn(`build --configuration=${deployEnv} --progress=false`);
console.log('\n\n\n==== Add any mode-specific files into the AIO distribution. ====\n');
cp('-rf', `src/extra-files/${deployEnv}/.`, 'dist/');
console.log('\n\n\n==== Update opensearch descriptor for AIO with `deployedUrl`. ====\n');
yarn(`set-opensearch-url ${deployedUrl.replace(/[^/]$/, '$&/')}`); // The URL must end with `/`.
console.log('\n\n\n==== Check payload size and upload the numbers to Firebase DB. ====\n');
yarn('payload-size');
console.log('\n\n\n==== Deploy AIO to Firebase hosting. ====\n');
yarn(`firebase use "${projectId}" --token "${firebaseToken}"`);
yarn(`firebase target:apply hosting aio "${siteId}" --token "${firebaseToken}"`);
yarn(
`firebase deploy --only hosting:aio --message "Commit: ${currentCommit}" --non-interactive ` +
`--token "${firebaseToken}"`);
console.log('\n\n\n==== Run PWA-score tests. ====\n');
yarn(`test-pwa-score "${deployedUrl}" "${minPwaScore}"`);
}
function exec(cmd, opts) {
// Using `silent: true` to ensure no secret env variables are printed.
return _exec(cmd, {silent: true, ...opts}).trim();
}
function getRemoteRefs(refOrPattern, remote = NG_REMOTE_URL) {
return exec(`git ls-remote ${remote} ${refOrPattern}`).split('\n');
}
function getLatestCommit(branchName, remote = undefined) {
return getRemoteRefs(branchName, remote)[0].slice(0, 40);
}
function skipDeployment(reason) {
return {reason, skipped: true};
}
function yarn(cmd) {
// Using `--silent` to ensure no secret env variables are printed.
return exec(`yarn --silent ${cmd}`);
}
-132
View File
@@ -1,132 +0,0 @@
#!/usr/bin/env bash
# WARNING: CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN should NOT be printed.
set +x -eu -o pipefail
# Do not deploy if we are running in a fork.
if [[ "$CI_REPO_OWNER/$CI_REPO_NAME" != "angular/angular" ]]; then
echo "Skipping deploy because this is not angular/angular."
exit 0
fi
# Do not deploy if this is a PR. PRs are deployed in the `aio_preview` CircleCI job.
if [[ $CI_PULL_REQUEST != "false" ]]; then
echo "Skipping deploy because this is a PR build."
exit 0
fi
# Do not deploy if the current commit is not the latest on its branch.
readonly latestCommit=$(git ls-remote origin $CI_BRANCH | cut -c1-40)
if [[ $CI_COMMIT != $latestCommit ]]; then
echo "Skipping deploy because $CI_COMMIT is not the latest commit ($latestCommit)."
exit 0
fi
# The deployment mode is computed based on the branch we are building
if [[ $CI_BRANCH == master ]]; then
readonly deployEnv=next
elif [[ $CI_BRANCH == $CI_STABLE_BRANCH ]]; then
readonly deployEnv=stable
else
# Extract the major versions from the branches, e.g. the 4 from 4.3.x
readonly majorVersion=${CI_BRANCH%%.*}
readonly majorVersionStable=${CI_STABLE_BRANCH%%.*}
# Do not deploy if the major version is not less than the stable branch major version
if (( $majorVersion >= $majorVersionStable )); then
echo "Skipping deploy of branch \"$CI_BRANCH\" to firebase."
echo "We only deploy archive branches with the major version less than the stable branch: \"$CI_STABLE_BRANCH\""
exit 0
fi
# Find the branch that has highest minor version for the given `$majorVersion`
readonly mostRecentMinorVersion=$(
# List the branches that start with the major version
git ls-remote origin refs/heads/${majorVersion}.*.x |
# Extract the version number
awk -F'/' '{print $3}' |
# Sort by the minor version
sort -t. -k 2,2n |
# Get the highest version
tail -n1
)
# Do not deploy as it is not the latest branch for the given major version
if [[ $CI_BRANCH != $mostRecentMinorVersion ]]; then
echo "Skipping deploy of branch \"$CI_BRANCH\" to firebase."
echo "There is a more recent branch with the same major version: \"$mostRecentMinorVersion\""
exit 0
fi
readonly deployEnv=archive
fi
case $deployEnv in
next)
readonly projectId=aio-staging
readonly siteId=$projectId
readonly deployedUrl=https://next.angular.io/
readonly firebaseToken=$CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN
;;
stable)
readonly projectId=angular-io
readonly siteId=$projectId
readonly deployedUrl=https://angular.io/
readonly firebaseToken=$CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN
;;
archive)
# Special case v9-angular-io because its piloting the firebase hosting "multisites" setup
# See https://angular-team.atlassian.net/browse/DEV-125 for more info.
if [[ "$majorVersion" == "9" ]]; then
readonly projectId=aio-staging
readonly siteId=v9-angular-io
else
readonly projectId=v${majorVersion}-angular-io
readonly siteId=$projectId
fi
readonly deployedUrl=https://v${majorVersion}.angular.io/
readonly firebaseToken=$CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN
;;
esac
echo "Git branch : $CI_BRANCH"
echo "Build/deploy mode : $deployEnv"
echo "Firebase project : $projectId"
echo "Firebase site : $siteId"
echo "Deployment URL : $deployedUrl"
if [[ ${1:-} == "--dry-run" ]]; then
exit 0
fi
# Deploy
(
cd "`dirname $0`/.."
echo "\n\n\n==== Build the aio app ====\n"
yarn build --configuration=$deployEnv --progress=false
echo "\n\n\n==== Add any mode-specific files into the aio distribution ====\n"
cp -rf src/extra-files/$deployEnv/. dist/
echo "\n\n\n==== Update opensearch descriptor for aio with the deployedUrl ====\n"
# deployedUrl must end with /
yarn set-opensearch-url $deployedUrl
echo "\n\n\n==== Check payload size and upload the numbers to firebase db ====\n"
yarn payload-size
echo "\n\n\n==== Deploy aio to firebase hosting ====\n"
yarn firebase use "${projectId}" --token "$firebaseToken"
yarn firebase target:apply hosting aio $siteId --token "$firebaseToken"
yarn firebase deploy --only hosting:aio --message "Commit: $CI_COMMIT" --non-interactive --token "$firebaseToken"
echo "\n\n\n==== Run PWA-score tests ====\n"
yarn test-pwa-score "$deployedUrl" "$CI_AIO_MIN_PWA_SCORE"
)
+282
View File
@@ -0,0 +1,282 @@
#!/usr/bin/env node
'use strict';
const {execSync} = require('child_process');
const {computeDeploymentInfo, computeInputVars, getLatestCommit} = require('./deploy-to-firebase');
describe('deploy-to-firebase:', () => {
it('master - skip deploy - not angular', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'notangular',
}))).toEqual({
skipped: true,
reason: 'Skipping deploy because this is not angular/angular.',
});
});
it('master - skip deploy - angular fork', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'notangular',
CI_REPO_NAME: 'angular',
}))).toEqual({
skipped: true,
reason: 'Skipping deploy because this is not angular/angular.',
});
});
it('master - skip deploy - pull request', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'true',
}))).toEqual({
skipped: true,
reason: 'Skipping deploy because this is a PR build.',
});
});
it('master - deploy success', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: 'master',
CI_COMMIT: getLatestCommit('master'),
}))).toEqual({
deployEnv: 'next',
projectId: 'angular-io',
siteId: 'next-angular-io-site',
deployedUrl: 'https://next.angular.io/',
});
});
it('master - skip deploy - commit not HEAD', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: 'master',
CI_COMMIT: 'DUMMY_TEST_COMMIT',
}))).toEqual({
skipped: true,
reason:
'Skipping deploy because DUMMY_TEST_COMMIT is not the latest commit ' +
`(${getLatestCommit('master')}).`,
});
});
it('stable - deploy success', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: '4.3.x',
CI_STABLE_BRANCH: '4.3.x',
CI_COMMIT: getLatestCommit('4.3.x'),
}))).toEqual({
deployEnv: 'stable',
projectId: 'angular-io',
siteId: 'v4-angular-io-site',
deployedUrl: 'https://angular.io/',
});
});
it('stable - skip deploy - commit not HEAD', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: '4.3.x',
CI_STABLE_BRANCH: '4.3.x',
CI_COMMIT: 'DUMMY_TEST_COMMIT',
}))).toEqual({
skipped: true,
reason:
'Skipping deploy because DUMMY_TEST_COMMIT is not the latest commit ' +
`(${getLatestCommit('4.3.x')}).`,
});
});
it('archive - deploy success', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: '2.4.x',
CI_STABLE_BRANCH: '4.3.x',
CI_COMMIT: getLatestCommit('2.4.x'),
}))).toEqual({
deployEnv: 'archive',
projectId: 'angular-io',
siteId: 'v2-angular-io-site',
deployedUrl: 'https://v2.angular.io/',
});
});
// v9 used to be special-cased, because it was piloting the Firebase hosting "multisites" setup.
// See https://angular-team.atlassian.net/browse/DEV-125 for more info.
it('archive - deploy success (no special case for v9)', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: '9.1.x',
CI_STABLE_BRANCH: '10.0.x',
CI_COMMIT: getLatestCommit('9.1.x'),
}))).toEqual({
deployEnv: 'archive',
projectId: 'angular-io',
siteId: 'v9-angular-io-site',
deployedUrl: 'https://v9.angular.io/',
});
});
it('archive - skip deploy - commit not HEAD', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: '2.4.x',
CI_STABLE_BRANCH: '4.3.x',
CI_COMMIT: 'DUMMY_TEST_COMMIT',
}))).toEqual({
skipped: true,
reason:
'Skipping deploy because DUMMY_TEST_COMMIT is not the latest commit ' +
`(${getLatestCommit('2.4.x')}).`,
});
});
it('archive - skip deploy - major same as stable, minor less than stable', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: '2.1.x',
CI_STABLE_BRANCH: '2.2.x',
CI_COMMIT: getLatestCommit('2.1.x'),
}))).toEqual({
skipped: true,
reason:
'Skipping deploy of branch "2.1.x" to Firebase.\n' +
'There is a more recent branch with the same major version: "2.4.x"',
});
});
it('archive - skip deploy - major lower than stable, minor not latest', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: '2.1.x',
CI_STABLE_BRANCH: '4.3.x',
CI_COMMIT: getLatestCommit('2.1.x'),
}))).toEqual({
skipped: true,
reason:
'Skipping deploy of branch "2.1.x" to Firebase.\n' +
'There is a more recent branch with the same major version: "2.4.x"',
});
});
it('rc - deploy success - major higher than stable', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: '4.4.x',
CI_STABLE_BRANCH: '2.2.x',
CI_COMMIT: getLatestCommit('4.4.x'),
}))).toEqual({
deployEnv: 'rc',
projectId: 'angular-io',
siteId: 'rc-angular-io-site',
deployedUrl: 'https://rc.angular.io/',
});
});
it('rc - deploy success - major same as stable, minor higher', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: '2.4.x',
CI_STABLE_BRANCH: '2.2.x',
CI_COMMIT: getLatestCommit('2.4.x'),
}))).toEqual({
deployEnv: 'rc',
projectId: 'angular-io',
siteId: 'rc-angular-io-site',
deployedUrl: 'https://rc.angular.io/',
});
});
it('rc - skip deploy - commit not HEAD', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: '2.4.x',
CI_STABLE_BRANCH: '2.2.x',
CI_COMMIT: 'DUMMY_TEST_COMMIT',
}))).toEqual({
skipped: true,
reason:
'Skipping deploy because DUMMY_TEST_COMMIT is not the latest commit ' +
`(${getLatestCommit('2.4.x')}).`,
});
});
it('rc - skip deploy - major same as stable, minor not latest', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: '2.1.x',
CI_STABLE_BRANCH: '2.0.x',
CI_COMMIT: getLatestCommit('2.1.x'),
}))).toEqual({
skipped: true,
reason:
'Skipping deploy of branch "2.1.x" to Firebase.\n' +
'There is a more recent branch with the same major version: "2.4.x"',
});
});
it('rc - skip deploy - major higher than stable, minor not latest', () => {
expect(computeDeploymentInfo(computeInputVars({
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: '4.3.x',
CI_STABLE_BRANCH: '2.4.x',
CI_COMMIT: getLatestCommit('4.3.x'),
}))).toEqual({
skipped: true,
reason:
'Skipping deploy of branch "4.3.x" to Firebase.\n' +
'There is a more recent branch with the same major version: "4.4.x"',
});
});
it('integration - should run the main script without error', () => {
const cmd = `"${process.execPath}" "${__dirname}/deploy-to-firebase" --dry-run`;
const env = {
CI_REPO_OWNER: 'angular',
CI_REPO_NAME: 'angular',
CI_PULL_REQUEST: 'false',
CI_BRANCH: 'master',
CI_COMMIT: getLatestCommit('master')
};
const result = execSync(cmd, {encoding: 'utf8', env}).trim();
expect(result).toBe(
'Git branch : master\n' +
'Build/deploy mode : next\n' +
'Firebase project : angular-io\n' +
'Firebase site : next-angular-io-site\n' +
'Deployment URLs : https://next.angular.io/\n' +
' https://next-angular-io-site.web.app/');
});
});
-244
View File
@@ -1,244 +0,0 @@
#!/usr/bin/env bash
set +x -eu -o pipefail
readonly deployToFirebaseDryRun="`dirname $0`/deploy-to-firebase.sh --dry-run"
function check {
if [[ $1 == $2 ]]; then
echo Pass
exit 0
fi
echo Fail
echo ---- Expected ----
echo "$2"
echo ---- Actual ----
echo "$1"
exit 1
}
(
echo ===== master - skip deploy - not angular
actual=$(
export BASH_ENV=/dev/null
export CI_REPO_OWNER=angular
export CI_REPO_NAME=notangular
$deployToFirebaseDryRun
)
expected="Skipping deploy because this is not angular/angular."
check "$actual" "$expected"
)
(
echo ===== master - skip deploy - angular fork
actual=$(
export BASH_ENV=/dev/null
export CI_REPO_OWNER=notangular
export CI_REPO_NAME=angular
$deployToFirebaseDryRun
)
expected="Skipping deploy because this is not angular/angular."
check "$actual" "$expected"
)
(
echo ===== master - skip deploy - pull request
actual=$(
export BASH_ENV=/dev/null
export CI_REPO_OWNER=angular
export CI_REPO_NAME=angular
export CI_PULL_REQUEST=true
$deployToFirebaseDryRun
)
expected="Skipping deploy because this is a PR build."
check "$actual" "$expected"
)
(
echo ===== master - deploy success
actual=$(
export BASH_ENV=/dev/null
export CI_REPO_OWNER=angular
export CI_REPO_NAME=angular
export CI_PULL_REQUEST=false
export CI_BRANCH=master
export CI_COMMIT=$(git ls-remote origin master | cut -c1-40)
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
$deployToFirebaseDryRun
)
expected="Git branch : master
Build/deploy mode : next
Firebase project : aio-staging
Firebase site : aio-staging
Deployment URL : https://next.angular.io/"
check "$actual" "$expected"
)
(
echo ===== master - skip deploy - commit not HEAD
actual=$(
export BASH_ENV=/dev/null
export CI_REPO_OWNER=angular
export CI_REPO_NAME=angular
export CI_PULL_REQUEST=false
export CI_BRANCH=master
export CI_COMMIT=DUMMY_TEST_COMMIT
$deployToFirebaseDryRun
)
expected="Skipping deploy because DUMMY_TEST_COMMIT is not the latest commit ($(git ls-remote origin master | cut -c1-40))."
check "$actual" "$expected"
)
(
echo ===== stable - deploy success
actual=$(
export BASH_ENV=/dev/null
export CI_REPO_OWNER=angular
export CI_REPO_NAME=angular
export CI_PULL_REQUEST=false
export CI_BRANCH=4.3.x
export CI_STABLE_BRANCH=4.3.x
export CI_COMMIT=$(git ls-remote origin 4.3.x | cut -c1-40)
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
$deployToFirebaseDryRun
)
expected="Git branch : 4.3.x
Build/deploy mode : stable
Firebase project : angular-io
Firebase site : angular-io
Deployment URL : https://angular.io/"
check "$actual" "$expected"
)
(
echo ===== stable - skip deploy - commit not HEAD
actual=$(
export BASH_ENV=/dev/null
export CI_REPO_OWNER=angular
export CI_REPO_NAME=angular
export CI_PULL_REQUEST=false
export CI_BRANCH=4.3.x
export CI_STABLE_BRANCH=4.3.x
export CI_COMMIT=DUMMY_TEST_COMMIT
$deployToFirebaseDryRun
)
expected="Skipping deploy because DUMMY_TEST_COMMIT is not the latest commit ($(git ls-remote origin 4.3.x | cut -c1-40))."
check "$actual" "$expected"
)
(
echo ===== archive - deploy success
actual=$(
export BASH_ENV=/dev/null
export CI_REPO_OWNER=angular
export CI_REPO_NAME=angular
export CI_PULL_REQUEST=false
export CI_BRANCH=2.4.x
export CI_STABLE_BRANCH=4.3.x
export CI_COMMIT=$(git ls-remote origin 2.4.x | cut -c1-40)
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
$deployToFirebaseDryRun
)
expected="Git branch : 2.4.x
Build/deploy mode : archive
Firebase project : v2-angular-io
Firebase site : v2-angular-io
Deployment URL : https://v2.angular.io/"
check "$actual" "$expected"
)
(
echo ===== archive - v9-angular-io multisite special case - deploy success
actual=$(
export BASH_ENV=/dev/null
export CI_REPO_OWNER=angular
export CI_REPO_NAME=angular
export CI_PULL_REQUEST=false
export CI_BRANCH=9.1.x
export CI_STABLE_BRANCH=10.0.x
export CI_COMMIT=$(git ls-remote origin 9.1.x | cut -c1-40)
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
$deployToFirebaseDryRun
)
expected="Git branch : 9.1.x
Build/deploy mode : archive
Firebase project : aio-staging
Firebase site : v9-angular-io
Deployment URL : https://v9.angular.io/"
# TODO: This test incorrectly expects the Firebase project to be v9-angular-io.
# v9-angular-io is a "multisites" project currently within the aio-staging project
# This setup is temporary and was created in order to deploy v9.angular.io without
# disruptions.
# See https://angular-team.atlassian.net/browse/DEV-125 for more info.
check "$actual" "$expected"
)
(
echo ===== archive - skip deploy - commit not HEAD
actual=$(
export BASH_ENV=/dev/null
export CI_REPO_OWNER=angular
export CI_REPO_NAME=angular
export CI_PULL_REQUEST=false
export CI_BRANCH=2.4.x
export CI_STABLE_BRANCH=4.3.x
export CI_COMMIT=DUMMY_TEST_COMMIT
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
$deployToFirebaseDryRun
)
expected="Skipping deploy because DUMMY_TEST_COMMIT is not the latest commit ($(git ls-remote origin 2.4.x | cut -c1-40))."
check "$actual" "$expected"
)
(
echo ===== archive - skip deploy - major version too high, lower minor
actual=$(
export BASH_ENV=/dev/null
export CI_REPO_OWNER=angular
export CI_REPO_NAME=angular
export CI_PULL_REQUEST=false
export CI_BRANCH=2.1.x
export CI_STABLE_BRANCH=2.2.x
export CI_COMMIT=$(git ls-remote origin 2.1.x | cut -c-40)
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
$deployToFirebaseDryRun
)
expected="Skipping deploy of branch \"2.1.x\" to firebase.
We only deploy archive branches with the major version less than the stable branch: \"2.2.x\""
check "$actual" "$expected"
)
(
echo ===== archive - skip deploy - major version too high, higher minor
actual=$(
export BASH_ENV=/dev/null
export CI_REPO_OWNER=angular
export CI_REPO_NAME=angular
export CI_PULL_REQUEST=false
export CI_BRANCH=2.4.x
export CI_STABLE_BRANCH=2.2.x
export CI_COMMIT=$(git ls-remote origin 2.4.x | cut -c-40)
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
$deployToFirebaseDryRun
)
expected="Skipping deploy of branch \"2.4.x\" to firebase.
We only deploy archive branches with the major version less than the stable branch: \"2.2.x\""
check "$actual" "$expected"
)
(
echo ===== archive - skip deploy - minor version too low
actual=$(
export BASH_ENV=/dev/null
export CI_REPO_OWNER=angular
export CI_REPO_NAME=angular
export CI_PULL_REQUEST=false
export CI_BRANCH=2.1.x
export CI_STABLE_BRANCH=4.3.x
export CI_COMMIT=$(git ls-remote origin 2.1.x | cut -c-40)
export CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN=XXXXX
$deployToFirebaseDryRun
)
expected="Skipping deploy of branch \"2.1.x\" to firebase.
There is a more recent branch with the same major version: \"2.4.x\""
check "$actual" "$expected"
)
+1
View File
@@ -835,6 +835,7 @@ describe('AppComponent', () => {
const redirectionPerMode: {[mode: string]: boolean} = {
archive: true,
next: false,
rc: false,
stable: false,
};
+1
View File
@@ -152,6 +152,7 @@ export class AppComponent implements OnInit {
// TODO(pbd): consider whether we can lookup the stable and next versions from the internet
const computedVersions: NavigationNode[] = [
{ title: 'next', url: 'https://next.angular.io/' },
{ title: 'rc', url: 'https://rc.angular.io/' },
{ title: 'stable', url: 'https://angular.io/' },
];
if (this.deployment.mode === 'archive') {
+2 -2
View File
@@ -1,6 +1,6 @@
// This is for archived sites, which are hosted at https://vX.angular.io, where X is the major Angular version.
// This is for archived sites, which are hosted at https://vX.angular.io/, where X is the major Angular version.
export const environment = {
gaId: 'UA-8594346-15', // Production id (since it is linked from the main site)
production: true,
mode: 'archive'
mode: 'archive',
};
+2 -2
View File
@@ -1,6 +1,6 @@
// This is for the staging site, which is hosted at https://next.angular.io (and https://aio-staging.firebaseapp.org)
// This is for the staging site, which is hosted at https://next.angular.io/.
export const environment = {
gaId: 'UA-8594346-15', // Production id (since it is linked from the main site)
production: true,
mode: 'next'
mode: 'next',
};
+6
View File
@@ -0,0 +1,6 @@
// This is for the release-candidate site, which is hosted at https://rc.angular.io/.
export const environment = {
gaId: 'UA-8594346-15', // Production id (since it is linked from the main site)
production: true,
mode: 'rc',
};
+2 -2
View File
@@ -1,6 +1,6 @@
// This is for the production site, which is hosted at https://angular.io
// This is for the production site, which is hosted at https://angular.io/.
export const environment = {
gaId: 'UA-8594346-15', // Production id
production: true,
mode: 'stable'
mode: 'stable',
};
+3 -3
View File
@@ -1,11 +1,11 @@
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `angular-cli.json`.
// `ng build --configuration=<foo>` then `environment.<foo>.ts` will be used instead.
// The list of which configurations maps to which file can be found in `angular.json`.
export const environment = {
gaId: 'UA-8594346-26', // Development id
production: false,
mode: 'stable'
mode: 'stable',
};
+2 -2
View File
@@ -6,8 +6,8 @@ After the AIO application had been built and before it is deployed all files and
inside the folder with the same name as the current deployment mode (next, stable, archive)
will be copied to the `dist` folder.
See the `scripts/deploy-to-firebase.sh` script for more detail.
See the `scripts/deploy-to-firebase.js` script for more details.
**Note:**
The `deploy-to-firebase.sh` script always expects there to be a folder for the current deployment
The `deploy-to-firebase.js` script always expects there to be a folder for the current deployment
mode (even if it is empty).
+3
View File
@@ -0,0 +1,3 @@
# Disallow all URLs (see http://www.robotstxt.org/robotstxt.html)
User-agent: *
Disallow: /
+6 -45
View File
@@ -1,50 +1,11 @@
aio-shell.mode-archive {
.mat-toolbar.mat-primary, footer {
background: linear-gradient(145deg,#263238,#78909C);
}
.vertical-menu-item {
&.selected, &:hover {
color: #263238;
}
}
.toc-inner ul.toc-list li.active a {
color: #263238;
&:before {
background-color: #263238;
}
}
.toc-inner ul.toc-list li:hover a {
color: #263238;
}
@include deployTheme(#263238, #78909C);
}
aio-shell.mode-next {
.mat-toolbar.mat-primary, footer {
background: linear-gradient(145deg,#DD0031,#C3002F);
}
.vertical-menu-item {
&.selected, &:hover {
color: #DD0031;
}
}
.toc-inner ul.toc-list li.active a {
color: #DD0031;
&:before {
background-color: #DD0031;
}
}
.toc-inner ul.toc-list li:hover a {
color: #DD0031;
}
@include deployTheme(#DD0031, #C3002F);
}
aio-shell.mode-rc {
@include deployTheme(#DDA302, #C3A300);
}

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