Compare commits

...

135 Commits

Author SHA1 Message Date
0a530e6b47 release: cut the v8.0.0-beta.11 release 2019-04-03 15:02:25 -07:00
dc5577dcb1 docs: release notes for the v7.2.12 release 2019-04-03 14:56:26 -07:00
a6809e0e7d docs: update location API docs (#27010)
PR Close #27010
2019-04-02 16:11:28 -07:00
ddb935fac7 docs: update examples region to match the description in the guide (#29259)
PR Close #29259
2019-04-02 16:09:19 -07:00
afd4a4ed4d feat(core): Add "AbstractType<T>" interface (#29295)
This new interface will match classes whether they are abstract or
concrete. Casting as `AbstractType<MyConcrete>` will return a type that
isn't newable. This type will be used to match abstract classes in the
`get()` functions of `Injector` and `TestBed`.
Type isn't used yet so this isn't a breaking change.

Issue #26491

PR Close #29295
2019-04-02 16:07:22 -07:00
60afe88bcc feat(ivy): do not emit empty providers/imports for defineInjector (#29598)
The defineInjector function specifies its providers and imports array to
be optional, so if no providers/imports are present these keys may be
omitted. This commit updates the compiler to only generate the keys when
necessary.

PR Close #29598
2019-04-02 16:03:54 -07:00
2d372f48db feat(ivy): exclude declarations from injector imports (#29598)
Prior to this change, a module's imports and exports would be used verbatim
as an injectors' imports. This is detrimental for tree-shaking, as a
module's exports could reference declarations that would then prevent such
declarations from being eligible for tree-shaking.

Since an injector actually only needs NgModule references as its imports,
we may safely filter out any declarations from the list of module exports.
This makes them eligible for tree-shaking once again.

PR Close #29598
2019-04-02 16:03:54 -07:00
45c6360e5a feat(ivy): emit module scope metadata using pure function call (#29598)
Prior to this change, all module metadata would be included in the
`defineNgModule` call that is set as the `ngModuleDef` field of module
types. Part of the metadata is scope information like declarations,
imports and exports that is used for computing the transitive module
scope in JIT environments, preventing those references from being
tree-shaken for production builds.

This change moves the metadata for scope computations to a pure function
call that patches the scope references onto the module type. Because the
function is marked pure, it may be tree-shaken out during production builds
such that references to declarations and exports are dropped, which in turn
allows for tree-shaken any declaration that is not otherwise referenced.

Fixes #28077, FW-1035

PR Close #29598
2019-04-02 16:03:54 -07:00
6b39c9cf32 fix(compiler-cli): ngcc - cope with processing entry-points multiple times (#29657)
With the new API, where you can choose to only process the first
matching format, it is possible to process an entry-point multiple
times, if you pass in a different format each time.

Previously, ngcc would always try to process the typings files for
the entry-point along with processing the first format of the current
execution of ngcc. But this meant that it would be trying to process
the typings a second time.

Now we only process the typings if they have not already been
processed as part of processing another format in another
even if it was in a different execution of ngcc.

PR Close #29657
2019-04-02 15:59:34 -07:00
c5799491e7 ci: fix CODEOWNERS for ngcc (#29660)
With a770aa231, ngcc was moved to a different directory
(`compiler/src/ngcc/` --> `compiler/ngcc/`), but the `CODEOWNERS` file
was not updated to reflect that.
PR Close #29660
2019-04-02 15:57:36 -07:00
b14537a004 fix(bazel): use //:tsconfig.json as the default for ng_module (#29670)
This matches the behavior of ts_library

PR Close #29670
2019-04-02 15:57:11 -07:00
630aaa6bfb docs: add Deborah Kurata to Trusted Collaborators (#29605)
This commit adds Deborah to the Trusted Collaborators list, so she will appear in the Collaborators list on angular.io.
PR Close #29605
2019-04-02 15:53:48 -07:00
7c8f4e3202 feat(core): template-var-assignment update schematic (#29608)
Introduces a new update schematic called "template-var-assignment"
that is responsible for analyzing template files in order to warn
developers if template variables are assigned to values.

The schematic also comes with a driver for `tslint` so that the
check can be used wtihin Google.

PR Close #29608
2019-04-02 15:47:32 -07:00
15eb1e0ce1 refactor(core): stronger type for resolved angular decorators (#29608)
PR Close #29608
2019-04-02 15:47:32 -07:00
780081def0 refactor(core): move schematic typescript logic to utility package (#29608)
PR Close #29608
2019-04-02 15:47:32 -07:00
5a724b34bd refactor(ivy): move instructions (#29646)
- moves all publicly exported instructions to their own files
- refactors namespace instructions to set state in `state.ts`
- no longer exports * from `instructions.ts`.
- `instructions.ts` renamed to `shared.ts` (old `shared.ts` contents folded in to `instructions.ts`)
- updates `all.ts` to re-export from public instruction files.

PR Close #29646
2019-04-02 15:47:02 -07:00
03d914a6c2 build: hide @angular/http for Angular v8 (#29550)
Currently our plan is to skip the publish, docgen, and update steps for this package.
During RC, we'll determine if the breaking change is too difficult for users, in which case we might restore the package for another major.

PR Close #29550
2019-04-02 10:55:31 -07:00
98f8b0f328 fix(ivy): ngcc - properly handle aliases class expressions (#29119)
In ES2015, classes could have been emitted as a variable declaration
initialized with a class expression. In certain situations, an intermediary
variable suffixed with `_1` is present such that the variable
declaration's initializer becomes a binary expression with its rhs being
the class expression, and its lhs being the identifier of the intermediate
variable. This structure was not recognized, resulting in such classes not
being considered as a class in `Esm2015ReflectionHost`.

As a consequence, the analysis of functions/methods that return a
`ModuleWithProviders` object did not take the methods of such classes into
account.

Another edge-case with such intermediate variable was that static
properties would not be considered as class members. A testcase was added
to prevent regressions.

Fixes #29078

PR Close #29119
2019-04-02 10:50:46 -07:00
5a1d21ebb4 ci: exclude ngcc from needing g3 presubmit (#29119)
In a770aa2 ngcc was moved up one folder, however the angular-robot config
was not updated to reflect this change.

PR Close #29119
2019-04-02 10:50:46 -07:00
cbd5d28f71 docs: add info regarding injecting custom pipes (#28291)
Indicate that a pipe also needs to be included in the providers array

PR Close #28291
2019-04-02 10:38:36 -07:00
9f54d76ef5 refactor(upgrade): use Bazel packages to avoid symlinks in the source (#29466)
Previously we had to share code between upgrade/dynamic and upgrade/static
by symlinking the `src` folder, which allowed both packages to access
the upgrade/common files.

These symlinks are always problematic on Windows, where we had to run
a script to re-link them, and restore them.

This change uses Bazel packages to share the `upgrade/common` code,
which avoids the need for symlinking the `src` folder.

Also, the Windows specific scripts that fixup the symlinks have also
been removed as there is no more need for them.

PR Close #29466
2019-04-02 10:38:01 -07:00
e5201f92fc refactor(platform-browser): rename _singleTagWhitelist (#29592)
PR Close #29592
2019-04-02 10:37:29 -07:00
3487055d10 refactor(compiler): rename INTERPOLATION_BLACKLIST_REGEXPS (#29593)
PR Close #29593
2019-04-02 10:36:26 -07:00
1c07061246 refactor: change error message (#29594)
Removes usage of whitelist from error messages, comments and test descriptions in ts_api_guardian

Related to #28539

PR Close #29594
2019-04-02 10:29:33 -07:00
d11b0c0c41 refactor(compiler): update docs (#29599)
PR Close #29599
2019-04-02 10:28:52 -07:00
1293da1cf7 refactor(core): update docs (#29600)
PR Close #29600
2019-04-02 10:28:23 -07:00
7c1f73ac7b build(bazel): update to nodejs rules 0.27.9 (#29647)
PR Close #29647
2019-04-02 10:27:14 -07:00
0e201ea9d8 fix(docs-infra): fix scroll position restoration error in ScrollService (#29658)
Based on Google Analytics error report, the following error happens
occasionally (15% or total errors for 2019-03):

```
Cannot read property '0' of null TypeError: at t.scrollToPosition@main.js
```

This was a result of calling [ViewportScroller#scrollToPosition()][1]
with `null`, which in turn happens when calling
[ScrollService#scrollToPosition()][2] while `this.scrollPosition` is
`null`. This can be a result of a `popstate` event without an associated
history state.

This commit fixes the error by checking whether `this.scrollPosition` is
`null`, before using it with `scrollToPosition()`.

(It also refactors away the unneeded internal `popStateFired` property.)

[1]: https://github.com/angular/angular/blob/deca6a60d/packages/common/src/viewport_scroller.ts#L101-L105
[2]: https://github.com/angular/angular/blob/deca6a60d/aio/src/app/shared/scroll.service.ts#L158-L161

PR Close #29658
2019-04-02 10:26:49 -07:00
53be333439 perf(docs-infra): avoid unnecessary JSON parsing in ScrollService (#29658)
PR Close #29658
2019-04-02 10:26:49 -07:00
19081dc9a3 refactor(docs-infra): minor clean-up of ScrollService (#29658)
PR Close #29658
2019-04-02 10:26:49 -07:00
9e4c0bd815 docs: fix typos in getting-started (#29665)
PR #27684 introduced a new getting-started guide and a few typos slipped through the review.

PR Close #29665
2019-04-02 10:25:59 -07:00
deca6a60dd test(docs-infra): avoid click-related CI flake in e2e test (#29641)
One of the tests introduced in #29601 is susceptible to a kind of
WebDriver flake related to trying to click elements hidden behind fixed
positioned elements.
This commit works around the issue by clicking the elements directly
using JavaScript (instead of `WebElement#click()`).

PR Close #29641
2019-04-01 16:18:03 -07:00
63013f1aeb fix(ivy): support finding the import of namespace-imported identifiers (#27675)
Currently there is no support in ngtsc for imports of the form:

```
import * as core from `@angular/core`

export function forRoot(): core.ModuleWithProviders;
```

This commit modifies the `ReflectionHost.getImportOfIdentifier(id)`
method, so that it supports this kind of return type.

PR Close #27675
2019-04-01 16:06:14 -07:00
8bfaaf164a docs: add Web Worker guide (#29633)
Followup to https://github.com/angular/angular-cli/pull/13700

PR Close #29633
2019-04-01 15:31:47 -07:00
1f469cd7bb docs: improve formatDate description (#29632)
PR #29289 reworded the description, making it less obvious that the value to format can be a `Date`.

PR Close #29632
2019-04-01 15:14:50 -07:00
7041e61562 perf(ivy): basic incremental compilation for ngtsc (#29380)
This commit introduces a mechanism for incremental compilation to the ngtsc
compiler.

Previously, incremental information was used in the construction of the
ts.Program for subsequent compilations, but was not used in ngtsc itself.

This commit adds an IncrementalState class, which tracks state between ngtsc
compilations. Currently, this supports skipping the TypeScript emit step
when the compiler can prove the contents of emit have not changed.

This is implemented for @Injectables as well as for files which don't
contain any Angular decorated types. These are the only files which can be
proven to be safe today.

See ngtsc/incremental/README.md for more details.

PR Close #29380
2019-04-01 15:13:56 -07:00
7316212c1e test(ivy): support multiple compilations in the ngtsc test env (#29380)
This commit adds support for compiling the same program repeatedly in a way
that's similar to how incremental builds work in a tool such as the CLI.

* support is added to the compiler entrypoint for reuse of the Program
  object between compilations. This is the basis of the compiler's
  incremental compilation model.

* support is added to wrap the CompilerHost the compiler creates and cache
  ts.SourceFiles in between compilations.

* support is added to track when files are emitted, for assertion purposes.

* an 'exclude' section is added to the base tsconfig to prevent .d.ts
  outputs from the first compilation from becoming inputs to any subsequent
  compilations.

PR Close #29380
2019-04-01 15:13:56 -07:00
aaa16f286d feat(ivy): performance trace mechanism for ngtsc (#29380)
This commit adds a `tracePerformance` option for tsconfig.json. When
specified, it causes a JSON file with timing information from the ngtsc
compiler to be emitted at the specified path.

This tracing system is used to instrument the analysis/emit phases of
compilation, and will be useful in debugging future integration work with
@angular/cli.

See ngtsc/perf/README.md for more details.

PR Close #29380
2019-04-01 15:13:55 -07:00
3e569767e3 fix(ivy): avoid remote scoping if it's not actually required (#29404)
Currently, ngtsc decides to use remote scoping if the compilation of a
component may create a cyclic import. This happens if there are two
components in a scope (say, A and B) and A directly uses B. During
compilation of B ngtsc will then note that if B were to use A, a cycle would
be generated, and so it will opt to use remote scoping for B.

ngtsc already uses the R3TargetBinder to correctly track the imports that
are actually required, for future cycle tracking. This commit expands that
usage to not trigger remote scoping unless B actually does consume A in its
template.

PR Close #29404
2019-04-01 15:13:35 -07:00
abf69dec5b docs: fix typos in getting started (#29640)
PR Close #29640
2019-04-01 15:06:10 -07:00
701da0099b build: Remove --watchfs from bazelrc file (#29635)
--watchfs is causing the build to be flaky on Windows because Bazel
doesn't have proper support for watchfs on Windows, but it doesn't seem
to bring much performance on Linux, either.

Fixes: https://github.com/angular/angular/issues/29541

PR Close #29635
2019-04-01 14:57:30 -07:00
f9497bf28b fix(router): adjust setting navigationTransition when a new navigation cancels an existing one (#29636)
Prior to this change, if a navigation was ongoing and a new one came in, the router could get into a state where `router.currentNavigation` was `null` even though a navigation was executing. This change moves where we set the `currentNavigation` value so it's inside a `switchMap`. This solves the problem because the `finally` on the `switchMap` had been setting `currentNavigation` to `null` but the new `currentNavigation` value would have already been set. Essentially this was a timing problem and is resolved with this change.

Fixes #29389 #29590

PR Close #29636
2019-04-01 12:11:55 -07:00
d7e5535d00 docs: add custom-element ref to library overview (#28476)
PR Close #28476
2019-04-01 12:04:06 -07:00
8d3d75e454 feat(compiler-cli): ngcc - make logging more configurable (#29591)
This allows CLI usage to filter excessive log messages
and integrations like webpack plugins to provide their own logger.

// FW-1198

PR Close #29591
2019-04-01 11:53:28 -07:00
39345b6fae style(compiler-cli): ensure FFR type is implemented correctly (#29539)
PR Close #29539
2019-04-01 11:53:08 -07:00
06859f1335 refactor(compiler-cli): track visited source files in PartialEvaluator (#29539)
PR Close #29539
2019-04-01 11:53:08 -07:00
717aa7c6e4 docs: update CODEOWNERS with missing or removed guides/examples (#29612)
PR Close #29612
2019-04-01 11:52:23 -07:00
9cd90532c1 docs: add missing window key shortcut to language service guide (#29613)
PR Close #29613
2019-04-01 11:28:12 -07:00
ff2a55f14f docs: update Jorge Cano GDE bio (#29622)
PR Close #29622
2019-04-01 11:26:40 -07:00
0abd5f5f03 test(docs-infra): add e2e test for the contributors page (#29601)
Previously, if the shape of data in `contributors.json` was incorrect,
there would be a runtime error (when trying to parse the data), which
would result in a blank page. The likelihood for this happening is
higher after #29553, where the shape of data changed.

This commit adds some basic e2e tests that verify the page works as
expected and there are contributors listed.

PR Close #29601
2019-04-01 11:24:42 -07:00
cd6581e4f0 docs: use smaller image for Jason Bedard (since it was already available) (#29601)
PR Close #29601
2019-04-01 11:24:42 -07:00
76110d71d3 docs(http): add information about body content type to flush method for testing (#29214)
PR Close #29214
2019-04-01 11:03:49 -07:00
a4fb0486c1 docs: fix broken changelog link (#29471)
PR Close #29471
2019-04-01 11:01:39 -07:00
8a13f6b278 docs: remove ngcc steps from Ivy opt-in (#29506)
PR Close #29506
2019-04-01 11:01:14 -07:00
ee7c5ed620 docs: add Ivy lazy load opt-in (#29506)
PR Close #29506
2019-04-01 11:01:14 -07:00
2ff3d2d421 test(upgrade): work around SauceLabs issue with loading AngularJS files (#29603)
Sometimes (especially on mobile browsers on SauceLabs) the script may
fail to load due to a temporary issue with the internet connection. To
avoid flakes on CI when this happens, we retry the download after some
delay.

Related to #28578.

PR Close #29603
2019-04-01 10:59:45 -07:00
33016b8929 fix(core): static-query schematic should detect static queries in getters. (#29609)
Queries can also be statically accessed within getters. e.g.

```ts
ngOnInit() {
  this.myQueryGetter.doSomething();
}
```

In that case we need to check if the `myQueryGetter` definition accesses
a query statically. As we need to use the type checker for every property acess
within lifecylce hooks, the schematic might become slower than before, but considering
that this is a one-time execution, it is totally fine using the type-checker extensively.

PR Close #29609
2019-04-01 10:58:51 -07:00
b2c03b8cd4 build(docs-infra): remove unused PhantomJS dependency (#29611)
PhantomJS is [not being developed any more][1] and with modern
alternatives (such as Chrome headless) there is no reason to keep it as
a dependency.

[1]: https://github.com/ariya/phantomjs/issues/15344

PR Close #29611
2019-04-01 10:57:30 -07:00
fd4c939394 build(docs-infra): upgrade cli command docs sources to f63f8c60f (#29618)
Updating [angular#master](https://github.com/angular/angular/tree/master) from [cli-builds#master](https://github.com/angular/cli-builds/tree/master).
Relevant changes in [commit range](35df0b528...f63f8c60f):

**Modified**
- help/build.json

Closes #29607

PR Close #29618
2019-04-01 10:55:22 -07:00
6759aa68dc docs: added complete path to the spec file (#29621)
PR Close #29621
2019-04-01 10:54:30 -07:00
ab4be7bf80 docs: fix typo in description of angular.io/index.html (#29630)
change "compeling" to "compelling" in description meta tag

PR Close #29630
2019-04-01 10:54:08 -07:00
2b6e107b1e build(docs-infra): add check to ensure all contributor pictures exist (#29553)
PR Close #29553
2019-03-29 11:01:45 -07:00
6a55ba28b2 docs: add Sam Julien to GDE group as well (#29553)
PR Close #29553
2019-03-29 11:01:45 -07:00
33524d9d9c feat(docs-infra): support contributors belonging to multiple groups (#29553)
PR Close #29553
2019-03-29 11:01:45 -07:00
b99a070f88 refactor(docs-infra): change unused classes to interfaces (#29553)
PR Close #29553
2019-03-29 11:01:45 -07:00
799a5a4915 docs: change the order of groups in contributors page (#29553)
Put "Collaborators" before "GDE", since they are semantically closer to
the core team.

PR Close #29553
2019-03-29 11:01:45 -07:00
4b2407a4db docs: change heading of contributors page to avoid confusion (Collaborators --> Contributors) (#29553)
Now that "Collaborators" is a separate group in the contributors page,
having "Angular Collaborators" as the heading of the page (which also
contains the "Angular" and "GDE" groups) is confusing.
Changing the title to "Angular Contributors" to avoid confusion.

PR Close #29553
2019-03-29 11:01:45 -07:00
ed19464be0 docs: change contributor group name (Collaborator --> Collaborators) (#29553)
The name of the group also serves as the group tab's title in the docs
app and having "Collaborator" (singular) as a title for a list of people
didn't read well.
Changing th group name (and thus tab title) to "Collaborators" (plural).

PR Close #29553
2019-03-29 11:01:45 -07:00
c67f6a7e60 docs: fix typo in renderer description (#29581)
PR Close #29581
2019-03-29 10:50:35 -07:00
d4c4a89431 fix(ivy): host attributes and @COmponentChild should be supported on the same component (#29565)
PR Close #29565
2019-03-29 10:49:35 -07:00
12c9bd257d docs: add new getting started guide (#27684)
PR Close #27684
2019-03-29 10:47:37 -07:00
e8768acacc fix(common): escape query selector used when anchor scrolling (#29577)
When an anchor scroll happens, we run document.querySelector. This value can be taken directly from the user. Therefore it's possible to throw an error on scrolling, which can cause the application to fail.

This PR escapes the selector before using it.

Related to #28193
[Internal discussion](https://groups.google.com/a/google.com/forum/#!topic/angular-users/d82GHfmRKLc)

PR Close #29577
2019-03-29 10:39:38 -07:00
303eae918d fix(ivy): querying should be possible on any debug element (#29534)
PR Close #29534
2019-03-29 10:32:57 -07:00
50f7ab2a06 fix(ivy): debug element should support components with ViewContainerRef (#29534)
PR Close #29534
2019-03-29 10:32:57 -07:00
22b89ea58a docs: move text that mention what is expected to fail up higher into the section (#27329)
PR Close #27329
2019-03-29 10:30:28 -07:00
e8921365b7 docs: remove coremodule references (#28434)
PR Close #28434
2019-03-29 10:29:51 -07:00
Jun
009acd2a6c docs(service-worker): add info about no network request for performance strategy (#29288)
PR Close #29288
2019-03-29 10:28:46 -07:00
333bfa0ffb docs: api doc for i18n (#29289)
PR Close #29289
2019-03-29 10:27:42 -07:00
eb0e29b269 build: make VSCode settings opt-in (#29504)
PR Close #29504
2019-03-29 10:26:55 -07:00
71daa11357 docs: add note about ngModel usage in structural directives guide (#29522)
When I tried one of the examples provided in the documention, encountered the " Can't bind to 'ngModel' since it isn't a known property of 'select' ” error. So to resolve it I imported the FormsModule in ngModule. If it is mentioned in the documentation, it would be handy for the beginners to try and learn. Thanks for considering.

Duplicate of pull Request# 29206, As I encountered few issues after multiple authors corrected, So I am creating the new pull request

PR Close #29522
2019-03-29 10:26:15 -07:00
a81fd5f750 build(docs-infra): upgrade cli command docs sources to 35df0b528 (#29583)
Updating [angular#master](https://github.com/angular/angular/tree/master) from [cli-builds#master](https://github.com/angular/cli-builds/tree/master).
Relevant changes in [commit range](42e87428d...35df0b528):

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

PR Close #29583
2019-03-29 10:25:30 -07:00
57f7996b6d docs: add asset config details (#28214)
PR Close #28214
2019-03-28 15:31:24 -07:00
27ba4ac982 docs: reorg deployment guide with serve-from-disk info from CLI story (#28217)
PR Close #28217
2019-03-28 15:30:50 -07:00
6c76dfc568 docs: copy-edit ivy opt-in page (#29507)
PR Close #29507
2019-03-28 15:29:49 -07:00
78ba503fb9 fix(ivy): ngcc - write .d.ts.map files to the correct folder (#29556)
Previously we were writing `.d.ts` and `.d.ts.map` to different
folders.

PR Close #29556
2019-03-28 15:23:35 -07:00
1df9908579 fix(ivy): ngcc - ensure generated source map paths are correct (#29556)
Previously we were using absolute paths, but since at rendering time
we do not know exactly where the file will be written it is more correct
to  change to using relative paths. This is actually better all round
since it allows the folders to be portable to different machines, etc.

PR Close #29556
2019-03-28 15:23:35 -07:00
c456b73302 refactor(ivy): ngcc - remove the targetPath properties of Transformer and Renderer (#29556)
We have already removed this concept from the public API. This just cleans it out altogether.

The `targetPath` was an alternative output path to the original `basePath`.
This is not really a very useful concept, since the actual target path
of each output file is more complex and not consistently relative to the `basePath`.

PR Close #29556
2019-03-28 15:23:35 -07:00
632669f069 refactor: update tsickle comment to be more precise (#29513)
Co-Authored-By: benlesh <ben@benlesh.com>
PR Close #29513
2019-03-28 15:22:37 -07:00
33963ca0d3 feat(ivy): add property instruction (#29513)
- Adds `property` instruction
- Does _NOT_ add compiler changes to accommodate `property` instruction, that will be a follow up PR.
- Updates `select` instruction to set the selected index in state.
- Adds dev mode assertions around the selected index state.

Related #29527

PR Close #29513
2019-03-28 15:22:37 -07:00
7b27009e20 fix(ivy): fix proliferation of provider overrides for modules (#29571)
When an @NgModule is imported more than once in the testing module (for
example it appears in the imports of more than one module, or if it's
literally listed multiple times), then TestBed had a bug where the
providers for the module would be overridden many times.

This alone was problematic but would not break tests. However, the original
value of the providers field of the ngInjectorDef was saved each time, and
restored in the same order. Thus, if the provider array was [X], and
overrides were applied twice, then the override array would become
[X, X'] and then [X, X', X, X']. However, on the second override the state
[X, X'] would be stored as original. The array would then be restored to
[X] and then [X, X'].

Each test, therefore, would continue to double the size of the providers
array for the module, eventually exhausting the browser's memory.

This commit adds a Set to track when overrides have been applied to a module
and refrain from applying them more than once.

PR Close #29571
2019-03-28 13:59:25 -07:00
d46a7c8468 docs: add Joost Koehoorn to Angular collaborators (#29554)
PR Close #29554
2019-03-28 10:12:01 -07:00
71ec99856a fix(ivy): allow TestBed to recompile AOT-compiled components in case of template overrides (#29555)
Prior to this change, recompilation of AOT-compiled components in TestBed may fail when template override is requested. That was happening due to the `styleUrls` field defined for a Component, thus switching its state to "requires resolution" (i.e. having external resources) at compile time. This change avoids this issue by storing styles and resetting `styleUrls` field before recompilation. Once compilation is done, saved styles are patched back onto Component def.

PR Close #29555
2019-03-28 10:11:41 -07:00
e958447100 build(docs-infra): upgrade cli command docs sources to 42e87428d (#29562)
Updating [angular#master](https://github.com/angular/angular/tree/master) from [cli-builds#master](https://github.com/angular/cli-builds/tree/master).
Relevant changes in [commit range](18d979cdc...42e87428d):

**Modified**
- help/add.json

PR Close #29562
2019-03-28 10:11:19 -07:00
931d356a10 Revert "feat(ivy): add property instruction (#29513)"
This reverts commit e4c1c88cbc.
2019-03-27 16:11:04 -07:00
e4c1c88cbc feat(ivy): add property instruction (#29513)
- Adds `property` instruction
- Does _NOT_ add compiler changes to accommodate `property` instruction, that will be a follow up PR.
- Updates `select` instruction to set the selected index in state.
- Adds dev mode assertions around the selected index state.

Related #29527

PR Close #29513
2019-03-27 13:49:01 -07:00
1e5a818719 fix(ivy): ngtsc is unable to detect flat module entry-point on windows (#29453)
Currently when building an Angular project with `ngtsc`
and `flatModuleOutFile` enabled, the Ngtsc build will fail
if there are multiple source files as root file names.

Ngtsc and NGC currently determine the entry-point for multiple
root file names by looking for files ending with `/index.ts`.

This functionality is technically deprecated, but still supported
and currently breaks on Windows as the root file names are not
guaranteed to be normalized POSIX-like paths.

In order to make this logic more reliable in the future, this commit
also switches the shim generators and entry-point logic to the branded
path types. This ensures that we don't break this in the future.

PR Close #29453
2019-03-27 13:46:37 -07:00
e57ed61448 refactor(ivy): fix incorrect error message in ngtsc "PathSegment" (#29453)
PR Close #29453
2019-03-27 13:46:37 -07:00
aaa8a3a957 build: update bazel to 0.24 (#29530)
PR Close #29530
2019-03-27 13:45:29 -07:00
80161d5033 build: remove unused dependency from common example (#29532)
Since 04cf4ef0c, the dependency on `Reflect` is no longer needed.

PR Close #29532
2019-03-27 13:44:46 -07:00
6a66af7a27 ci: add packages/examples/common/ to fw-core (#29533)
PR Close #29533
2019-03-27 13:44:02 -07:00
9745f55a65 feat: remove @angular/http dependency from @angular/platform-server (#29408)
PR Close #29408
2019-03-27 12:38:29 -07:00
c9810064cb ci: lock chrome and firefox versions for saucelabs (#29529)
With 0f1da49b86, the Chrome beta job has
been disabled because a new Chrome beta has been released, but Saucelabs
didn't support a chromedriver that is compatible with that given beta version.

Now the topic of pinning these external browsers to a specific version came up. In order to make the build less prone to unexpected new versions, we need to
_permanently_ disable the Chrome beta browser. Otherwise pinning `SL_CHROME`
to a specific version does not statisfy the requirement of making the CI jobs
more deterministic.

See original discussion: https://github.com/angular/angular/pull/29518#discussion_r269140676

Chrome can be pinned to Chrome v73 (latest stable version at time of this commit)
Firefox can be pinned to Firefox v65 (latest stable version available in Saucelabs platform)

PR Close #29529
2019-03-27 12:38:13 -07:00
1727fe24fb refactor(ivy): name anonymous wrapper function (#29543)
This simple change helps with debugging / perf investigations
as we can see function names on a call stack.

PR Close #29543
2019-03-27 12:37:33 -07:00
4eb6b02f08 refactor(ivy): remove forEach usage in ApplicationRef.tick (#29543)
forEach is slower as compared to a regular loop but more importantly
this change removes an anonymous function and thus makes stack traces
shorter and easier to read (important for perf analysis).

PR Close #29543
2019-03-27 12:37:33 -07:00
96b800c8bc feat(ivy): select instruction now generated in front of all relevant instructions (#29546)
PR Close #29546
2019-03-27 12:37:03 -07:00
dd69e4e780 refactor(ivy): remove duplicated flatten util (#29547)
This commit removes code duplication where we had 2 versions of a
`flatten` utility. Moreover this change results in queries using
a non-recursive version of `flatten` which should result in a better
performance of query refresh operations.

PR Close #29547
2019-03-27 12:36:23 -07:00
401b8eedd5 fix(bazel): Update schematics to support routing (#29548)
PR closes https://github.com/angular/angular/issues/29035

PR Close #29548
2019-03-27 12:35:52 -07:00
8badf9808a build: add pre-release check that validates the version name (#29551)
Currently with the release of "8.0.0-beta.10", the Bazel npm packag accidentally
was stamped with an incorrect version placeholder: `8.0.0-beta.10+1.sha-a28b3e3`.

This can happen because the placeholder is based on latest tag that matches the
Semver format. e.g. if `HEAD` equals to the commit that has the latest tag, the
version name will be correct and refer to the tag name (e.g. `8.0.0-beta.10`). Though
if the latest commit is not tagged with the most recent tag, the version
name will also include the SHA of the commit (e.g.  `8.0.0-beta.10+1.sha-a28b3e3`).

We can ensure that we don't accidentally release versions from a more recent commit
that shouldn't be part of the release by adding a pre-release check that ensures that
the `BUILD_SCM_VERSION` Bazel status variable matches the expected version format.

PR Close #29551
2019-03-27 12:26:13 -07:00
f8c7c3c09c docs: add schematic details and links to config page (#27272)
PR Close #27272
2019-03-27 09:58:24 -07:00
b17d1a9aa3 docs: update description text (#28507)
PR Close #28507
2019-03-27 09:57:36 -07:00
60f6d9e733 docs: fix lint error (#28507)
PR Close #28507
2019-03-27 09:57:36 -07:00
416b0d29b9 docs: add details to HttpUrlEncodingCodec API description (#28507)
PR Close #28507
2019-03-27 09:57:36 -07:00
2b836c81a2 docs(router): clarify scrollPositionRestoration options, refactor example (#29260)
clarify scrollPositionRestoration enabled to fully describe the functionality it provides. refactor app module example to compile and remove dependency on unnecessary framework. Remove component example due to bug on reload.

PR Close #29260
2019-03-27 09:55:56 -07:00
ac3ce0d793 docs: replaced hero with heroes component property (#29487)
PR Close #29487
2019-03-27 09:53:51 -07:00
6c33058856 docs: add library structure (#29376)
Fixes #29225

PR Close #29376
2019-03-27 09:42:54 -07:00
50fb629012 docs: add Bonnie to GDE page (#29432)
PR Close #29432
2019-03-27 09:42:28 -07:00
309ffe7e16 fix(ivy): TestBed rewrite to avoid unnecessary recompilations (#29483)
Prior to this change, Ivy version of TestBed was not designed to support the logic to avoid recompilations - most of the Components/Directives/Pipes were recompiled for each test, even if there were no overrides defined for a given Type. Additional checks to avoid recompilation were introduced in one of the previous commits (0244a2433e), but there were still some corner cases that required attention. In order to support the necessary logic better, Ivy TestBed was rewritten/refactored. Main results of this rewrite are:

* no recompilation for Components/Directives/Pipes without overrides
* the logic to restore state between tests (isolate tests) was improved
* transitive scopes calculation no longer performs recompilation (it works with compiled defs)

As a result of these changes we see reduction in memory consumption (3.5-4x improvement) and pefromance increase (4-4.5x improvement).

PR Close #29483
2019-03-27 09:41:58 -07:00
fea2a0f2ac docs: update Shortcut keys for Developer tools in chrome Browser on Windows machine (#29485)
PR Close #29485
2019-03-27 09:41:39 -07:00
e0dcd11a49 docs: update Shortcut keys for Developer tools in chrome Browser on Windows platform (#29485)
PR Close #29485
2019-03-27 09:41:39 -07:00
3514543e4b build(bazel): update integration/bazel lock file (#29508)
PR Close #29508
2019-03-27 09:41:11 -07:00
d9162a872d build(bazel): update to nodejs rules 0.27.8 (#29508)
* fixes prodmode issue in integration/bazel

BREAKING CHANGE:

@bazel/typescript is now a peerDependency of @angular/bazel so user's of @angular/bazel must add @bazel/typescript to their package.json

PR Close #29508
2019-03-27 09:41:11 -07:00
06056b4a6d docs: add Sam Julien to Collaborator group (#29528)
PR Close #29528
2019-03-27 09:40:51 -07:00
3c11646dd3 ci: update windows CI bazelrc (#29542)
PR Close #29542
2019-03-27 09:40:21 -07:00
a2f8f5595f refactor(ivy): rename flushHooksUpTo to select (#29527)
PR Close #29527
2019-03-27 09:35:55 -07:00
a28b3e3359 release: cut the v8.0.0-beta.10 release 2019-03-26 15:54:00 -07:00
495a4c1754 docs: release notes for the v7.2.11 release 2019-03-26 15:47:51 -07:00
17f7bdbd60 build: update zone.js to 0.9.0 (#28219)
The API changes are due to enabling strict checks in TypeScript (via `strict: true`).
The payload size changes in `polyfills.js` are due to more browser APIs being patched in recent versions (e.g. `fetch`, `customElement v1`).

PR Close #28219
2019-03-26 12:50:38 -07:00
531fa00992 docs: fix typo in rxjs guide example (#29446)
PR Close #29446
2019-03-26 12:49:46 -07:00
c412374854 fix(ivy): DebugNode.query should query nodes in the logical tree (#29480)
PR Close #29480
2019-03-26 12:48:37 -07:00
9724247ad8 fix(ivy): generate empty QueryList for root component content queries (#29514)
In View Engine, we used to generate empty QueryLists for content queries on root
components (though we did not actually support populating these lists). We need
to keep this behavior in Ivy for backwards compatibility. Otherwise, components
that are sometimes used as root will fail if they are relying on content query
results to always be defined.

PR Close #29514
2019-03-26 12:45:21 -07:00
568140fb03 fix(ivy): include className in DebugNode.properties (#29488)
Fixes the node's class bindings not being included under `DebugNode.properties.className` like in ViewEngine.

This PR resolves FW-1196.

PR Close #29488
2019-03-26 12:44:51 -07:00
7951c4feb2 test(platform-browser): fix shadow dom test not working in firefox 65 (#29518)
With 093dc915ae9ad92a3baa602eb7cb7862ca4b6734, Firefox has been updated
to the latest available version within Saucelabs. Firefox added shadow DOM support
in Firefox 63 and therefore the shadow dom test in `platform-browser` now runs as well.

This test currently fails because Firefox does not support computed style property
shorthands. In order to make this test work on Firefox now, we just switch from `border`
to `background` (because of the overhead when comparing each `top`, `bottom`, `left`, `right`-border properties)

PR Close #29518
2019-03-26 10:40:25 -07:00
0f1da49b86 ci: temporarily disable chrome beta for saucelabs (#29518)
We need to temporarily disable Chrome beta within the
`legacy-saucelabs-tests` and `test_saucelabs_bazel` job.

This is necessary because Saucelabs added Chrome v74 to their
beta version channel without providing the corresponding
chromedriver that is *required* for that beta version.

Explicitly specifying a chromedriver within the Selenium browser
capabilities doesn't seem to work because Saucelabs seems to mirror
their supported chromedriver versions. Meaning that we can't explicitly
use chromedriver.storage.googleapis.com/index.html?path=74.0.3729.6/

Re-enabling tracked with: FW-1205

PR Close #29518
2019-03-26 10:40:25 -07:00
a5c9fa3c8f ci: update chrome and firefox saucelabs versions (#29518)
Updates the browser versions of Chrome and Firefox to the latest releases. This
matches what we claim to support according to https://angular.io/guide/browser-support.

PR Close #29518
2019-03-26 10:40:25 -07:00
6feef368f6 test(ivy): add tests for component factory projectable node corner cases (#27791)
In some cases ivy expects projectable nodes to be passed in a different order
to ViewEngine. Specifically, ivy expects the catch-all ("*") to be at index
0, whereas ViewEngine expects it to be at its position at which it was parsed
in the template.

This commit adds one test that breaks under ivy and others that just describe
more accurately what happens in corner cases.

PR Close #27791
2019-03-25 13:47:48 -07:00
598 changed files with 14110 additions and 9384 deletions

View File

@ -35,8 +35,9 @@ test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test
# See https://github.com/bazelbuild/bazel/issues/4603
build --symlink_prefix=dist/
# Performance: avoid stat'ing input files
build --watchfs
# Disable watchfs as it causes tests to be flaky on Windows
# https://github.com/angular/angular/issues/29541
build --nowatchfs
# Turn off legacy external runfiles
run --nolegacy_external_runfiles
@ -118,7 +119,7 @@ build --define=compile=legacy
# Load default settings for Remote Build Execution
# When updating, the URLs of bazel_toolchains in packages/bazel/package.bzl
# may also need to be updated (see https://github.com/angular/angular/pull/27935)
import %workspace%/third_party/github.com/bazelbuild/bazel-toolchains/bazelrc/bazel-0.21.0.bazelrc
import %workspace%/third_party/github.com/bazelbuild/bazel-toolchains/bazelrc/bazel-0.24.0.bazelrc
# Increase the default number of jobs by 50% because our build has lots of
# parallelism

View File

@ -2,15 +2,17 @@
# We do this by copying this file to /etc/bazel.bazelrc at the start of the build.
# See documentation in /docs/BAZEL.md
# Save downloaded repositories in a location that can be cached by CodeFresh. This helps us
# speeding up the analysis time significantly with Bazel managed node dependencies on the CI.
# build --repository_cache=C:/codefresh/volume/bazel_repository_cache
# Save downloaded repositories in a location that can be cached by CodeFresh and shared between
# builds. This helps speed up the analysis time significantly with Bazel managed node dependencies
# on the CI.
# https://codefresh.io/docs/docs/configure-ci-cd-pipeline/introduction-to-codefresh-pipelines/#caching-the-artifacts-of-your-build-system
build --repository_cache=C:/codefresh/volume/bazel_repository_cache
# Don't be spammy in the logs
# TODO(gmagolan): Hide progress again once build performance improves
# Presently, CircleCI can timeout during bazel test ... with the following
# error: Too long with no output (exceeded 10m0s)
# build --noshow_progress
build --noshow_progress
# Print all the options that apply to the build.
# This helps us diagnose which options override others

View File

@ -17,8 +17,6 @@ steps:
commands:
# Install dependencies
- yarn install --frozen-lockfile --non-interactive --network-timeout 100000 --no-progress
# Create symlinks needed for Windows.
- scripts\windows\create-symlinks.cmd
# Add Bazel CI config
- copy .codefresh\bazel.rc %ProgramData%\bazel.bazelrc
# Run tests

13
.github/CODEOWNERS vendored
View File

@ -399,10 +399,10 @@
# ================================================
# packages/compiler-cli/src/ngcc/
# packages/compiler-cli/ngcc/
# ================================================
/packages/compiler-cli/src/ngcc/** @angular/fw-ngcc @angular/framework-global-approvers
/packages/compiler-cli/ngcc/** @angular/fw-ngcc @angular/framework-global-approvers
@ -414,6 +414,7 @@
/packages/compiler-cli/src/ngtools/** @angular/tools-cli @angular/framework-global-approvers
/aio/content/guide/ivy.md @angular/tools-cli @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/web-worker.md @angular/tools-cli @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
@ -432,6 +433,7 @@
/packages/platform-browser-dynamic/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/packages/platform-webworker/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/packages/platform-webworker-dynamic/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/packages/examples/common/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/architecture-components.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/architecture-modules.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
@ -512,6 +514,7 @@
/aio/content/guide/module-types.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/template-syntax.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/examples/built-in-template-functions/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/examples/event-binding/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/examples/interpolation/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/examples/template-syntax/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
@ -627,6 +630,7 @@
/packages/service-worker/** @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/service-worker-getting-started.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/examples/service-worker-getting-started/** @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/app-shell.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/service-worker-communications.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/service-worker-config.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/service-worker-devops.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
@ -753,6 +757,10 @@ testing/** @angular/fw-test
/aio/content/examples/toh-pt4/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/examples/toh-pt5/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/examples/toh-pt6/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/examples/getting-started-v0/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/examples/getting-started/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/getting-started/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/images/guide/getting-started/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
@ -779,7 +787,6 @@ testing/** @angular/fw-test
/aio/content/guide/npm-packages.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/browser-support.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/typescript-configuration.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/examples/quickstart/** @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/setup.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/examples/setup/** @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
/aio/content/guide/build.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes

View File

@ -46,7 +46,7 @@ merge:
- "packages/bazel/src/ng_package/**"
- "packages/bazel/src/protractor/**"
- "packages/bazel/src/schematics/**"
- "packages/compiler-cli/src/ngcc/**"
- "packages/compiler-cli/ngcc/**"
- "packages/docs/**"
- "packages/elements/schematics/**"
- "packages/examples/**"

1
.gitignore vendored
View File

@ -13,6 +13,7 @@ pubspec.lock
.idea/
.settings/
.vscode/launch.json
.vscode/settings.json
*.swo
modules/.settings
modules/.vscode

23
.vscode/README.md vendored Normal file
View File

@ -0,0 +1,23 @@
# VSCode Configuration
This folder contains opt-in [Workspace Settings](https://code.visualstudio.com/docs/getstarted/settings) and [Extension Recommendations](https://code.visualstudio.com/docs/editor/extension-gallery#_workspace-recommended-extensions) that the Angular team recommends using when working on this repository.
## Usage
To use the recommended settings follow the steps below:
- install <https://marketplace.visualstudio.com/items?itemName=xaver.clang-format>
- copy `.vscode/recommended-settings.json` to `.vscode/settings.json`
- restart the editor
If you already have your custom workspace settings you should instead manually merge the file content.
This isn't an automatic process so you will need to repeat it when settings are updated.
To see the recommended extensions select "Extensions: Show Recommended Extensions" in the [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette).
## Editing `.vscode/recommended-settings.json`
If you wish to add extra configuration items please keep in mind any settings you add here will be used by many users.
Try to keep these settings to things that help facilitate the development process and avoid altering the user workflow whenever possible.

View File

@ -1,4 +1,7 @@
{
// Format js and ts files on save with `clang-format.executable`
// If `clang-format.executable` is not being used, these two settings should be removed otherwise it will break existing formatting.
// You can instead run `yarn gulp format` to manually format your code.
"[javascript]": {
"editor.formatOnSave": true,
},
@ -8,6 +11,7 @@
// Please install https://marketplace.visualstudio.com/items?itemName=xaver.clang-format to take advantage of `clang-format` in VSCode.
// (See https://clang.llvm.org/docs/ClangFormat.html for more info `clang-format`.)
"clang-format.executable": "${workspaceRoot}/node_modules/.bin/clang-format",
// Exclude third party modules and build artifacts from the editor watchers/searches.
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,

View File

@ -5,13 +5,17 @@ package(default_visibility = ["//visibility:public"])
load("//tools:defaults.bzl", "karma_web_test")
exports_files([
"tsconfig.json",
"LICENSE",
"protractor-perf.conf.js",
"karma-js.conf.js",
"browser-providers.conf.js",
])
alias(
name = "tsconfig.json",
actual = "//packages:tsconfig-build.json",
)
filegroup(
name = "web_test_bootstrap_scripts",
# do not sort

View File

@ -1,3 +1,73 @@
<a name="8.0.0-beta.11"></a>
# [8.0.0-beta.11](https://github.com/angular/angular/compare/8.0.0-beta.10...8.0.0-beta.11) (2019-04-03)
### Bug Fixes
* **bazel:** Update schematics to support routing ([#29548](https://github.com/angular/angular/issues/29548)) ([401b8ee](https://github.com/angular/angular/commit/401b8ee))
* **bazel:** use //:tsconfig.json as the default for ng_module ([#29670](https://github.com/angular/angular/issues/29670)) ([b14537a](https://github.com/angular/angular/commit/b14537a))
* **compiler-cli:** ngcc - cope with processing entry-points multiple times ([#29657](https://github.com/angular/angular/issues/29657)) ([6b39c9c](https://github.com/angular/angular/commit/6b39c9c))
* **core:** static-query schematic should detect static queries in getters. ([#29609](https://github.com/angular/angular/issues/29609)) ([33016b8](https://github.com/angular/angular/commit/33016b8))
### build
* **bazel:** update to nodejs rules 0.27.8 ([#29508](https://github.com/angular/angular/issues/29508)) ([d9162a8](https://github.com/angular/angular/commit/d9162a8))
### Features
* remove [@angular](https://github.com/angular)/http dependency from [@angular](https://github.com/angular)/platform-server ([#29408](https://github.com/angular/angular/issues/29408)) ([9745f55](https://github.com/angular/angular/commit/9745f55))
* **compiler-cli:** ngcc - make logging more configurable ([#29591](https://github.com/angular/angular/issues/29591)) ([8d3d75e](https://github.com/angular/angular/commit/8d3d75e))
* **core:** Add "AbstractType<T>" interface ([#29295](https://github.com/angular/angular/issues/29295)) ([afd4a4e](https://github.com/angular/angular/commit/afd4a4e)), closes [#26491](https://github.com/angular/angular/issues/26491)
* **core:** template-var-assignment update schematic ([#29608](https://github.com/angular/angular/issues/29608)) ([7c8f4e3](https://github.com/angular/angular/commit/7c8f4e3))
### BREAKING CHANGES
* **bazel:** @bazel/typescript is now a peerDependency of @angular/bazel so user's of @angular/bazel must add @bazel/typescript to their package.json
<a name="7.2.12"></a>
## [7.2.12](https://github.com/angular/angular/compare/7.2.11...7.2.12) (2019-04-03)
### Bug Fixes
* **common:** escape query selector used when anchor scrolling ([#29577](https://github.com/angular/angular/issues/29577)) ([7671c73](https://github.com/angular/angular/commit/7671c73)), closes [#28193](https://github.com/angular/angular/issues/28193)
* **router:** adjust setting navigationTransition when a new navigation cancels an existing one ([#29636](https://github.com/angular/angular/issues/29636)) ([e884c0c](https://github.com/angular/angular/commit/e884c0c)), closes [#29389](https://github.com/angular/angular/issues/29389) [#29590](https://github.com/angular/angular/issues/29590)
<a name="8.0.0-beta.10"></a>
# [8.0.0-beta.10](https://github.com/angular/angular/compare/8.0.0-beta.9...8.0.0-beta.10) (2019-03-26)
### Bug Fixes
* **bazel:** allow ng_module users to set createExternalSymbolFactoryReexports ([#29459](https://github.com/angular/angular/issues/29459)) ([21be0fb](https://github.com/angular/angular/commit/21be0fb))
* **bazel:** workaround problem reading summary files from node_modules ([#29459](https://github.com/angular/angular/issues/29459)) ([769d960](https://github.com/angular/angular/commit/769d960))
* **compiler:** inherit param types when class has a constructor which takes no declared parameters and delegates up ([#29232](https://github.com/angular/angular/issues/29232)) ([0007564](https://github.com/angular/angular/commit/0007564))
* **core:** parse incorrect ML open tag as text ([#29328](https://github.com/angular/angular/issues/29328)) ([dafbbf8](https://github.com/angular/angular/commit/dafbbf8)), closes [#29231](https://github.com/angular/angular/issues/29231)
* **core:** static-query schematic should detect queries in "ngDoCheck" and "ngOnChanges" ([#29492](https://github.com/angular/angular/issues/29492)) ([09fab58](https://github.com/angular/angular/commit/09fab58))
* **router:** support NgFactory promise in loadChildren typings ([#29392](https://github.com/angular/angular/issues/29392)) ([26a8c59](https://github.com/angular/angular/commit/26a8c59))
### Features
* **bazel:** Upgrade rules_nodejs and rules_sass ([#29388](https://github.com/angular/angular/issues/29388)) ([d6d081e](https://github.com/angular/angular/commit/d6d081e))
* **service-worker:** support multiple apps on different subpaths of a domain ([#27080](https://github.com/angular/angular/issues/27080)) ([e721c08](https://github.com/angular/angular/commit/e721c08)), closes [#21388](https://github.com/angular/angular/issues/21388)
<a name="7.2.11"></a>
## [7.2.11](https://github.com/angular/angular/compare/7.2.10...7.2.11) (2019-03-26)
This release contains various API docs improvements.
<a name="8.0.0-beta.9"></a>
# [8.0.0-beta.9](https://github.com/angular/angular/compare/8.0.0-beta.8...8.0.0-beta.9) (2019-03-20)
@ -54,7 +124,7 @@ Please update your TypeScript version to 3.3
### Bug Fixes
* **compiler-cli:** incorrect metadata bundle for multiple unnamed re-exports ([#29360](https://github.com/angular/angular/issues/29360)) ([cf8d934](https://github.com/angular/angular/commit/cf8d934)), closes [/github.com/angular/material2/blob/master/tools/package-tools/build-release.ts#L78-L85](https://github.com//github.com/angular/material2/blob/master/tools/package-tools/build-release.ts/issues/L78-L85)
* **compiler-cli:** incorrect metadata bundle for multiple unnamed re-exports ([#29360](https://github.com/angular/angular/issues/29360)) ([cf8d934](https://github.com/angular/angular/commit/cf8d934)), closes [github.com/angular/material2/blob/master/tools/package-tools/build-release.ts#L78-L85](https://github.com/angular/material2/blob/master/tools/package-tools/build-release.ts#L78-L85)

View File

@ -15,8 +15,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# Fetch rules_nodejs so we can install our npm dependencies
http_archive(
name = "build_bazel_rules_nodejs",
sha256 = "fb87ed5965cef93188af9a7287511639403f4b0da418961ce6defb9dcf658f51",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.27.7/rules_nodejs-0.27.7.tar.gz"],
sha256 = "213dcf7e72f3acd4d1e369b7a356f3e5d9560f380bd655b13b7c0ea425d7c419",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.27.9/rules_nodejs-0.27.9.tar.gz"],
)
# Check the bazel version and download npm dependencies

View File

@ -41,16 +41,6 @@ Here are the most important tasks you might need to use:
- `yarn example-e2e --filter=foo` - limit e2e tests to those containing the word "foo"
- `yarn example-e2e --setup --local` - run e2e tests with the local version of Angular contained in the "dist" folder
## Developing on Windows
The `packages/` directory may contain Linux-specific symlinks, which are not recognized by Windows.
These unresolved links cause the docs generation process to fail because it cannot locate certain files.
> Hint: The following steps require administration rights or [Windows Developer Mode](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development) enabled!
To fix this problem, run `scripts/windows/create-symlinks.sh`. This command creates temporary files where the symlinks used to be. Make sure not to commit those files with your documentation changes.
When you are done making and testing your documentation changes, you can restore the original symlinks and delete the temporary files by running `scripts/windows/remove-symlinks.sh`.
It's necessary to remove the temporary files, because otherwise they're displayed as local changes in your git working copy and certain operations are blocked.
## Using ServiceWorker locally

View File

@ -0,0 +1,21 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('Getting Started V0', () => {
beforeEach(() => {
return browser.get('/');
});
it('should display "My Store" in the top bar', async() => {
const title = await element(by.css('app-root app-top-bar h1')).getText();
expect(title).toEqual('My Store');
});
it('should display "Products" on the homepage', async() => {
const title = await element(by.css('app-root app-product-list h2')).getText();
expect(title).toEqual('Products');
});
});

View File

@ -0,0 +1,4 @@
{
"useCommonBoilerplate": false,
"projectType": "getting-started"
}

View File

@ -0,0 +1,3 @@
p {
font-family: Lato;
}

View File

@ -0,0 +1,5 @@
<app-top-bar></app-top-bar>
<div class="container">
<router-outlet></router-outlet>
</div>

View File

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

View File

@ -0,0 +1,25 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { TopBarComponent } from './top-bar/top-bar.component';
import { ProductListComponent } from './product-list/product-list.component';
@NgModule({
imports: [
BrowserModule,
ReactiveFormsModule,
RouterModule.forRoot([
{ path: '', component: ProductListComponent },
])
],
declarations: [
AppComponent,
TopBarComponent,
ProductListComponent
],
bootstrap: [ AppComponent ]
})
export class AppModule { }

View File

@ -0,0 +1,16 @@
import { Component } from '@angular/core';
import { products } from '../products';
@Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.css']
})
export class ProductListComponent {
products = products;
share() {
window.alert('The product has been shared!');
}
}

View File

@ -0,0 +1,17 @@
export const products = [
{
name: 'Phone XL',
price: 799,
description: 'A large phone with one of the best screens'
},
{
name: 'Phone Mini',
price: 699,
description: 'A great phone with one of the best cameras'
},
{
name: 'Phone Standard',
price: 299,
description: ''
}
];

View File

@ -0,0 +1,5 @@
<a [routerLink]="['/']">
<h1>My Store</h1>
</a>
<a [routerLink]="['/cart']" class="button fancy-button"><i class="material-icons">shopping_cart</i>Checkout</a>

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-top-bar',
templateUrl: './top-bar.component.html',
styleUrls: ['./top-bar.component.css']
})
export class TopBarComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@ -0,0 +1,14 @@
[
{
"type": "Overnight",
"price": 25.99
},
{
"type": "2-Day",
"price": 9.99
},
{
"type": "Postal",
"price": 2.99
}
]

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Angular Getting Started</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<link
href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet"
/>
</head>
<body>
<app-root></app-root>
</body>
</html>

View File

@ -1,9 +1,8 @@
// #docregion
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { environment } from './environments/environment';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();

View File

@ -0,0 +1,9 @@
{
"description": "Getting Started",
"files":[
"!**/*.d.ts",
"!**/*.js",
"!**/*.[0-9].*"
],
"tags": ["Angular", "getting started", "tutorial"]
}

View File

@ -0,0 +1,118 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by, ExpectedConditions as EC, logging, ElementFinder, ElementArrayFinder } from 'protractor';
describe('Getting Started', () => {
const pageElements = {
topBarHeader: element(by.css('app-root app-top-bar h1')),
topBarLinks: element(by.css('app-root app-top-bar a')),
topBarCheckoutLink: element(by.cssContainingText('app-root app-top-bar a', 'Checkout')),
productListHeader: element(by.css('app-root app-product-list h2')),
productListItems: element.all(by.css('app-root app-product-list h3')),
productListLinks: element.all(by.css('app-root app-product-list a')),
productDetailsPage: element(by.css('app-root app-product-details div')),
cartPage: element(by.css('app-root app-cart'))
};
describe('General', () => {
beforeAll(async() => {
await browser.get('/');
});
it('should display "My Store"', async() => {
const title = await pageElements.topBarHeader.getText();
expect(title).toEqual('My Store');
});
it('should display "Products" on the homepage', async() => {
const title = await pageElements.productListHeader.getText();
expect(title).toEqual('Products');
});
});
describe('Product List', () => {
beforeAll(async() => {
await browser.get('/');
});
it('should display 3 items', async() => {
const products = await pageElements.productListItems;
expect(products.length).toEqual(3);
});
});
describe('Product Details', () => {
beforeEach(async() => {
await browser.get('/');
});
it('should display information for a product', async() => {
await pageElements.productListLinks.get(0).click();
const product = pageElements.productDetailsPage;
const productHeader = await product.element(by.css('h3')).getText();
const productPrice = await product.element(by.css('h4')).getText();
const productDescription = await product.element(by.css('p')).getText();
expect(await product.isDisplayed()).toBeTruthy();
expect(productHeader).toBe('Phone XL');
expect(productPrice).toBe('$799.00');
expect(productDescription).toBe('A large phone with one of the best screens');
});
it('should add the product to the cart', async() => {
await pageElements.productListLinks.get(0).click();
const product = pageElements.productDetailsPage;
const buyButton = await product.element(by.css('button'));
const checkoutLink = pageElements.topBarCheckoutLink;
await buyButton.click();
await browser.wait(EC.alertIsPresent(), 1000);
await browser.switchTo().alert().accept();
await checkoutLink.click();
const cartItems = await element.all(by.css('app-root app-cart div.cart-item'));
expect(cartItems.length).toBe(1);
});
});
describe('Cart', () => {
beforeEach(async() => {
await browser.get('/');
});
it('should go through the checkout process', async() => {
await pageElements.productListLinks.get(0).click();
const checkoutLink = pageElements.topBarCheckoutLink;
const productDetailsPage = pageElements.productDetailsPage;
const buyButton = await productDetailsPage.element(by.css('button'));
const cartPage = pageElements.cartPage;
const inputFields = cartPage.all(by.css('form input'));
const purchaseButton = await cartPage.element(by.css('button'));
const nameField = inputFields.get(0);
const addressField = inputFields.get(1);
await buyButton.click();
await browser.wait(EC.alertIsPresent(), 1000);
await browser.switchTo().alert().accept();
await checkoutLink.click();
await nameField.sendKeys('Customer');
await addressField.sendKeys('Address');
await purchaseButton.click();
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
const cartMessages = logs.filter(({ message }) => message.includes('Your order has been submitted'));
expect(cartMessages.length).toBe(1);
});
});
});

View File

@ -0,0 +1,4 @@
{
"useCommonBoilerplate": false,
"projectType": "getting-started"
}

View File

@ -0,0 +1,5 @@
<app-top-bar></app-top-bar>
<div class="container">
<router-outlet></router-outlet>
</div>

View File

@ -1,10 +1,9 @@
// #docregion
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: '<h1>{{title}}</h1>',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Angular Modules';
}

View File

@ -0,0 +1,55 @@
// #docplaster
// #docregion http-client-module-import, http-client-module
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
import { HttpClientModule } from '@angular/common/http';
// #enddocregion http-client-module-import
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { TopBarComponent } from './top-bar/top-bar.component';
import { ProductListComponent } from './product-list/product-list.component';
import { ProductAlertsComponent } from './product-alerts/product-alerts.component';
import { ProductDetailsComponent } from './product-details/product-details.component';
// #enddocregion http-client-module
import { CartComponent } from './cart/cart.component';
import { ShippingComponent } from './shipping/shipping.component';
// #docregion product-details-route, http-client-module, shipping-route, cart-route
@NgModule({
imports: [
BrowserModule,
// #enddocregion product-details-route, cart-route
HttpClientModule,
// #docregion product-details-route, cart-route
ReactiveFormsModule,
RouterModule.forRoot([
{ path: '', component: ProductListComponent },
{ path: 'products/:productId', component: ProductDetailsComponent },
// #enddocregion product-details-route
{ path: 'cart', component: CartComponent },
// #enddocregion cart-route, http-client-module
{ path: 'shipping', component: ShippingComponent },
// #enddocregion shipping-route
// #docregion product-details-route, http-client-module, shipping-route, cart-route
])
],
// #enddocregion product-details-route, cart-route
declarations: [
AppComponent,
TopBarComponent,
ProductListComponent,
ProductAlertsComponent,
ProductDetailsComponent,
// #enddocregion http-client-module
CartComponent,
ShippingComponent
// #docregion http-client-module
],
bootstrap: [
AppComponent
]
})
export class AppModule { }

View File

@ -0,0 +1,13 @@
// #docplaster
// #docregion
import { Injectable } from '@angular/core';
// #docregion v1
@Injectable({
providedIn: 'root'
})
export class CartService {
constructor() {}
}

View File

@ -0,0 +1,39 @@
// #docplaster
// #docregion import-http
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
// #enddocregion import-http
@Injectable({
providedIn: 'root'
})
// #docregion props, methods, inject-http, get-shipping
export class CartService {
items = [];
// #enddocregion props, methods
constructor(
private http: HttpClient
) {}
// #enddocregion inject-http
// #docregion methods
addToCart(product) {
this.items.push(product);
}
getItems() {
return this.items;
}
clearCart() {
this.items = [];
return this.items;
}
// #enddocregion methods
getShippingPrices() {
return this.http.get('/assets/shipping.json');
}
// #docregion props, methods, import-inject
}

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.css']
})
export class CartComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@ -0,0 +1,15 @@
<!-- #docplaster -->
<!-- #docregion prices -->
<h3>Cart</h3>
<!-- #enddocregion prices -->
<p>
<a routerLink="/shipping">Shipping Prices</a>
</p>
<!-- #docregion prices -->
<div class="cart-item" *ngFor="let item of items">
<span>{{ item.name }} </span>
<span>{{ item.price | currency }}</span>
</div>
<!-- #enddocregion prices -->

View File

@ -0,0 +1,21 @@
// #docplaster
// #docregion imports
import { Component } from '@angular/core';
import { CartService } from '../cart.service';
// #enddocregion imports
@Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.css']
})
// #docregion inject-cart, items, submit
export class CartComponent {
// #enddocregion inject-cart
items;
// #docregion inject-cart
constructor(
private cartService: CartService
) { }
}

View File

@ -0,0 +1,21 @@
// #docplaster
// #docregion imports
import { Component } from '@angular/core';
import { CartService } from '../cart.service';
// #enddocregion imports
@Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.css']
})
// #docregion props-services, submit
export class CartComponent {
items;
constructor(
private cartService: CartService
) {
this.items = this.cartService.getItems();
}
}

View File

@ -0,0 +1,28 @@
<!-- #docplaster -->
<!-- #docregion checkout-form-1, checkout-form-2 -->
<h3>Cart</h3>
<p>
<a routerLink="/shipping">Shipping Prices</a>
</p>
<div class="cart-item" *ngFor="let item of items">
<span>{{ item.name }} </span>
<span>{{ item.price | currency }}</span>
</div>
<form [formGroup]="checkoutForm" (ngSubmit)="onSubmit(checkoutForm.value)">
<!-- #enddocregion checkout-form-1 -->
<div>
<label>Name</label>
<input type="text" formControlName="name">
</div>
<div>
<label>Address</label>
<input type="text" formControlName="address">
</div>
<button class="button" type="submit">Purchase</button>
<!-- #docregion checkout-form-1 -->
</form>

View File

@ -0,0 +1,40 @@
// #docplaster
// #docregion imports
import { Component } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { CartService } from '../cart.service';
// #enddocregion imports
@Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.css']
})
// #docregion props-services, submit
export class CartComponent {
items;
checkoutForm;
constructor(
private cartService: CartService,
private formBuilder: FormBuilder,
) {
this.items = this.cartService.getItems();
this.checkoutForm = this.formBuilder.group({
name: '',
address: ''
});
}
// #enddocregion props-services
onSubmit(customerData) {
// Process checkout data here
console.warn('Your order has been submitted', customerData);
this.items = this.cartService.clearCart();
this.checkoutForm.reset();
}
// #docregion props-services
}

View File

@ -0,0 +1,3 @@
<p *ngIf="product.price > 700">
<button>Notify Me</button>
</p>

View File

@ -0,0 +1,19 @@
// #docplaster
// #docregion as-generated, imports
import { Component } from '@angular/core';
// #enddocregion as-generated
import { Input } from '@angular/core';
// #enddocregion imports
// #docregion as-generated
@Component({
selector: 'app-product-alerts',
templateUrl: './product-alerts.component.html',
styleUrls: ['./product-alerts.component.css']
})
// #docregion input-decorator
export class ProductAlertsComponent {
// #enddocregion as-generated
@Input() product;
// #docregion as-generated
}

View File

@ -0,0 +1,3 @@
<p *ngIf="product.price > 700">
<button (click)="notify.emit()">Notify Me</button>
</p>

View File

@ -0,0 +1,17 @@
// #docplaster
// #docregion imports
import { Component } from '@angular/core';
import { Input } from '@angular/core';
import { Output, EventEmitter } from '@angular/core';
// #enddocregion imports
@Component({
selector: 'app-product-alerts',
templateUrl: './product-alerts.component.html',
styleUrls: ['./product-alerts.component.css']
})
// #docregion input-output
export class ProductAlertsComponent {
@Input() product;
@Output() notify = new EventEmitter();
}

View File

@ -0,0 +1,31 @@
// #docplaster
// #docregion imports
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { products } from '../products';
// #enddocregion imports
@Component({
selector: 'app-product-details',
templateUrl: './product-details.component.html',
styleUrls: ['./product-details.component.css']
})
// #docregion props-methods, add-to-cart
export class ProductDetailsComponent implements OnInit {
product;
constructor(
private route: ActivatedRoute,
) { }
// #enddocregion props-methods
// #docregion get-product
ngOnInit() {
this.route.paramMap.subscribe(params => {
this.product = products[+params.get('productId')];
});
}
// #enddocregion get-product
// #docregion props-methods
}

View File

@ -0,0 +1,13 @@
<!-- #docplaster -->
<!-- #docregion details -->
<h2>Product Details</h2>
<div *ngIf="product">
<h3>{{ product.name }}</h3>
<h4>{{ product.price | currency }}</h4>
<p>{{ product.description }}</p>
<!-- #enddocregion details -->
<button (click)="addToCart(product)">Buy</button>
<!-- #docregion details -->
</div>

View File

@ -0,0 +1,46 @@
// #docplaster
// #docregion imports, cart-service
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { products } from '../products';
// #enddocregion imports
import { CartService } from '../cart.service';
// #enddocregion cart-service
@Component({
selector: 'app-product-details',
templateUrl: './product-details.component.html',
styleUrls: ['./product-details.component.css']
})
// #docregion props-methods, get-product, inject-cart-service, add-to-cart
export class ProductDetailsComponent implements OnInit {
// #enddocregion add-to-cart, get-product, inject-cart-service
product;
// #docregion inject-cart-service
constructor(
private route: ActivatedRoute,
// #enddocregion props-methods
private cartService: CartService
// #docregion props-methods
) { }
// #enddocregion inject-cart-service
// #docregion get-product
ngOnInit() {
// #enddocregion props-methods
this.route.paramMap.subscribe(params => {
this.product = products[+params.get('productId')];
});
// #docregion props-methods
}
// #enddocregion props-methods, get-product
// #docregion add-to-cart
addToCart(product) {
window.alert('Your product has been added to the cart!');
this.cartService.addToCart(product);
}
// #docregion props-methods, get-product, inject-cart-service
}

View File

@ -0,0 +1 @@
<h2>Products</h2>

View File

@ -0,0 +1,15 @@
import { Component } from '@angular/core';
import { products } from '../products';
@Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.css']
})
export class ProductListComponent {
products = products;
share() {
window.alert('The product has been shared!');
}
}

View File

@ -0,0 +1,20 @@
<!-- #docplaster -->
<!-- #docregion ngfor, interpolation -->
<h2>Products</h2>
<div *ngFor="let product of products">
<!-- #enddocregion ngfor -->
<h3>
<!-- #enddocregion interpolation -->
<a [title]="product.name + ' details'">
<!-- #docregion interpolation -->
{{ product.name }}
<!-- #enddocregion interpolation -->
</a>
<!-- #docregion interpolation -->
</h3>
<!-- #docregion ngfor -->
</div>
<!-- #enddocregion ngfor, interpolation -->

View File

@ -0,0 +1,15 @@
<h2>Products</h2>
<div *ngFor="let product of products">
<h3>
<a [title]="product.name + ' details'">
{{ product.name }}
</a>
</h3>
<p *ngIf="product.description">
Description: {{ product.description }}
</p>
</div>

View File

@ -0,0 +1,19 @@
<h2>Products</h2>
<div *ngFor="let product of products">
<h3>
<a [title]="product.name + ' details'">
{{ product.name }}
</a>
</h3>
<p *ngIf="product.description">
Description: {{ product.description }}
</p>
<button (click)="share()">
Share
</button>
</div>

View File

@ -0,0 +1,28 @@
<h2>Products</h2>
<div *ngFor="let product of products">
<!-- #docregion product-details -->
<h3>
<a [title]="product.name + ' details'">
{{ product.name }}
</a>
</h3>
<!-- #enddocregion product-details -->
<p *ngIf="product.description">
Description: {{ product.description }}
</p>
<!-- #docregion app-product-alerts -->
<button (click)="share()">
Share
</button>
<app-product-alerts
[product]="product">
</app-product-alerts>
<!-- #enddocregion app-product-alerts -->
</div>

View File

@ -0,0 +1,27 @@
<h2>Products</h2>
<div *ngFor="let product of products">
<h3>
<a [title]="product.name + ' details'">
{{ product.name }}
</a>
</h3>
<p *ngIf="product.description">
Description: {{ product.description }}
</p>
<!-- #docregion on-notify -->
<button (click)="share()">
Share
</button>
<app-product-alerts
[product]="product"
(notify)="onNotify()">
</app-product-alerts>
<!-- #enddocregion on-notify -->
</div>

View File

@ -0,0 +1,26 @@
<h2>Products</h2>
<!-- #docregion router-link -->
<div *ngFor="let product of products; index as productId">
<h3>
<a [title]="product.name + ' details'" [routerLink]="['/products', productId]">
{{ product.name }}
</a>
</h3>
<!-- #enddocregion router-link -->
<p *ngIf="product.description">
Description: {{ product.description }}
</p>
<button (click)="share()">
Share
</button>
<app-product-alerts
[product]="product"
(notify)="onNotify()">
</app-product-alerts>
<!-- #docregion router-link -->
</div>
<!-- #enddocregion router-link -->

View File

@ -0,0 +1,21 @@
import { Component } from '@angular/core';
import { products } from '../products';
@Component({
selector: 'app-product-list',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.css']
})
// #docregion on-notify
export class ProductListComponent {
products = products;
share() {
window.alert('The product has been shared!');
}
onNotify() {
window.alert('You will be notified when the product goes on sale');
}
}

View File

@ -0,0 +1,17 @@
export const products = [
{
name: 'Phone XL',
price: 799,
description: 'A large phone with one of the best screens'
},
{
name: 'Phone Mini',
price: 699,
description: 'A great phone with one of the best cameras'
},
{
name: 'Phone Standard',
price: 299,
description: ''
}
];

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-shipping',
templateUrl: './shipping.component.html',
styleUrls: ['./shipping.component.css']
})
export class Shipping1Component implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@ -0,0 +1,6 @@
<h3>Shipping Prices</h3>
<div class="shipping-item" *ngFor="let shipping of shippingCosts | async">
<span>{{ shipping.type }} </span>
<span>{{ shipping.price | currency }}</span>
</div>

View File

@ -0,0 +1,22 @@
// #docplaster
// #docregion imports
import { Component } from '@angular/core';
import { CartService } from '../cart.service';
// #enddocregion
@Component({
selector: 'app-shipping',
templateUrl: './shipping.component.html',
styleUrls: ['./shipping.component.css']
})
// #docregion props, ctor
export class ShippingComponent {
shippingCosts;
// #enddocregion props
constructor(private cartService: CartService) {
this.shippingCosts = this.cartService.getShippingPrices();
}
// #docregion props
}

View File

@ -0,0 +1,7 @@
<a>
<h1>My Store</h1>
</a>
<a class="button fancy-button">
<i class="material-icons">shopping_cart</i>Checkout
</a>

View File

@ -0,0 +1,7 @@
<a [routerLink]="['/']">
<h1>My Store</h1>
</a>
<a [routerLink]="['/cart']" class="button fancy-button">
<i class="material-icons">shopping_cart</i>Checkout
</a>

View File

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

View File

@ -0,0 +1,14 @@
[
{
"type": "Overnight",
"price": 25.99
},
{
"type": "2-Day",
"price": 9.99
},
{
"type": "Postal",
"price": 2.99
}
]

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Angular Getting Started</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<link
href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet"
/>
</head>
<body>
<app-root></app-root>
</body>
</html>

View File

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

View File

@ -0,0 +1,9 @@
{
"description": "Getting Started",
"files":[
"!**/*.d.ts",
"!**/*.js",
"!**/*.[0-9].*"
],
"tags": ["Angular", "getting started", "tutorial"]
}

View File

@ -1,24 +0,0 @@
{
"description": "Contact NgModule v.1",
"files": [
"src/app/app.component.1b.ts",
"src/app/app.module.1b.ts",
"src/app/highlight.directive.ts",
"src/app/title.component.html",
"src/app/title.component.ts",
"src/app/user.service.ts",
"src/app/contact/awesome.pipe.ts",
"src/app/contact/contact.component.css",
"src/app/contact/contact.component.html",
"src/app/contact/contact.component.3.ts",
"src/app/contact/contact.service.ts",
"src/app/contact/contact-highlight.directive.ts",
"src/main.1b.ts",
"src/styles.css",
"src/index.1b.html"
],
"main": "src/index.1b.html",
"tags": ["NgModule"]
}

View File

@ -1,26 +0,0 @@
{
"description": "Contact NgModule v.2",
"files": [
"src/app/app.component.2.ts",
"src/app/app.module.2.ts",
"src/app/highlight.directive.ts",
"src/app/title.component.html",
"src/app/title.component.ts",
"src/app/user.service.ts",
"src/app/contact/contact.component.css",
"src/app/contact/contact.component.html",
"src/app/contact/contact.service.ts",
"src/app/contact/awesome.pipe.ts",
"src/app/contact/contact.component.3.ts",
"src/app/contact/contact.module.2.ts",
"src/app/contact/contact-highlight.directive.ts",
"src/main.2.ts",
"src/styles.css",
"src/index.2.html"
],
"main": "src/index.2.html",
"tags": ["NgModule"]
}

View File

@ -1,223 +0,0 @@
'use strict'; // necessary for es6 output in node
import { browser, element, by } from 'protractor';
describe('NgModule', function () {
// helpers
const gold = 'rgba(255, 215, 0, 1)';
const powderblue = 'rgba(176, 224, 230, 1)';
const lightgray = 'rgba(211, 211, 211, 1)';
const white = 'rgba(0, 0, 0, 0)';
function getCommonsSectionStruct() {
const buttons = element.all(by.css('nav a'));
return {
title: element.all(by.tagName('h1')).get(0),
welcome: element.all(by.css('app-title p i')).get(0),
contactButton: buttons.get(0),
crisisButton: buttons.get(1),
heroesButton: buttons.get(2)
};
}
function getContactSectionStruct() {
const buttons = element.all(by.css('app-contact form button'));
return {
header: element.all(by.css('app-contact h2')).get(0),
popupMessage: element.all(by.css('app-contact div')).get(0),
contactNameHeader: element.all(by.css('app-contact form h3')).get(0),
input: element.all(by.css('app-contact form input')).get(0),
validationError: element.all(by.css('app-contact form .alert')).get(0),
saveButton: buttons.get(0), // can't be tested
nextContactButton: buttons.get(1),
newContactButton: buttons.get(2)
};
}
function getCrisisSectionStruct() {
return {
title: element.all(by.css('ng-component h3')).get(0),
items: element.all(by.css('ng-component a')),
itemId: element.all(by.css('ng-component div')).get(0),
listLink: element.all(by.css('ng-component a')).get(0),
};
}
function getHeroesSectionStruct() {
return {
header: element.all(by.css('ng-component h2')).get(0),
title: element.all(by.css('ng-component h3')).get(0),
items: element.all(by.css('ng-component a')),
itemId: element.all(by.css('ng-component ng-component div div')).get(0),
itemInput: element.all(by.css('ng-component ng-component input')).get(0),
listLink: element.all(by.css('ng-component ng-component a')).get(0),
};
}
// tests
function appTitleTests(color: string, name?: string) {
return function() {
it('should have a gray header', function() {
const commons = getCommonsSectionStruct();
expect(commons.title.getCssValue('backgroundColor')).toBe(color);
});
it('should welcome us', function () {
const commons = getCommonsSectionStruct();
expect(commons.welcome.getText()).toBe('Welcome, ' + (name || 'Sherlock Holmes'));
});
};
}
function contactTests(color: string, name?: string) {
return function() {
it('shows the contact\'s owner', function() {
const contacts = getContactSectionStruct();
expect(contacts.header.getText()).toBe('Contact of ' + (name || 'Sherlock Holmes'));
});
it('can cycle between contacts', function () {
const contacts = getContactSectionStruct();
const nextButton = contacts.nextContactButton;
expect(contacts.contactNameHeader.getText()).toBe('Awesome Sam Spade');
expect(contacts.contactNameHeader.getCssValue('backgroundColor')).toBe(color);
nextButton.click().then(function () {
expect(contacts.contactNameHeader.getText()).toBe('Awesome Nick Danger');
return nextButton.click();
}).then(function () {
expect(contacts.contactNameHeader.getText()).toBe('Awesome Nancy Drew');
});
});
it('can change an existing contact', function () {
const contacts = getContactSectionStruct();
contacts.input.sendKeys('a');
expect(contacts.input.getCssValue('backgroundColor')).toBe(color);
expect(contacts.contactNameHeader.getText()).toBe('Awesome Sam Spadea');
});
it('can create a new contact', function () {
const contacts = getContactSectionStruct();
const newContactButton = contacts.newContactButton;
newContactButton.click().then(function () {
expect(contacts.validationError.getText()).toBe('Name is required');
contacts.input.sendKeys('John Doe');
expect(contacts.contactNameHeader.getText()).toBe('Awesome John Doe');
expect(contacts.validationError.getText()).toBe('');
});
});
};
}
describe('index.html', function () {
beforeEach(function () {
browser.get('');
});
describe('app-title', appTitleTests(white, 'Miss Marple'));
describe('contact', contactTests(lightgray, 'Miss Marple'));
describe('crisis center', function () {
beforeEach(function () {
getCommonsSectionStruct().crisisButton.click();
});
it('shows a list of crisis', function () {
const crisis = getCrisisSectionStruct();
expect(crisis.title.getText()).toBe('Crisis List');
expect(crisis.items.count()).toBe(4);
expect(crisis.items.get(0).getText()).toBe('1 - Dragon Burning Cities');
});
it('can navigate to one crisis details', function () {
const crisis = getCrisisSectionStruct();
crisis.items.get(0).click().then(function() {
expect(crisis.itemId.getText()).toBe('Crisis id: 1');
return crisis.listLink.click();
}).then(function () {
// We are back to the list
expect(crisis.items.count()).toBe(4);
});
});
});
describe('heroes', function () {
beforeEach(function () {
getCommonsSectionStruct().heroesButton.click();
});
it('shows a list of heroes', function() {
const heroes = getHeroesSectionStruct();
expect(heroes.header.getText()).toBe('Heroes of Miss Marple');
expect(heroes.title.getText()).toBe('Hero List');
expect(heroes.items.count()).toBe(6);
expect(heroes.items.get(0).getText()).toBe('11 - Mr. Nice');
});
it('can navigate and edit one hero details', function () {
const heroes = getHeroesSectionStruct();
heroes.items.get(0).click().then(function () {
expect(heroes.itemId.getText()).toBe('Id: 11');
heroes.itemInput.sendKeys(' try');
return heroes.listLink.click();
}).then(function () {
// We are back to the list
expect(heroes.items.count()).toBe(6);
expect(heroes.items.get(0).getText()).toBe('11 - Mr. Nice try');
});
});
});
});
// describe('index.0.html', function() {
// beforeEach(function () {
// browser.get('index.0.html');
// });
// it('has a title', function () {
// const title = element.all(by.tagName('h1')).get(0);
// expect(title.getText()).toBe('Minimal NgModule');
// });
// });
// describe('index.1.html', function () {
// beforeEach(function () {
// browser.get('index.1.html');
// });
// describe('app-title', appTitleTests(powderblue));
// });
// describe('index.1b.html', function () {
// beforeEach(function () {
// browser.get('index.1b.html');
// });
// describe('app-title', appTitleTests(powderblue));
// describe('contact', contactTests(powderblue));
// });
// describe('index.2.html', function () {
// beforeEach(function () {
// browser.get('index.2.html');
// });
// describe('app-title', appTitleTests(gold));
// describe('contact', contactTests(powderblue));
// });
// describe('index.3.html', function () {
// beforeEach(function () {
// browser.get('index.3.html');
// });
// describe('app-title', appTitleTests(gold));
// });
});

View File

@ -1,12 +0,0 @@
{
"description": "Minimal NgModule",
"files": [
"src/app/app.component.0.ts",
"src/app/app.module.0.ts",
"src/main.0.ts",
"src/styles.css",
"src/index.0.html"
],
"main": "src/index.0.html",
"tags": ["NgModule"]
}

View File

@ -1,40 +0,0 @@
{
"description": "NgModule v.3",
"files": [
"src/app/app.component.3.ts",
"src/app/app.module.3.ts",
"src/app/app-routing.module.3.ts",
"src/app/highlight.directive.ts",
"src/app/title.component.html",
"src/app/title.component.ts",
"src/app/user.service.ts",
"src/app/contact/contact.component.css",
"src/app/contact/contact.component.html",
"src/app/contact/contact.service.ts",
"src/app/contact/awesome.pipe.ts",
"src/app/contact/contact.component.3.ts",
"src/app/contact/contact.module.3.ts",
"src/app/contact/contact-routing.module.3.ts",
"src/app/contact/contact-highlight.directive.ts",
"src/app/crisis/*.ts",
"src/app/hero/hero-detail.component.ts",
"src/app/hero/hero-list.component.ts",
"src/app/hero/hero.service.ts",
"src/app/hero/hero.component.3.ts",
"src/app/hero/hero.module.3.ts",
"src/app/hero/hero-routing.module.3.ts",
"src/app/hero/highlight.directive.ts",
"src/main.3.ts",
"src/styles.css",
"src/index.3.html"
],
"main": "src/index.3.html",
"tags": ["NgModule"]
}

View File

@ -1,19 +0,0 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ContactModule } from './contact/contact.module.3';
const routes: Routes = [
{ path: '', redirectTo: 'contact', pathMatch: 'full'},
{ path: 'crisis', loadChildren: './crisis/crisis.module#CrisisModule' },
{ path: 'heroes', loadChildren: './hero/hero.module.3#HeroModule' }
];
@NgModule({
imports: [
ContactModule,
RouterModule.forRoot(routes)
],
exports: [RouterModule]
})
export class AppRoutingModule {}

View File

@ -1,30 +0,0 @@
// #docregion
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ContactModule } from './contact/contact.module';
// #docregion routes
const routes: Routes = [
{ path: '', redirectTo: 'contact', pathMatch: 'full'},
// #docregion lazy-routes
{ path: 'crisis', loadChildren: './crisis/crisis.module#CrisisModule' },
{ path: 'heroes', loadChildren: './hero/hero.module#HeroModule' }
// #enddocregion lazy-routes
];
// #enddocregion routes
@NgModule({
// #docregion imports
imports: [
ContactModule,
// #docregion forRoot
RouterModule.forRoot(routes),
// #enddocregion forRoot
],
// #enddocregion imports
// #docregion exports
exports: [RouterModule]
// #enddocregion exports
})
export class AppRoutingModule {}

View File

@ -1,17 +0,0 @@
// #docplaster
// #docregion
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
// #enddocregion
/*
// #docregion template
template: '<h1 highlight>{{title}}</h1>'
// #enddocregion template
*/
// #docregion
template: '<app-title></app-title>'
})
export class AppComponent {}
// #enddocregion

View File

@ -1,13 +0,0 @@
// #docregion
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
// #docregion template
template: `
<app-title></app-title>
<app-contact></app-contact>
`
// #enddocregion template
})
export class AppComponent {}

View File

@ -1,10 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<app-title></app-title>
<app-contact></app-contact>
`
})
export class AppComponent {}

View File

@ -1,17 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
// #docregion template
template: `
<app-title></app-title>
<nav>
<a routerLink="contact" routerLinkActive="active">Contact</a>
<a routerLink="crisis" routerLinkActive="active">Crisis Center</a>
<a routerLink="heroes" routerLinkActive="active">Heroes</a>
</nav>
<router-outlet></router-outlet>
`
// #enddocregion template
})
export class AppComponent {}

View File

@ -1,17 +0,0 @@
// #docplaster
// #docregion
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<app-title></app-title>
<nav>
<a routerLink="contact" routerLinkActive="active">Contact</a>
<a routerLink="crisis" routerLinkActive="active">Crisis Center</a>
<a routerLink="heroes" routerLinkActive="active">Heroes</a>
</nav>
<router-outlet></router-outlet>
`
})
export class AppComponent {}

View File

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

View File

@ -1,52 +0,0 @@
// #docplaster
// #docregion
/* Angular Imports */
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
/* App Imports */
// #enddocregion
import { AppComponent } from './app.component.1';
/*
// #docregion
import { AppComponent } from './app.component';
// #enddocregion
*/
// #docregion
import { HighlightDirective } from './highlight.directive';
import { TitleComponent } from './title.component';
import { UserService } from './user.service';
/* Contact Related Imports */
import { FormsModule } from '@angular/forms';
import { AwesomePipe } from './contact/awesome.pipe';
import { ContactComponent } from './contact/contact.component.3';
import {
ContactHighlightDirective as ContactHighlightDirective
} from './contact/contact-highlight.directive';
@NgModule({
// #docregion imports
imports: [ BrowserModule, FormsModule ],
// #enddocregion imports
// #docregion declarations, directive, component
declarations: [
AppComponent,
HighlightDirective,
// #enddocregion directive
TitleComponent,
// #enddocregion component
AwesomePipe,
ContactComponent,
ContactHighlightDirective
// #docregion directive, component
],
// #enddocregion declarations, directive, component
// #docregion providers
providers: [ UserService ],
// #enddocregion providers
bootstrap: [ AppComponent ]
})
export class AppModule { }

View File

@ -1,46 +0,0 @@
// #docplaster
// #docregion
/* Angular Imports */
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
/* App Imports */
// #enddocregion
import { AppComponent } from './app.component.1b';
/*
// #docregion
import { AppComponent } from './app.component';
// #enddocregion
*/
// #docregion
import { HighlightDirective } from './highlight.directive';
import { TitleComponent } from './title.component';
import { UserService } from './user.service';
/* Contact Imports */
// #enddocregion
import { ContactComponent } from './contact/contact.component.3';
/*
// #docregion
import { ContactComponent } from './contact/contact.component';
// #enddocregion
*/
// #docregion
import { AwesomePipe } from './contact/awesome.pipe';
import { ContactService } from './contact/contact.service';
import { ContactHighlightDirective } from './contact/contact-highlight.directive';
@NgModule({
imports: [ BrowserModule, FormsModule ],
// #docregion declarations
declarations: [
AppComponent, HighlightDirective, TitleComponent,
AwesomePipe, ContactComponent, ContactHighlightDirective
],
// #docregion providers
providers: [ ContactService, UserService ],
// #enddocregion providers
bootstrap: [ AppComponent ]
})
export class AppModule { }

View File

@ -1,36 +0,0 @@
// #docplaster
// #docregion
/* Angular Imports */
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
/* App Imports */
// #enddocregion
import { AppComponent } from './app.component.2';
/*
// #docregion
import { AppComponent } from './app.component';
// #enddocregion
*/
// #docregion
import { HighlightDirective } from './highlight.directive';
import { TitleComponent } from './title.component';
import { UserService } from './user.service';
/* Contact Imports */
// #enddocregion
import { ContactModule } from './contact/contact.module.2';
/*
// #docregion
import { ContactModule } from './contact/contact.module';
// #enddocregion
*/
// #docregion
@NgModule({
imports: [ BrowserModule, ContactModule ],
declarations: [ AppComponent, HighlightDirective, TitleComponent ],
providers: [ UserService ],
bootstrap: [ AppComponent ],
})
export class AppModule { }

View File

@ -1,39 +0,0 @@
// #docplaster
// #docregion
// #docregion v4
/* Angular Imports */
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
/* App Imports */
import { AppComponent } from './app.component';
/* Core Modules */
import { CoreModule } from './core/core.module';
/* Routing Module */
import { AppRoutingModule } from './app-routing.module';
@NgModule({
// #docregion import-for-root
imports: [
BrowserModule,
// #enddocregion v4
// #enddocregion import-for-root
/*
// #docregion v4
CoreModule,
// #enddocregion v4
*/
// #docregion import-for-root
CoreModule.forRoot({userName: 'Miss Marple'}),
// #docregion v4
AppRoutingModule
],
// #enddocregion import-for-root
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
// #enddocregion v4
// #enddocregion

View File

@ -1,14 +0,0 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { ContactComponent } from './contact.component.3';
const routes = [
{ path: 'contact', component: ContactComponent}
];
@NgModule({
imports: [ RouterModule.forChild(routes) ],
exports: [ RouterModule ]
})
export class ContactRoutingModule {}

View File

@ -1,16 +0,0 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { ContactComponent } from './contact.component';
// #docregion routing
const routes = [
{ path: 'contact', component: ContactComponent}
];
@NgModule({
imports: [ RouterModule.forChild(routes) ],
exports: [ RouterModule ]
})
export class ContactRoutingModule {}
// #enddocregion

View File

@ -1,53 +0,0 @@
// #docregion
import { Component, OnInit } from '@angular/core';
import { Contact, ContactService } from './contact.service';
import { UserService } from '../user.service';
@Component({
selector: 'app-contact',
templateUrl: './contact.component.html',
styleUrls: [ './contact.component.css' ]
})
export class ContactComponent implements OnInit {
contact: Contact;
contacts: Contact[];
msg = 'Loading contacts ...';
userName = '';
constructor(private contactService: ContactService, userService: UserService) {
this.userName = userService.userName;
}
ngOnInit() {
this.contactService.getContacts().subscribe(contacts => {
this.msg = '';
this.contacts = contacts;
this.contact = contacts[0];
});
}
next() {
let ix = 1 + this.contacts.indexOf(this.contact);
if (ix >= this.contacts.length) { ix = 0; }
this.contact = this.contacts[ix];
}
onSubmit() {
// POST-DEMO TODO: do something like save it
this.displayMessage('Saved ' + this.contact.name);
}
newContact() {
this.displayMessage('New contact');
this.contact = {id: 42, name: ''};
this.contacts.push(this.contact);
}
/** Display a message briefly, then remove it. */
displayMessage(msg: string) {
this.msg = msg;
setTimeout(() => this.msg = '', 1500);
}
}

View File

@ -1,32 +0,0 @@
/* #docregion */
.ng-valid[required] {
border-left: 5px solid #42A948; /* green */
}
.ng-invalid {
border-left: 5px solid #a94442; /* red */
}
.alert {
padding: 15px;
margin: 8px 0;
border: 1px solid transparent;
border-radius: 4px;
}
.alert-danger {
color: #a94442;
background-color: #f2dede;
border-color: #ebccd1;
}
.msg {
color: blue;
background-color: whitesmoke;
border: 1px solid transparent;
border-radius: 4px;
margin-bottom: 20px;
}
.button-group {
padding-top: 12px;
}

View File

@ -1,37 +0,0 @@
<!-- #docregion -->
<h2>Contact of {{userName}}</h2>
<div *ngIf="msg" class="msg">{{msg}}</div>
<form *ngIf="contacts" (ngSubmit)="onSubmit()" #contactForm="ngForm">
<!-- #docregion awesome -->
<h3 highlight>{{ contact.name | awesome }}</h3>
<!-- #enddocregion awesome -->
<div class="form-group">
<label for="name">Name</label>
<!-- #docregion ngModel -->
<input type="text" class="form-control" required
[(ngModel)]="contact.name"
name="name" #name="ngModel" >
<!-- #enddocregion ngModel -->
<div [hidden]="name.valid" class="alert alert-danger">
Name is required
</div>
</div>
<div class="button-group">
<button type="submit" class="btn btn-default"
[disabled]="!contactForm.form.valid">
Save</button>
<button type="button" class="btn" (click)="next()"
[disabled]="!contactForm.form.valid">
Next Contact</button>
<button type="button" class="btn" (click)="newContact()">
New Contact</button>
</div>
</form>
<!-- #enddocregion -->

View File

@ -1,54 +0,0 @@
// Exact copy except import UserService from core
// #docregion
import { Component, OnInit } from '@angular/core';
import { Contact, ContactService } from './contact.service';
import { UserService } from '../core/user.service';
@Component({
selector: 'app-contact',
templateUrl: './contact.component.html',
styleUrls: [ './contact.component.css' ]
})
export class ContactComponent implements OnInit {
contact: Contact;
contacts: Contact[];
msg = 'Loading contacts ...';
userName = '';
constructor(private contactService: ContactService, userService: UserService) {
this.userName = userService.userName;
}
ngOnInit() {
this.contactService.getContacts().subscribe(contacts => {
this.msg = '';
this.contacts = contacts;
this.contact = contacts[0];
});
}
next() {
let ix = 1 + this.contacts.indexOf(this.contact);
if (ix >= this.contacts.length) { ix = 0; }
this.contact = this.contacts[ix];
}
onSubmit() {
// POST-DEMO TODO: do something like save it
this.displayMessage('Saved ' + this.contact.name);
}
newContact() {
this.displayMessage('New contact');
this.contact = {id: 42, name: ''};
this.contacts.push(this.contact);
}
/** Display a message briefly, then remove it. */
displayMessage(msg: string) {
this.msg = msg;
setTimeout(() => this.msg = '', 1500);
}
}

View File

@ -1,11 +0,0 @@
// #docregion
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
imports: [
CommonModule
],
declarations: []
})
export class ContactModule { }

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