refactor(docs-infra): complete removal of aio directory (#56496)

Finish removal of aio directory as it is no longer used or relied upon.

PR Close #56496
This commit is contained in:
Joey Perrott
2024-06-18 17:09:57 +00:00
committed by Andrew Kushnir
parent 7be9397ec5
commit cc6cd08ca3
3580 changed files with 15 additions and 193935 deletions
-3
View File
@@ -5,9 +5,6 @@
.git
node_modules
dist
aio/node_modules
aio/tools/examples/shared/node_modules
aio/tools/examples/shared/example-scaffold
# All integration test node_modules folders
integration/animations/node_modules
-9
View File
@@ -67,15 +67,6 @@ build:snapshot-build --stamp
# exceeds the max source file size. To address this, we just *don't* stamp Firefox builds of Angular DevTools.
build:snapshot-build-firefox --nostamp
##########################################################
# AIO architect build configuration #
# See aio/angular.json for available configurations. #
# To build with a partiular configuration: #
# bazel build //aio:build --aio_build_config=<config> #
# Default config is `stable``. #
##########################################################
build --flag_alias=aio_build_config=//aio:flag_aio_build_config
###############################
# Output #
###############################
+1 -1
View File
@@ -44,7 +44,7 @@ function setSecretVar() {
# Create a function to set an environment variable, when called.
#
# Use this function for creating setter for public environment variables that require expensive or
# time-consuming computaions and may not be needed. When needed, you can call this function to set
# time-consuming computations and may not be needed. When needed, you can call this function to set
# the environment variable (which will be available through `$BASH_ENV` from that point onwards).
#
# Arguments:
-1
View File
@@ -16,7 +16,6 @@ echo "source $envHelpersPath;" >> $BASH_ENV;
####################################################################################################
setPublicVar CI "$CI"
setPublicVar PROJECT_ROOT "$projectDir";
setPublicVar CI_AIO_MIN_PWA_SCORE "95";
# This is the branch being built; e.g. `pull/12345` for PR builds.
setPublicVar CI_BRANCH "$CIRCLE_BRANCH";
setPublicVar CI_BUILD_URL "$CIRCLE_BUILD_URL";
+1 -5
View File
@@ -6,10 +6,6 @@
"postCreateCommand": "yarn install",
"extensions": [
"devondcarew.bazel-code",
"gkalpak.aio-docs-utils",
"ms-vscode.vscode-typescript-tslint-plugin",
// The following extensions are useful when working on angular.io (i.e. inside the `aio/` directory).
//"angular.ng-template",
//"dbaeumer.vscode-eslint",
"ms-vscode.vscode-typescript-tslint-plugin"
],
}
-2
View File
@@ -26,8 +26,6 @@ jobs:
cache-node-modules: true
- name: Install node modules
run: yarn install --frozen-lockfile
- name: Install node modules in aio
run: yarn install --frozen-lockfile --cwd aio
- name: Check code lint
run: yarn -s tslint
- name: Check for circular dependencies
-55
View File
@@ -1,55 +0,0 @@
name: Monitoring
on:
schedule:
# Run at 10:00AM every day.
- cron: '0 10 * * *'
permissions: {}
defaults:
run:
shell: bash
jobs:
check_aio:
runs-on: ubuntu-latest
env:
MINIMUM_PWA_SCORE: 95
strategy:
fail-fast: false
matrix:
version: ['https://next.angular.io/', 'https://angular.io/']
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
with:
cache-node-modules: true
node-module-directories: |
./aio/node_modules
- name: Setup Bazel
uses: angular/dev-infra/github-actions/bazel/setup@03b8a7dffd1205e061f0bee949024ebefc2a6592
- name: Setup Bazel RBE
uses: angular/dev-infra/github-actions/bazel/configure-remote@03b8a7dffd1205e061f0bee949024ebefc2a6592
- name: Install node modules in aio
run: yarn install --frozen-lockfile --cwd aio
- name: Run basic e2e and deployment config tests.
run: yarn --cwd aio test-production-url --test_env=TARGET_URL="${{ matrix.version }}"
- name: Run PWA-score tests.
run: yarn --cwd aio test-pwa-score "${{ matrix.version }}" "${{ env.MINIMUM_PWA_SCORE }}"
- name: Run a11y tests.
run: yarn --cwd aio test-a11y-score "${{ matrix.version }}"
check_contributor_links:
runs-on: ubuntu-latest
steps:
- name: Initialize environment
uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@03b8a7dffd1205e061f0bee949024ebefc2a6592
with:
cache-node-modules: true
node-module-directories: |
./aio/node_modules
- name: Install node modules in aio
run: yarn install --frozen-lockfile --cwd aio
- name: Check website provided in contributors.json file
run: node aio/scripts/test-external-urls.js
+1 -1
View File
@@ -1,4 +1,4 @@
name: Update AIO Angular CLI help
name: Update ADEV Angular CLI help
on:
workflow_dispatch:
-1
View File
@@ -56,7 +56,6 @@ baseline.json
# Husky
.husky/_
aio/content/examples/.DS_Store
# Ignore cache created with the Angular CLI.
-2
View File
@@ -22,8 +22,6 @@ export const format: FormatConfig = {
'!packages/common/src/i18n/currencies.ts',
// Test cases contain non valid code.
'!packages/compiler-cli/test/compliance/test_cases/**/*.{js,ts}',
// Ignore AIO as its pending removal.
'!aio/**/*.{js,ts}',
// Ignore generated javascript file(s)
'!.github/actions/deploy-docs-site/main.js',
+1 -1
View File
@@ -28,7 +28,7 @@ export const release: ReleaseConfig = {
return performNpmReleaseBuild();
},
releaseNotes: {
hiddenScopes: ['aio', 'bazel', 'dev-infra', 'docs-infra', 'zone.js', 'devtools'],
hiddenScopes: ['bazel', 'dev-infra', 'docs-infra', 'zone.js', 'devtools'],
},
releasePrLabels: ['area: build & ci', 'action: merge', 'PullApprove: disable'],
};
-538
View File
@@ -121,19 +121,6 @@ groups:
contains_any_globs(files, [
'packages/animations/**/{*,.*}',
'packages/platform-browser/animations/**/{*,.*}',
'aio/content/guide/animations.md',
'aio/content/guide/add-an-animation.md',
'aio/content/guide/animate-state-style.md',
'aio/content/guide/animation-api-summary.md',
'aio/content/guide/understanding-angular-animation.md',
'aio/content/examples/animations/**/{*,.*}',
'aio/content/images/guide/animations/**/{*,.*}',
'aio/content/guide/complex-animation-sequences.md',
'aio/content/guide/reusable-animations.md',
'aio/content/guide/route-animations.md',
'aio/content/guide/transition-and-triggers.md',
'aio/content/guide/animations-attach-to-html-template.md',
'aio/content/guide/animation-transition-timing.md'
])
reviewers:
users:
@@ -152,13 +139,7 @@ groups:
contains_any_globs(files, [
'packages/compiler/**/{*,.*}',
'packages/examples/compiler/**/{*,.*}',
'aio/content/examples/angular-compiler-options/**/{*,.*}',
'packages/compiler-cli/**/{*,.*}',
'aio/content/guide/angular-compiler-options.md',
'aio/content/guide/aot-compiler.md',
'aio/content/guide/aot-metadata-errors.md',
'aio/content/guide/template-typecheck.md',
'aio/content/extended-diagnostics/*.md'
])
reviewers:
users:
@@ -200,155 +181,6 @@ groups:
'packages/examples/platform-browser/**/{*,.*}',
'packages/platform-browser-dynamic/**/{*,.*}',
'packages/docs/**/{*,.*}',
'aio/content/guide/accessibility.md',
'aio/content/examples/accessibility/**/{*,.*}',
'aio/content/guide/architecture-components.md',
'aio/content/guide/architecture-modules.md',
'aio/content/guide/architecture-next-steps.md',
'aio/content/guide/architecture-services.md',
'aio/content/guide/architecture.md',
'aio/content/examples/architecture/**/{*,.*}',
'aio/content/guide/rxjs-interop.md',
'aio/content/images/guide/architecture/**/{*,.*}',
'aio/content/guide/attribute-directives.md',
'aio/content/examples/attribute-directives/**/{*,.*}',
'aio/content/images/guide/attribute-directives/**/{*,.*}',
'aio/content/guide/bootstrapping.md',
'aio/content/examples/bootstrapping/**/{*,.*}',
'aio/content/guide/change-detection.md',
'aio/content/guide/change-detection-zone-pollution.md',
'aio/content/guide/change-detection-slow-computations.md',
'aio/content/guide/change-detection-skipping-subtrees.md',
'aio/content/images/guide/change-detection/**/{*,.*}',
'aio/content/guide/class-binding.md',
'aio/content/guide/cheatsheet.md',
'aio/content/guide/component-interaction.md',
'aio/content/examples/component-interaction/**/{*,.*}',
'aio/content/images/guide/component-interaction/**/{*,.*}',
'aio/content/guide/component-overview.md',
'aio/content/errors/*.md',
'aio/content/examples/errors/**/{*,.*}',
'aio/content/examples/component-overview/**/{*,.*}',
'aio/content/guide/component-styles.md',
'aio/content/guide/developer-guide-overview.md',
'aio/content/guide/view-encapsulation.md',
'aio/content/examples/component-styles/**/{*,.*}',
'aio/content/examples/content-projection/**/{*,.*}',
'aio/content/guide/content-projection.md',
'aio/content/guide/creating-injectable-service.md',
'aio/content/guide/dependency-injection-overview.md',
'aio/content/guide/dependency-injection.md',
'aio/content/examples/dependency-injection/**/{*,.*}',
'aio/content/images/guide/dependency-injection/**/{*,.*}',
'aio/content/guide/dependency-injection-in-action.md',
'aio/content/examples/dependency-injection-in-action/**/{*,.*}',
'aio/content/images/guide/dependency-injection-in-action/**/{*,.*}',
'aio/content/guide/dependency-injection-navtree.md',
'aio/content/guide/dependency-injection-providers.md',
'aio/content/guide/dependency-injection-context.md',
'aio/content/guide/lightweight-injection-tokens.md',
'aio/content/guide/displaying-data.md',
'aio/content/examples/displaying-data/**/{*,.*}',
'aio/content/images/guide/displaying-data/**/{*,.*}',
'aio/content/guide/dynamic-component-loader.md',
'aio/content/examples/dynamic-component-loader/**/{*,.*}',
'aio/content/images/guide/dynamic-component-loader/**/{*,.*}',
'aio/content/guide/example-apps-list.md',
'aio/content/guide/feature-modules.md',
'aio/content/examples/feature-modules/**/{*,.*}',
'aio/content/images/guide/feature-modules/**/{*,.*}',
'aio/content/guide/frequent-ngmodules.md',
'aio/content/images/guide/frequent-ngmodules/**/{*,.*}',
'aio/content/guide/hierarchical-dependency-injection.md',
'aio/content/examples/hierarchical-dependency-injection/**/{*,.*}',
'aio/content/guide/image-directive.md',
'aio/content/guide/image-directive-setup.md',
'aio/content/examples/providers-viewproviders/**/{*,.*}',
'aio/content/examples/resolution-modifiers/**/{*,.*}',
'aio/content/guide/lazy-loading-ngmodules.md',
'aio/content/examples/lazy-loading-ngmodules/**/{*,.*}',
'aio/content/images/guide/lazy-loading-ngmodules/**/{*,.*}',
'aio/content/guide/lifecycle-hooks.md',
'aio/content/examples/lifecycle-hooks/**/{*,.*}',
'aio/content/images/guide/lifecycle-hooks/**/{*,.*}',
'aio/content/examples/ngcontainer/**/{*,.*}',
'aio/content/guide/ngmodules.md',
'aio/content/examples/ngmodules/**/{*,.*}',
'aio/content/guide/ngmodule-api.md',
'aio/content/guide/ngmodule-faq.md',
'aio/content/guide/ngmodule-vs-jsmodule.md',
'aio/content/guide/module-types.md',
'aio/content/guide/template-overview.md',
'aio/content/guide/template-syntax.md',
'aio/content/guide/built-in-template-functions.md',
'aio/content/examples/built-in-template-functions/**/{*,.*}',
'aio/content/guide/event-binding.md',
'aio/content/guide/event-binding-concepts.md',
'aio/content/examples/event-binding/**/{*,.*}',
'aio/content/guide/interpolation.md',
'aio/content/examples/interpolation/**/{*,.*}',
'aio/content/examples/template-syntax/**/{*,.*}',
'aio/content/images/guide/template-syntax/**/{*,.*}',
'aio/content/guide/binding-overview.md',
'aio/content/guide/binding-syntax.md',
'aio/content/examples/binding-syntax/**/{*,.*}',
'aio/content/guide/property-binding.md',
'aio/content/examples/property-binding/**/{*,.*}',
'aio/content/guide/property-binding-best-practices.md',
'aio/content/guide/attribute-binding.md',
'aio/content/examples/attribute-binding/**/{*,.*}',
'aio/content/guide/two-way-binding.md',
'aio/content/examples/two-way-binding/**/{*,.*}',
'aio/content/guide/built-in-directives.md',
'aio/content/guide/directive-composition-api.md',
'aio/content/examples/built-in-directives/**/{*,.*}',
'aio/content/images/guide/built-in-directives/**/{*,.*}',
'aio/content/guide/template-reference-variables.md',
'aio/content/examples/template-reference-variables/**/{*,.*}',
'aio/content/guide/inputs-outputs.md',
'aio/content/examples/inputs-outputs/**/{*,.*}',
'aio/content/images/guide/inputs-outputs/**/{*,.*}',
'aio/content/guide/understanding-template-expr-overview.md',
'aio/content/guide/template-expression-operators.md',
'aio/content/examples/template-expression-operators/**/{*,.*}',
'aio/content/guide/pipes.md',
'aio/content/guide/pipes-custom-data-trans.md',
'aio/content/guide/pipes-overview.md',
'aio/content/guide/pipe-precedence.md',
'aio/content/guide/pipes-transform-data.md',
'aio/content/guide/pipe-template.md',
'aio/content/examples/pipes/**/{*,.*}',
'aio/content/images/guide/pipes/**/{*,.*}',
'aio/content/guide/providers.md',
'aio/content/examples/providers/**/{*,.*}',
'aio/content/images/guide/providers/**/{*,.*}',
'aio/content/guide/signal-queries.md',
'aio/content/guide/singleton-services.md',
'aio/content/guide/signal-inputs.md',
'aio/content/guide/sharing-ngmodules.md',
'aio/content/guide/standalone-components.md',
'aio/content/guide/standalone-migration.md',
'aio/content/guide/structural-directives.md',
'aio/content/examples/structural-directives/**/{*,.*}',
'aio/content/guide/svg-in-templates.md',
'aio/content/guide/style-precedence.md',
'aio/content/images/guide/structural-directives/**/{*,.*}',
'aio/content/guide/template-statements.md',
'aio/content/guide/understanding-angular-overview.md',
'aio/content/guide/user-input.md',
'aio/content/examples/user-input/**/{*,.*}',
'aio/content/images/guide/user-input/**/{*,.*}',
'aio/content/guide/view-encapsulation.md',
'aio/content/examples/view-encapsulation/**/{*,.*}',
'aio/content/images/guide/view-encapsulation/**/{*,.*}',
'aio/content/special-elements/**/{*,.*}',
'aio/content/blocks/**/{*,.*}',
'aio/content/guide/hydration.md',
'aio/content/guide/defer.md',
'aio/content/guide/signals.md',
'aio/content/guide/control_flow.md',
'aio/content/guide/model-inputs.md',
'aio/content/examples/injection-token/**/{*,.*}',
])
reviewers:
users:
@@ -391,23 +223,6 @@ groups:
contains_any_globs(files, [
'packages/common/http/**/{*,.*}',
'packages/examples/http/**/{*,.*}',
'aio/content/guide/understanding-communicating-with-http.md',
'aio/content/guide/http-configure-http-url-parameters.md',
'aio/content/guide/http-handle-request-errors.md',
'aio/content/guide/http-intercept-requests-and-responses.md',
'aio/content/guide/http-interceptor-use-cases.md',
'aio/content/guide/http-make-jsonp-request.md',
'aio/content/guide/http-optimize-server-interaction.md',
'aio/content/guide/http-pass-metadata-to-interceptors.md',
'aio/content/guide/http-request-data-from-server.md',
'aio/content/guide/http-security-xsrf-protection.md',
'aio/content/guide/http-send-data-to-server.md',
'aio/content/guide/http-server-communication.md',
'aio/content/guide/http-setup-server-communication.md',
'aio/content/guide/http-test-requests.md',
'aio/content/guide/http-track-show-request-progress.md',
'aio/content/examples/http/**/{*,.*}',
'aio/content/images/guide/http/**/{*,.*}'
])
reviewers:
users:
@@ -427,9 +242,6 @@ groups:
- >
contains_any_globs(files, [
'packages/elements/**/{*,.*}',
'aio/content/examples/elements/**/{*,.*}',
'aio/content/images/guide/elements/**/{*,.*}',
'aio/content/guide/elements.md'
])
reviewers:
users:
@@ -451,22 +263,6 @@ groups:
contains_any_globs(files, [
'packages/forms/**/{*,.*}',
'packages/examples/forms/**/{*,.*}',
'aio/content/guide/forms.md',
'aio/content/examples/forms/**/{*,.*}',
'aio/content/images/guide/forms/**/{*,.*}',
'aio/content/guide/forms-overview.md',
'aio/content/examples/forms-overview/**/{*,.*}',
'aio/content/images/guide/forms-overview/**/{*,.*}',
'aio/content/guide/form-validation.md',
'aio/content/guide/typed-forms.md',
'aio/content/examples/form-validation/**/{*,.*}',
'aio/content/images/guide/form-validation/**/{*,.*}',
'aio/content/guide/dynamic-form.md',
'aio/content/examples/dynamic-form/**/{*,.*}',
'aio/content/images/guide/dynamic-form/**/{*,.*}',
'aio/content/guide/reactive-forms.md',
'aio/content/examples/reactive-forms/**/{*,.*}',
'aio/content/images/guide/reactive-forms/**/{*,.*}'
])
reviewers:
users:
@@ -495,21 +291,6 @@ groups:
'packages/compiler/src/render3/view/i18n/**/{*,.*}',
'packages/compiler-cli/src/extract_i18n.ts',
'packages/localize/**/{*,.*}',
'aio/content/guide/i18n-overview.md',
'aio/content/guide/i18n-common-overview.md',
'aio/content/guide/i18n-common-add-package.md',
'aio/content/guide/i18n-common-locale-id.md',
'aio/content/guide/i18n-common-format-data-locale.md',
'aio/content/guide/i18n-common-prepare.md',
'aio/content/guide/i18n-common-translation-files.md',
'aio/content/guide/i18n-common-merge.md',
'aio/content/guide/i18n-common-deploy.md',
'aio/content/guide/i18n-example.md',
'aio/content/guide/i18n-optional-overview.md',
'aio/content/guide/i18n-optional-manual-runtime-locale.md',
'aio/content/guide/i18n-optional-import-global-variants.md',
'aio/content/guide/i18n-optional-manage-marked-text.md',
'aio/content/examples/i18n/**/{*,.*}'
])
reviewers:
users:
@@ -525,9 +306,6 @@ groups:
- >
contains_any_globs(files, [
'packages/platform-server/**/{*,.*}',
'aio/content/guide/prerendering.md',
'aio/content/guide/ssr.md',
'aio/content/examples/ssr/**/{*,.*}',
])
reviewers:
users:
@@ -549,16 +327,6 @@ groups:
contains_any_globs(files, [
'packages/router/**/{*,.*}',
'packages/examples/router/**/{*,.*}',
'aio/content/guide/router.md',
'aio/content/guide/router-tutorial.md',
'aio/content/guide/router-tutorial-toh.md',
'aio/content/guide/routing-overview.md',
'aio/content/guide/router-reference.md',
'aio/content/examples/router-tutorial/**/{*,.*}',
'aio/content/examples/router/**/{*,.*}',
'aio/content/images/guide/router/**/{*,.*}',
'aio/content/guide/routing-with-urlmatcher.md',
'aio/content/examples/routing-with-urlmatcher/**/{*,.*}'
])
reviewers:
users:
@@ -575,15 +343,6 @@ groups:
contains_any_globs(files, [
'packages/service-worker/**/{*,.*}',
'packages/examples/service-worker/**/{*,.*}',
'aio/content/guide/service-worker-getting-started.md',
'aio/content/examples/service-worker-getting-started/**/{*,.*}',
'aio/content/guide/app-shell.md',
'aio/content/guide/service-worker-communications.md',
'aio/content/guide/service-worker-config.md',
'aio/content/guide/service-worker-devops.md',
'aio/content/guide/service-worker-intro.md',
'aio/content/guide/service-worker-notifications.md',
'aio/content/images/guide/service-worker/**/{*,.*}'
])
reviewers:
users:
@@ -600,17 +359,6 @@ groups:
'packages/upgrade/**/{*,.*}',
'packages/common/upgrade/**/{*,.*}',
'packages/examples/upgrade/**/{*,.*}',
'aio/content/guide/upgrade.md',
'aio/content/examples/upgrade-lazy-load-ajs/**/{*,.*}',
'aio/content/examples/upgrade-module/**/{*,.*}',
'aio/content/images/guide/upgrade/**/{*,.*}',
'aio/content/examples/upgrade-phonecat-1-typescript/**/{*,.*}',
'aio/content/examples/upgrade-phonecat-2-hybrid/**/{*,.*}',
'aio/content/examples/upgrade-phonecat-3-final/**/{*,.*}',
'aio/content/guide/upgrade-performance.md',
'aio/content/guide/upgrade-setup.md',
'aio/content/guide/ajs-quick-reference.md',
'aio/content/examples/ajs-quick-reference/**/{*,.*}'
])
reviewers:
users:
@@ -626,17 +374,6 @@ groups:
- >
contains_any_globs(files.exclude('packages/compiler-cli/*').exclude('packages/language-service/*').exclude('packages/service-worker/*'), [
'packages/**/testing/**/{*,.*}',
'aio/content/guide/testing.md',
'aio/content/guide/test-debugging.md',
'aio/content/guide/testing-attribute-directives.md',
'aio/content/guide/testing-code-coverage.md',
'aio/content/guide/testing-components-basics.md',
'aio/content/guide/testing-components-scenarios.md',
'aio/content/guide/testing-pipes.md',
'aio/content/guide/testing-services.md',
'aio/content/guide/testing-utility-apis.md',
'aio/content/examples/testing/**/{*,.*}',
'aio/content/images/guide/testing/**/{*,.*}'
])
reviewers:
users:
@@ -700,9 +437,6 @@ groups:
'packages/tsconfig-tsec-base.json',
'packages/tsec-exemption.json',
'tools/tsec.bzl',
'aio/content/guide/security.md',
'aio/content/examples/security/**/{*,.*}',
'aio/content/images/guide/security/**/{*,.*}',
])
reviewers:
users:
@@ -739,8 +473,6 @@ groups:
- >
contains_any_globs(files, [
'packages/language-service/**/{*,.*}',
'aio/content/guide/language-service.md',
'aio/content/images/guide/language-service/**/{*,.*}'
])
reviewers:
users:
@@ -756,7 +488,6 @@ groups:
- >
contains_any_globs(files, [
'packages/zone.js/**/{*,.*}',
'aio/content/guide/zone.md'
])
reviewers:
users:
@@ -815,106 +546,6 @@ groups:
- dylhunn
- thePunderWoman
- josephperrott
- pkozlowski-opensource
# =========================================================
# Docs: Contributors
# =========================================================
docs-contributors:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/content/marketing/contributors.json',
'aio/content/images/bios/**/{*,.*}',
])
reviewers:
users:
- MarkTechson
- mgechev
- twerske
# =========================================================
# Docs: Gettings Started & Tutorial
# =========================================================
docs-getting-started-and-tutorial:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/content/guide/setup-local.md',
'aio/content/images/guide/setup-local/**/{*,.*}',
'aio/content/tutorial/**/{*,.*}',
'aio/content/images/guide/toh/**/{*,.*}',
'aio/content/demos/first-app/**/{*,.*}',
'aio/content/examples/first-app-*/**/{*,.*}',
'aio/content/images/guide/faa/**/{*,.*}',
'aio/content/examples/toh-pt0/**/{*,.*}',
'aio/content/examples/toh-pt1/**/{*,.*}',
'aio/content/examples/toh-pt2/**/{*,.*}',
'aio/content/examples/toh-pt3/**/{*,.*}',
'aio/content/examples/toh-pt4/**/{*,.*}',
'aio/content/examples/toh-pt5/**/{*,.*}',
'aio/content/examples/toh-pt6/**/{*,.*}',
'aio/content/examples/getting-started-v0/**/{*,.*}',
'aio/content/examples/getting-started/**/{*,.*}',
'aio/content/start/**/{*,.*}',
'aio/content/guide/quick-start.md',
'aio/content/images/guide/start/**/{*,.*}',
'aio/content/examples/what-is-angular/**/{*,.*}',
'aio/content/guide/what-is-angular.md'
])
reviewers:
users:
- AndrewKushnir
- thePunderWoman
# =========================================================
# Docs: Marketing
# =========================================================
docs-marketing:
<<: *defaults
conditions:
- >
contains_any_globs(files.exclude("aio/content/marketing/contributors.json"), [
'aio/content/examples/marketing-first-app/**/{*,.*}',
'aio/content/guide/roadmap.md',
'aio/content/marketing/**/{*,.*}',
'aio/content/images/marketing/**/{*,.*}',
'aio/content/file-not-found.md',
'aio/content/license.md',
'aio/content/navigation.json'
])
reviewers:
users:
- MarkTechson
- mgechev
- twerske
# =========================================================
# Docs: Observables
# =========================================================
docs-observables:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/content/guide/observables.md',
'aio/content/examples/observables/**/{*,.*}',
'aio/content/guide/comparing-observables.md',
'aio/content/examples/comparing-observables/**/{*,.*}',
'aio/content/guide/observables-in-angular.md',
'aio/content/examples/observables-in-angular/**/{*,.*}',
'aio/content/guide/practical-observable-usage.md',
'aio/content/examples/practical-observable-usage/**/{*,.*}',
'aio/content/guide/rx-library.md',
'aio/content/examples/rx-library/**/{*,.*}'
])
reviewers:
users:
- alxhub
- atscott
- dylhunn
# =========================================================
# Docs: Packaging, Tooling, Releasing
@@ -925,20 +556,6 @@ groups:
- >
contains_any_globs(files, [
'contributing-docs/public-api-surface.md',
'aio/content/guide/npm-packages.md',
'aio/content/guide/browser-support.md',
'aio/content/guide/releases.md',
'aio/content/guide/updating.md',
'aio/content/guide/deprecations.md',
'aio/content/examples/deprecation-guide/**/{*,.*}',
'aio/content/guide/migration-module-with-providers.md',
'aio/content/guide/static-query-migration.md',
'aio/content/guide/update-to-latest-version.md',
'aio/content/guide/versions.md',
'aio/content/guide/update-to-version-14.md',
'aio/content/guide/update-to-version-15.md',
'aio/content/guide/update-to-version-16.md',
'aio/content/guide/update-to-version-17.md',
])
reviewers:
users:
@@ -948,23 +565,6 @@ groups:
- thePunderWoman
- jelbourn
# =========================================================
# Docs: Angular DevTools
# =========================================================
docs-devtools:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/content/guide/devtools.md',
'aio/content/images/guide/devtools/**/{*,.*}'
])
reviewers:
users:
- MarkTechson
- mgechev
- twerske
# =========================================================
# Tooling: Compiler API shared with Angular CLI
#
@@ -988,80 +588,6 @@ groups:
required: 2 # require at least 2 approvals
reviewed_for: required
# =========================================================
# Docs: CLI
# =========================================================
docs-cli:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/content/cli/**/{*,.*}',
'aio/content/guide/typescript-configuration.md',
'aio/content/examples/setup/**/{*,.*}',
'aio/content/guide/build.md',
'aio/content/images/guide/build/**/{*,.*}',
'aio/content/images/guide/cli/**/{*,.*}',
'aio/content/guide/cli-builder.md',
'aio/content/examples/cli-builder/**/{*,.*}',
'aio/content/guide/deployment.md',
'aio/content/images/guide/deployment/**/{*,.*}',
'aio/content/guide/file-structure.md',
'aio/content/guide/ivy.md',
'aio/content/guide/strict-mode.md',
'aio/content/guide/web-worker.md',
'aio/content/guide/workspace-config.md',
'aio/content/guide/migration-solution-style-tsconfig.md',
'aio/content/guide/migration-update-libraries-tslib.md',
'aio/content/guide/esbuild.md',
])
reviewers:
users:
- alan-agius4
- clydin
- dgp1130
- mgechev
# =========================================================
# Docs: CLI Libraries
# =========================================================
docs-libraries:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/content/examples/angular-linker-plugin/webpack.config.mjs',
'aio/content/guide/creating-libraries.md',
'aio/content/guide/libraries.md',
'aio/content/guide/using-libraries.md',
'aio/content/guide/angular-package-format.md'
])
reviewers:
users:
- alan-agius4
- alxhub
- mgechev
# =========================================================
# Docs: Schematics
# =========================================================
docs-schematics:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/content/guide/schematics.md',
'aio/content/guide/schematics-authoring.md',
'aio/content/guide/schematics-for-libraries.md',
'aio/content/images/guide/schematics/**/{*,.*}',
'aio/content/examples/schematics-for-libraries/**/{*,.*}'
])
reviewers:
users:
- alan-agius4
- dylhunn
- mgechev
# =========================================================
# Docs: Angular Dev Site
# =========================================================
@@ -1087,65 +613,6 @@ groups:
- pkozlowski-opensource
- ~JeanMeche
# =========================================================
# Docs-infra
# =========================================================
docs-infra:
<<: *defaults
conditions:
- >
contains_any_globs(files, [
'aio/{*,.*}',
'aio/aio-builds-setup/**/{*,.*}',
'aio/content/cli-src/**/{*,.*}',
'aio/content/examples/{*,.*}',
'aio/scripts/**/{*,.*}',
'aio/src/**/{*,.*}',
'aio/tests/**/{*,.*}',
'aio/tools/**/{*,.*}',
'aio/tools/examples/shared/boilerplate/cli/.vscode/**/{*,.*}',
'aio/content/BUILD.bazel',
'aio/content/images/guide/contributors-guide/**/{*,.*}',
'aio/content/guide/contributors-guide-overview.md',
'aio/content/guide/docs-style-guide.md',
'aio/content/examples/docs-style-guide/**/{*,.*}',
'aio/content/images/guide/docs-style-guide/**/{*,.*}',
'aio/content/guide/docs-lint-errors.md',
'aio/content/images/guide/docs-lint-errors/**/{*,.*}',
'aio/content/guide/localized-documentation.md',
'aio/content/guide/localizing-angular.md',
'aio/content/guide/reviewing-content.md',
'aio/content/guide/updating-content-github-ui.md',
'aio/content/guide/updating-search-keywords.md',
'aio/content/guide/doc-build-test.md',
'aio/content/guide/doc-edit-finish.md',
'aio/content/guide/doc-editing.md',
'aio/content/guide/doc-github-tasks.md',
'aio/content/guide/doc-pr-open.md',
'aio/content/guide/doc-pr-prep.md',
'aio/content/guide/doc-pr-update.md',
'aio/content/guide/doc-prepare-to-edit.md',
'aio/content/guide/doc-select-issue.md',
'aio/content/guide/doc-tasks.md',
'aio/content/guide/doc-update-overview.md',
'aio/content/guide/doc-update-start.md',
'aio/content/guide/docs-lint-errors.md',
'aio/content/images/guide/preparing-to-edit-docs/**/{*,.*}',
'aio/content/images/guide/github-for-docs/**/{*,.*}',
'aio/content/images/guide/doc-update-start/**/{*,.*}',
'aio/content/images/guide/doc-update-overview/**/{*,.*}',
'aio/content/images/guide/doc-pr-update/**/{*,.*}',
'aio/content/images/guide/doc-pr-prep/**/{*,.*}',
'aio/content/images/guide/doc-pr-open/**/{*,.*}',
'aio/content/images/guide/doc-github-tasks/**/{*,.*}',
'aio/content/images/guide/doc-prepare-to-edit/**/{*,.*}',
])
reviewers:
users:
- AndrewKushnir
- thePunderWoman
- josephperrott
# =========================================================
# Angular DevTools
# =========================================================
@@ -1228,11 +695,6 @@ groups:
- >
contains_any_globs(files.exclude("goldens/public-api/manage.js"), [
'goldens/public-api/**/{*,.*}',
'aio/content/guide/angular-package-format.md',
'aio/content/guide/glossary.md',
'aio/content/guide/styleguide.md',
'aio/content/examples/styleguide/**/{*,.*}',
'aio/content/images/guide/styleguide/{*,.*}'
])
reviewers:
users:
-2
View File
@@ -12,14 +12,12 @@
"**/node_modules/**": true,
"**/bazel-out/**": true,
"**/dist/**": true,
"**/aio/src/generated/**": true,
},
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
"**/bazel-out": true,
"**/dist": true,
"**/aio/src/generated": true,
".history": true,
},
"git.ignoreLimitWarning": true,
-1
View File
@@ -67,7 +67,6 @@ nodejs_binary(
data = [".yarn/releases/yarn-1.22.19.cjs"],
entry_point = ".yarn/releases/yarn-1.22.19.cjs",
visibility = [
"//aio/tools/examples/shared:__pkg__",
"//integration:__subpackages__",
],
)
+1 -1
View File
@@ -302,7 +302,7 @@ There are currently a few exceptions to the "use package name" rule:
* `dev-infra`: used for dev-infra related changes within the directories /scripts and /tools
* `docs-infra`: used for docs-app (angular.io) related changes within the /aio directory of the repo
* `docs-infra`: used for docs-app (angular.dev) related changes within the /adev directory of the repo
* `migrations`: used for changes to the `ng update` migrations.
-24
View File
@@ -94,30 +94,6 @@ yarn_install(
yarn_lock = "//:yarn.lock",
)
yarn_install(
name = "aio_example_deps",
# Rename the default js_library target from "node_modules" as this obscures the
# the source directory stamped as a filegroup in the manual BUILD contents below.
all_node_modules_target_name = "node_modules_all",
data = [
YARN_LABEL,
"//:.yarnrc",
],
# Disabled because, when False, yarn_install preserves the node_modules folder
# with bin symlinks in the external repository. This is needed to link the shared
# set of deps for example e2es.
exports_directories_only = False,
manual_build_file_contents = """\
filegroup(
name = "node_modules_files",
srcs = ["node_modules"],
)
""",
package_json = "//aio/tools/examples/shared:package.json",
yarn = YARN_LABEL,
yarn_lock = "//aio/tools/examples/shared:yarn.lock",
)
load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies")
aspect_bazel_lib_dependencies()
+1 -1
View File
@@ -130,7 +130,7 @@ function httpGet(url, options = {}) {
] = `token ${process.env.ANGULAR_CLI_BUILDS_READONLY_GITHUB_TOKEN}`;
// User agent is required
// https://docs.github.com/en/rest/overview/resources-in-the-rest-api?apiVersion=2022-11-28#user-agent-required
options.headers['User-Agent'] = `AIO_Angular_CLI_Sources_Update`;
options.headers['User-Agent'] = `ADEV_Angular_CLI_Sources_Update`;
return new Promise((resolve, reject) => {
get(url, options, (res) => {
@@ -1,8 +1,7 @@
/*
* This example project is special in that it is not a cli app. To run tests appropriate for this
* project, the test command is overwritten in `aio/content/examples/injection-token/example-config.json`.
* This example project is special in that it is not a cli app.
*
* This is an empty placeholder file to ensure that `aio/tools/examples/run-example-e2e.mjs` runs
* This is an empty placeholder file to ensure that example tests correctly runs
* tests for this project.
*
* TODO: Fix our infrastructure/tooling, so that this hack is not necessary.
-1
View File
@@ -2,7 +2,6 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
package(default_visibility = [
"//adev:__subpackages__",
"//aio:__subpackages__",
])
js_library(
-51
View File
@@ -1,51 +0,0 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
/tools/examples/shared/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
/.firebase/
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
firebase-debug.log
testem.log
/typings
# e2e
protractor-results*.txt
# Example playground
content/example-playground
# System files
.DS_Store
Thumbs.db
-392
View File
@@ -1,392 +0,0 @@
load("@npm//@angular-devkit/architect-cli:index.bzl", "architect", "architect_test")
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin", "npm_package_bin")
load("//tools:defaults.bzl", "nodejs_binary")
load("@aspect_bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory")
load(":local_packages_util.bzl", "link_local_packages", "substitute_local_package_deps")
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag", "string_flag")
load("//aio/scripts:local_server_test.bzl", "local_server_test")
load("@npm//@angular/build-tooling/bazel/remote-execution:index.bzl", "ENABLE_NETWORK")
load(":aio_targets.bzl", "aio_test")
load("@bazel_skylib//lib:collections.bzl", "collections")
exports_files([
"firebase.json",
"ngsw-config.json",
"ngsw-config.template.json",
"tsconfig.json",
])
# If set will use first party angular deps for aio targets instead of their npm equivalent
bool_flag(
name = "flag_aio_local_deps",
build_setting_default = False,
)
config_setting(
name = "aio_local_deps",
flag_values = {
":flag_aio_local_deps": "true",
},
)
# Config setting controlling the AIO architect configuration to build with
string_flag(
name = "flag_aio_build_config",
build_setting_default = "stable",
values = [
"stable",
"rc",
"next",
"archive",
],
)
config_setting(
name = "aio_build_config_stable",
flag_values = {
":flag_aio_build_config": "stable",
},
)
config_setting(
name = "aio_build_config_rc",
flag_values = {
":flag_aio_build_config": "rc",
},
)
config_setting(
name = "aio_build_config_next",
flag_values = {
":flag_aio_build_config": "next",
},
)
config_setting(
name = "aio_build_config_archive",
flag_values = {
":flag_aio_build_config": "archive",
},
)
# Run dgeni generation
npm_package_bin(
name = "dgeni",
# angular.io-package is a js_library target, which copies sources to $(BINDIR)
args = ["./$(BINDIR)/aio/tools/transforms/angular.io-package"],
data = [
"//aio/tools/transforms/angular.io-package",
# Dgeni typescript package crawls type definitions for Angular dependencies
"@npm//rxjs",
"@npm//@types/node",
],
env = {
"BAZEL_DGENI_OUTPUT_PATH": "$(@D)",
"GIT_BIN": "$(GIT_BIN_PATH)",
},
exec_properties = ENABLE_NETWORK,
output_dir = True,
stamp = "@rules_nodejs//nodejs/stamp:use_stamp_flag",
# Makes remote git calls to get previous versions
tags = [
"requires-network",
],
tool = "@npm//dgeni/bin:dgeni",
toolchains = [
"@npm//@angular/build-tooling/bazel/git-toolchain:current_git_toolchain",
],
visibility = ["//aio/tests/deployment:__subpackages__"],
)
# Copy stackblitz live examples to expected assets location
copy_to_directory(
name = "stackblitz",
srcs = ["//aio/content/examples:all-stackblitz"],
replace_prefixes = {
"examples": "generated/live-examples",
},
root_paths = [
"aio/content",
],
)
# Copy example zips to expected assets location
copy_to_directory(
name = "example-zips",
srcs = ["//aio/content/examples:all-example-zips"],
replace_prefixes = {
"examples": "generated/zips",
},
root_paths = [
"aio/content",
],
)
# All source and configuration files required to build the docs app
APPLICATION_FILES = [
"angular.json",
"tsconfig.app.json",
"tsconfig.json",
"tsconfig.worker.json",
"security-exemptions.json",
"//aio/src/assets",
"//aio/src/assets/js",
] + glob(
["src/**/*"],
exclude = [
"src/**/*.spec.ts",
# Temporarily exclude generated sources produced by the non-bazel
# build until the whole project is built by bazel and this directory
# isn't needed.
"src/generated/**/*",
],
)
# Dependencies required to build the docs app.
APPLICATION_DEPS = [
":dgeni",
":stackblitz",
":example-zips",
"//aio/src/generated:ngsw-config",
"@npm//@angular-devkit/build-angular",
"@npm//@angular-eslint/builder",
"@npm//@angular/animations",
"@npm//@angular/cdk",
"@npm//@angular/cli",
"@npm//@angular/common",
"@npm//@angular/compiler",
"@npm//@angular/compiler-cli",
"@npm//@angular/core",
"@npm//@angular/elements",
"@npm//@angular/forms",
"@npm//@angular/material",
"@npm//@angular/platform-browser",
"@npm//@angular/platform-browser-dynamic",
"@npm//@angular/router",
"@npm//@angular/service-worker",
"@npm//@types/lunr",
"@npm//@types/trusted-types",
"@npm//lunr",
"@npm//rxjs",
"@npm//safevalues",
"@npm//tslib",
"@npm//zone.js",
]
# All sources, specs, and config files required to test the docs app
TEST_FILES = APPLICATION_FILES + [
"karma.conf.js",
"tsconfig.spec.json",
] + glob(
["src/**/*.spec.ts"],
)
# Dependencies required to test the docs app
TEST_DEPS = APPLICATION_DEPS + [
"@npm//@angular/build-tooling/bazel/browsers/chromium",
"@npm//@types/jasmine",
"@npm//@types/node",
"@npm//assert",
"@npm//jasmine",
"@npm//jasmine-core",
"@npm//karma-chrome-launcher",
"@npm//karma-coverage",
"@npm//karma-jasmine",
"@npm//karma-jasmine-html-reporter",
"//adev/tools:windows-chromium-path",
]
# All sources, specs, and config files required to serve the app
# and run e2e tests against it
E2E_FILES = APPLICATION_FILES + glob(["tests/e2e/**"])
# Dependencies required to run the e2e tests
E2E_DEPS = APPLICATION_DEPS + [
"@npm//@angular/build-tooling/bazel/browsers/chromium",
"@npm//@types/jasmine",
"@npm//@types/node",
"@npm//jasmine-spec-reporter",
"@npm//protractor",
"@npm//ts-node",
"//adev/tools:windows-chromium-path",
]
# Poll period for architect rules that watch for changes
ARCHITECT_POLL_MS = 1000
# Stamp npm_link targets for all dependencies that correspond to a
# first-party equivalent pacakge in angular.
link_local_packages(all_aio_deps = collections.uniq(APPLICATION_DEPS + TEST_DEPS + E2E_DEPS))
copy_to_bin(
name = "application_files_bin",
srcs = APPLICATION_FILES,
)
architect(
name = "build-app",
args = select({
":aio_build_config_stable": ["site:build:stable"],
":aio_build_config_next": ["site:build:next"],
":aio_build_config_rc": ["site:build:rc"],
":aio_build_config_archive": ["site:build:archive"],
}) + [
"--output-path=build-app",
],
chdir = "$(RULEDIR)",
data = [":application_files_bin"] + select({
":aio_local_deps": substitute_local_package_deps(APPLICATION_DEPS),
"//conditions:default": APPLICATION_DEPS,
}),
output_dir = True,
# When building with local packages (--config=aio_local_deps), RBE complains about
# the input tree being too large (> 70,000 files).
tags = ["no-remote-exec"],
)
npm_package_bin(
name = "404-page",
outs = ["404.html"],
args = [
"$(execpath src/404-body.html)",
"$(execpath :build-app)",
"$@",
],
data = [
"src/404-body.html",
":build-app",
],
tool = "//aio/scripts:build-404-page",
)
# Prepare the final build artifact which substitutes a generated 404 page
# into the architect output.
copy_to_directory(
name = "build",
srcs = [
":404-page",
":build-app",
],
replace_prefixes = {
"build-app": "",
},
visibility = ["//aio/scripts/deploy-to-firebase:__pkg__"],
)
TEST_DATA = TEST_FILES + select({
":aio_local_deps": substitute_local_package_deps(TEST_DEPS),
"//conditions:default": TEST_DEPS,
})
aio_test(
name = "test",
args = [
"site:test",
"--no-watch",
],
data = TEST_DATA,
)
aio_test(
name = "test-and-watch",
args = [
"site:test",
"--watch",
"--poll=%d" % ARCHITECT_POLL_MS,
],
data = TEST_DATA,
tags = [
"ibazel_notify_changes",
"manual",
],
)
architect_test(
name = "e2e",
size = "large",
args = [
"site:e2e",
"--no-webdriver-update",
"--port=0",
],
chdir = package_name(),
data = E2E_FILES + select({
":aio_local_deps": substitute_local_package_deps(E2E_DEPS),
"//conditions:default": E2E_DEPS,
}),
env = {
"CHROME_BIN": "../$(CHROMIUM)",
"CHROMEDRIVER_BIN": "../$(CHROMEDRIVER)",
},
# TODO: investigate why those tests became more flaky
# (presumably after AIO migration to Bazel)
flaky = True,
toolchains = [
"@npm//@angular/build-tooling/bazel/browsers/chromium:toolchain_alias",
],
)
# Build and serve the app. Run with ibazel to watch for changes and re-serve.
architect(
name = "serve",
args = [
"site:serve",
"--open",
"--poll=%d" % ARCHITECT_POLL_MS,
"--live-reload",
"--watch",
],
chdir = package_name(),
data = APPLICATION_FILES + select({
":aio_local_deps": substitute_local_package_deps(APPLICATION_DEPS),
"//conditions:default": APPLICATION_DEPS,
}),
tags = ["ibazel_notify_changes"],
)
# Build and serve the app, watch for changes, and run a fast but low-fidelity
# rebuild when docs change. Watching and serving is a part of the node script,
# so there is no need to run with ibazel, which would be slow as it would redo
# the full dgeni build on each change.
nodejs_binary(
name = "docs-watch",
chdir = package_name(),
data = APPLICATION_FILES + [
"//aio/scripts:fast-serve-and-watch",
] + select({
":aio_local_deps": substitute_local_package_deps(APPLICATION_DEPS),
"//conditions:default": APPLICATION_DEPS,
}),
enable_linker = True,
entry_point = "//aio/scripts:fast-serve-and-watch.js",
env = {
# Have the authors package output its low-fi dgeni build
# to a different directory in the runfiles tree because bazel
# write-protects original dgeni runfiles. Then in angular.json
# we list this folder last under assets so that it will
# take precedence over the original dgeni assets, effectively
# overwriting select sources and then serving them.
"BAZEL_DGENI_OUTPUT_PATH": "dgeni-fast",
},
)
local_server_test(
name = "test-a11y-score-localhost",
args = ["LOCALHOST_URL"],
entry_point = "//aio/scripts:test-aio-a11y",
serve_target = ":build",
)
local_server_test(
name = "test-pwa-score-localhost",
args = [
"LOCALHOST_URL",
"all:0,pwa:100",
],
data = [
"//aio/scripts:audit-web-app",
],
entry_point = "//aio/scripts:audit-web-app-script",
serve_target = ":build",
)
-16
View File
@@ -1,16 +0,0 @@
load("@npm//@angular-devkit/architect-cli:index.bzl", "architect_test")
def aio_test(name, data, args, **kwargs):
architect_test(
name = name,
args = args,
chdir = native.package_name(),
data = data,
env = {
"CHROME_BIN": "../$(CHROMIUM)",
},
toolchains = [
"@npm//@angular/build-tooling/bazel/browsers/chromium:toolchain_alias",
],
**kwargs
)
-11
View File
@@ -1,11 +0,0 @@
package(default_visibility = ["//visibility:public"])
filegroup(
name = "content",
srcs = glob(
["**"],
exclude = [
"BUILD.bazel",
],
),
)
-58
View File
@@ -1,58 +0,0 @@
A type of [block](api/core/defer) that can be used to defer load the JavaScript for components, directives and pipes used inside a component template.
@syntax
```html
@defer ( on <trigger>; when <condition>; prefetch on <trigger>; prefetch when <condition> ) {
<!-- deferred template fragment -->
<calendar-cmp />
} @placeholder ( minimum? <duration> ) {
<!-- placeholder template fragment -->
<p>Placeholder</p>
} @loading ( minimum? <duration>; after? <duration> ) {
<!-- loading template fragment -->
<img alt="loading image" src="loading.gif" />
} @error {
<!-- error template fragment -->
<p>An loading error occurred</p>
}
```
@description
<h3>Blocks</h3>
Supported sections of a defer block. Note: only the @defer block template fragment is deferred loaded. The remaining optional blocks are eagerly loaded.
| block | Description |
| ----------- | ----------- |
| `@defer` | The defer loaded block of content |
| `@placeholder` | Content shown prior to defer loading (Optional)|
| `@loading` | Content shown during defer loading (Optional) |
| `@error` | Content shown when defer loading errors occur (Optional) |
<h3>Triggers</h3>
Triggers provide conditions for when defer loading occurs. Some allow a template reference variable as an optional parameter. Separate multiple triggers with a semicolon.
| trigger | Triggers... |
| ----------- | ----------- |
| `on idle` | when the browser reports idle state (default) |
| `on viewport(<elementRef>?)` | when the element enters the viewport |
| `on interaction(<elementRef>?)` | when clicked, touched, or focused |
| `on hover(<elementRef>?)` | when element has been hovered |
| `on immediate` | when the page finishes rendering |
| `on timer(<duration>)` | after a specific timeout |
| `when <condition>` | on a custom condition |
<h2>Prefetch</h2>
Configures prefetching of the defer block used in the `@defer` parameters, but does not affect rendering. Rendering is handled by the standard `on` and `when` conditions. Separate multiple prefetch configurations with a semicolon.
```html
@defer (prefetch on <trigger>; prefetch when <condition>) {
<!-- deferred template fragment -->
}
```
Learn more in the [defer loading guide](guide/defer).
-58
View File
@@ -1,58 +0,0 @@
The `@for` block repeatedly renders content of a block for each item in a collection.
@syntax
```html
@for (item of items; track item.name) {
<li>{{ item.name }}</li>
} @empty {
<li>There are no items.</li>
}
```
@description
The `@for` block renders its content in response to changes in a collection. Collections can be any
JavaScript [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols),
but there are performance advantages of using a regular `Array`.
You can optionally include an `@empty` section immediately after the `@for` block content. The
content of the `@empty` block displays when there are no items.
<h3> track and objects identity </h3>
The value of the `track` expression determines a key used to associate array items with the views in
the DOM. Having clear indication of the item identity allows Angular to execute a minimal set of DOM
operations as items are added, removed or moved in a collection.
To optimize performance, especially in loops over immutable data, ensure the track expression is effectively used to
identify each item uniquely. Because of the potential for poor performance, the `track` expression
is required for the `@for` loops.
For collections that remain static , `track $index` provides a straightforward tracking mechanism. For dynamic
collections experiencing additions, deletions, or reordering, opt for a
unique property of each item as the tracking key.
<h3> `$index` and other contextual variables </h3>
Inside `@for` contents, several implicit variables are always available:
| Variable | Meaning |
|----------|-----------------------------------------------|
| `$count` | Number of items in a collection iterated over |
| `$index` | Index of the current row |
| `$first` | Whether the current row is the first row |
| `$last` | Whether the current row is the last row |
| `$even` | Whether the current row index is even |
| `$odd` | Whether the current row index is odd |
These variables are always available with these names, but can be aliased via a `let` segment:
```html
@for (item of items; track item.id; let idx = $index, e = $even) {
Item #{{ idx }}: {{ item.name }}
}
```
The aliasing is especially useful in case of using nested `@for` blocks where contextual variable
names could collide.
-25
View File
@@ -1,25 +0,0 @@
The `@if` block conditionally displays its content when its condition expression is truthy.
@syntax
```html
@if (a > b) {
{{a}} is greater than {{b}}
} @else if (b > a) {
{{a}} is less than {{b}}
} @else {
{{a}} is equal to {{b}}
}
```
@description
Content is added and removed from the DOM based on the evaluation of conditional expressions in the `@if` and `@else` blocks.
The built-in `@if` supports referencing of expression results to keep a solution for common coding patterns:
```html
@if (users$ | async; as users) {
{{ users.length }}
}
```
-25
View File
@@ -1,25 +0,0 @@
The `@switch` block is inspired by the JavaScript `switch` statement:
@syntax
```html
@switch (condition) {
@case (caseA) {
Case A.
}
@case (caseB) {
Case B.
}
@default {
Default case.
}
}
```
@description
The `@switch` blocks displays content selected by one of the cases matching against the conditional expression. The value of the conditional expression is compared to the case expression using the `===` operator.
The `@default` block is optional and can be omitted. If no `@case` matches the expression and there is no `@default` block, nothing is shown.
**`@switch` does not have fallthrough**, so you do not need an equivalent to a `break` or `return` statement.
-44
View File
@@ -1,44 +0,0 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# git should ignore the cached files
.angular
node_modules
# Compiled output
/dist
/tmp
/out-tsc
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db
-109
View File
@@ -1,109 +0,0 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"addOneButton": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": {},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/addOneButton",
"index": "src/index.html",
"main": "src/main.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
],
"scripts": [],
"polyfills": [
"zone.js"
]
},
"configurations": {
"production": {
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"buildTarget": "addOneButton:build"
},
"configurations": {
"production": {
"buildTarget": "addOneButton:build:production"
},
"development": {
"buildTarget": "addOneButton:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "addOneButton:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": [
],
"scripts": [],
"assets": [
"src/favicon.ico",
"src/assets"
],
"polyfills": [
"zone.js",
"zone.js/testing"
]
}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
}
}
}
},
"defaultProject": "addOneButton",
"cli": {
"analytics": false
}
}
-44
View File
@@ -1,44 +0,0 @@
{
"name": "angular",
"version": "0.0.0",
"private": true,
"dependencies": {
"@angular/common": "^16.0.0",
"@angular/compiler": "^16.0.0",
"@angular/core": "^16.0.0",
"@angular/platform-browser": "^16.0.0",
"rxjs": "^7.8.0",
"tslib": "^2.5.3",
"zone.js": "^0.13.0"
},
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"devDependencies": {
"@angular-devkit/build-angular": "^16.0.0",
"@angular-eslint/builder": "16.0.3",
"@angular-eslint/eslint-plugin": "16.0.3",
"@angular-eslint/eslint-plugin-template": "16.0.3",
"@angular-eslint/schematics": "16.0.3",
"@angular-eslint/template-parser": "16.0.3",
"@angular/cli": "^16.0.0",
"@angular/compiler-cli": "^16.0.0",
"@types/jasmine": "~4.3.0",
"@typescript-eslint/eslint-plugin": "5.59.7",
"@typescript-eslint/parser": "5.59.7",
"eslint": "^8.40.0",
"jasmine-core": "~4.5.0",
"jasmine-spec-reporter": "~7.0.0",
"karma": "~6.4.1",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "^2.0.0",
"typescript": "~5.0.0"
}
}
@@ -1,9 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Your first Angular app</title>
</head>
<body>
<add-one-button>Loading...</add-one-button>
</body>
</html>
@@ -1,32 +0,0 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, './coverage/my-app'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};
-21
View File
@@ -1,21 +0,0 @@
// import required packages
import 'zone.js';
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
// describe component
@Component({
selector: 'add-one-button', // component name used in markup
standalone: true, // component is self-contained
template: // the component's markup
`
<button (click)="count = count + 1">Add one</button> {{ count }}
`,
})
// export component
export class AddOneButtonComponent {
count = 0;
}
bootstrapApplication(AddOneButtonComponent);
@@ -1 +0,0 @@
/* Add application styles & imports to this file! */
@@ -1,13 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"types": []
},
"files": [
"main.ts"
],
"include": [
"**/*.d.ts"
]
}
@@ -1,17 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/spec",
"types": [
"jasmine",
"node"
]
},
"files": [
"test.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}
-27
View File
@@ -1,27 +0,0 @@
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"target": "es2022",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2018",
"dom"
]
},
"angularCompilerOptions": {
"disableTypeScriptVersionCheck": true,
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}
}
File diff suppressed because it is too large Load Diff
-30
View File
@@ -1,30 +0,0 @@
@name Expression Changed After Checked
@category runtime
@videoUrl https://www.youtube.com/embed/O47uUnJjbJc
@shortDescription Expression has changed after it was checked
@description
Angular throws an `ExpressionChangedAfterItHasBeenCheckedError` when an expression value has been changed after change detection has completed. Angular only throws this error in development mode.
In development mode, Angular performs an additional check after each change detection run, to ensure the bindings haven't changed. This catches errors where the view is left in an inconsistent state. This can occur, for example, if a method or getter returns a different value each time it is called, or if a child component changes values on its parent. If either of these occurs, this is a sign that change detection is not stabilized. Angular throws the error to ensure data is always reflected correctly in the view, which prevents erratic UI behavior or a possible infinite loop.
This error commonly occurs when you've added template expressions or have begun to implement lifecycle hooks like `ngAfterViewInit` or `ngOnChanges`. It is also common when dealing with loading status and asynchronous operations, or when a child component changes its parent bindings.
@debugging
The [source maps](https://developer.mozilla.org/docs/Tools/Debugger/How_to/Use_a_source_map) generated by the CLI are very useful when debugging. Navigate up the call stack until you find a template expression where the value displayed in the error has changed.
Ensure that there are no changes to the bindings in the template after change detection is run. This often means refactoring to use the correct [component lifecycle hook](guide/lifecycle-hooks) for your use case. If the issue exists within `ngAfterViewInit`, the recommended solution is to use a constructor or `ngOnInit` to set initial values, or use `ngAfterContentInit` for other value bindings.
If you are binding to methods in the view, ensure that the invocation does not update any of the other bindings in the template.
Read more about which solution is right for you in ['Everything you need to know about the "ExpressionChangedAfterItHasBeenCheckedError" error'](https://indepth.dev/posts/1001/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error) and why this is useful at ['Angular Debugging "Expression has changed after it was checked": Simple Explanation (and Fix)'](https://blog.angular-university.io/angular-debugging).
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
-30
View File
@@ -1,30 +0,0 @@
@name Wrong Async Validator Return Type
@category runtime
@shortDescription Async validator must return a Promise or Observable
@description
Async validators must return a promise or an observable, and emit/resolve them whether the validation fails or succeeds. In particular, they must implement the [AsyncValidatorFn API](api/forms/AsyncValidator)
```typescript
export function isTenAsync(control: AbstractControl):
Observable<ValidationErrors | null> {
const v: number = control.value;
if (v !== 10) {
// Emit an object with a validation error.
return of({ 'notTen': true, 'requiredValue': 10 });
}
// Emit null, to indicate no error occurred.
return of(null);
}
```
@debugging
Did you mistakenly use a synchronous validator instead of an async validator?
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-06-28
-28
View File
@@ -1,28 +0,0 @@
@name Missing value accessor
@category runtime
@shortDescription You must register an `NgValueAccessor` with a custom form control
@description
For all custom form controls, you must register a value accessor.
Here's an example of how to provide one:
```typescript
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MyInputField),
multi: true,
}
]
```
@debugging
As described above, your control was expected to have a value accessor, but was missing one. However, there are many different reasons this can happen in practice. Here's a listing of some known problems leading to this error.
1. If you **defined** a custom form control, did you remember to provide a value accessor?
1. Did you put `ngModel` on an element with no value, or an **invalid element** (e.g. `<div [(ngModel)]="foo">`)?
1. Are you using a custom form control declared inside an `NgModule`? if so, make sure you are **importing** the `NgModule`.
1. Are you using `ngModel` with a third-party custom form control? Check whether that control provides a value accessor. If not, use **`ngDefaultControl`** on the control's element.
1. Are you **testing** a custom form control? Be sure to configure your testbed to know about the control. You can do so with `Testbed.configureTestingModule`.
1. Are you using **Nx and Module Federation** with Webpack? Your `webpack.config.js` may require [extra configuration](https://github.com/angular/angular/issues/43821#issuecomment-1054845431) to ensure the forms package is shared.
-21
View File
@@ -1,21 +0,0 @@
@name Circular Dependency in DI
@category runtime
@videoUrl https://www.youtube.com/embed/CpLOm4o_FzM
@shortDescription Circular dependency in DI detected while instantiating a provider
@description
A cyclic dependency exists when a [dependency of a service](guide/hierarchical-dependency-injection) directly or indirectly depends on the service itself. For example, if `UserService` depends on `EmployeeService`, which also depends on `UserService`. Angular will have to instantiate `EmployeeService` to create `UserService`, which depends on `UserService`, itself.
@debugging
Use the call stack to determine where the cyclical dependency exists.
You will be able to see if any child dependencies rely on the original file by [mapping out](guide/dependency-injection-in-action) the component, module, or service's dependencies, and identifying the loop causing the problem.
Break this loop \(or circle\) of dependency to resolve this error. This most commonly means removing or refactoring the dependencies to not be reliant on one another.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
-30
View File
@@ -1,30 +0,0 @@
@name No Provider Found
@category runtime
@videoUrl https://www.youtube.com/embed/lAlOryf1-WU
@shortDescription No provider for {token} found!
@description
You see this error when you try to inject a service but have not declared a corresponding provider. A provider is a mapping that supplies a value that you can inject into the constructor of a class in your application.
Read more on providers in our [Dependency Injection guide](guide/dependency-injection).
@debugging
Work backwards from the object where the error states that a [provider](guide/architecture-services) is missing: `No provider for ${this}!`. This is commonly thrown in [services](tutorial/tour-of-heroes/toh-pt4), which require non-existing providers.
To fix the error ensure that your service is registered in the list of providers of an `NgModule` or has the `@Injectable` decorator with a `providedIn` property at top.
The most common solution is to add a provider in `@Injectable` using `providedIn`:
<code-example format="typescript" language="typescript">
&commat;Injectable({ providedIn: 'app' })
</code-example>
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
-71
View File
@@ -1,71 +0,0 @@
@name `inject()` must be called from an injection context
@category runtime
@shortDescription `inject()` must be called from an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`.
@description
You see this error when you try to use the [`inject`](api/core/inject) function outside of the allowed [injection context](guide/dependency-injection-context). The injection context is available during the class creation and initialization. It is also available to functions
used with `runInInjectionContext`.
In practice the `inject()` calls are allowed in a constructor, a constructor parameter and a field initializer:
```typescript
@Injectable({providedIn: 'root'})
export class Car {
radio: Radio|undefined;
// OK: field initializer
spareTyre = inject(Tyre);
constructor() {
// OK: constructor body
this.radio = inject(Radio);
}
}
```
It is also legal to call [`inject`](api/core/inject) from a provider's factory:
```typescript
providers: [
{provide: Car, useFactory: () => {
// OK: a class factory
const engine = inject(Engine);
return new Car(engine);
}}
]
```
Calls to the [`inject`](api/core/inject) function outside of the class creation or `runInInjectionContext` will result in error. Most notably, calls to `inject()` are disallowed after a class instance was created, in methods (including lifecycle hooks):
```typescript
@Component({ ... })
export class CarComponent {
ngOnInit() {
// ERROR: too late, the component instance was already created
const engine = inject(Engine);
engine.start();
}
}
```
@debugging
Work backwards from the stack trace of the error to identify a place where the disallowed call to `inject()` is located.
To fix the error move the [`inject`](api/core/inject) call to an allowed place (usually a class constructor or a field initializer).
**Note:** If you are running in a test context, `TestBed.runInInjectionContext` will enable `inject()` to succeed.
```typescript
TestBed.runInInjectionContext(() => {
// ...
});
```
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2023-04-11
-17
View File
@@ -1,17 +0,0 @@
@name Invalid multi provider
@category runtime
@shortDescription Expected provider to be `multi: true` but did not get an Array
@description
The Angular runtime will throw this error when it injects a token intended to be used with `multi: true` but
a non-Array was found instead. For example, `ENVIRONMENT_INITIALIZER` should be provided
like `{provide: ENVIRONMENT_INITIALIZER, multi: true, useValue: () => {...}}`.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-11-28
-16
View File
@@ -1,16 +0,0 @@
@name Missing Iterable Differ
@category runtime
@shortDescription Cannot find a differ for object in ngFor
@description
`NgFor` could not find an iterable differ for the value passed in. Make sure it's an iterable, like an `Array`.
@debugging
When using ngFor in a template, you must use some type of Iterable, like `Array`, `Set`, `Map`, etc.
If you're trying to iterate over the keys in an object, you should look at the [KeyValue pipe](/api/common/KeyValuePipe) instead.
<!-- links -->
<!-- external links -->
<!-- end links -->
-23
View File
@@ -1,23 +0,0 @@
@name JSONP support in HttpClient configuration
@category runtime
@shortDescription Missing JSONP support in HttpClient configuration
@description
Angular produces this error when you attempt a `JSONP` request without providing the necessary support for it in the `HttpClient` configuration.
To enable `JSONP` support, you can do one of the following:
- add the `withJsonpSupport()` as an argument during the `provideHttpClient` function call (e.g. `provideHttpClient(withJsonpSupport())`) when `bootstrapApplication` is used
- import the `HttpClientJsonpModule` in your root AppModule, when NgModule-based bootstrap is used.
@debugging
Make sure that the JSONP support is added into your application either by calling the `withJsonpSupport()` function (when the `provideHttpClient()` is used) or importing the `HttpClientJsonpModule` module as described above.
See [Make a JSONP request](/guide/http-make-jsonp-request) for more info.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2023-05-02
-31
View File
@@ -1,31 +0,0 @@
@name Selector Collision
@category runtime
@videoUrl https://www.youtube.com/embed/z_3Z5mOm59I
@shortDescription Multiple components match with the same tagname
@description
Two or more components use the same [element selector](guide/component-overview#specifying-a-components-css-selector). Because there can only be a single component associated with an element, selectors must be unique strings to prevent ambiguity for Angular.
@debugging
Use the element name from the error message to search for places where you're using the same [selector declaration](guide/architecture-components) in your codebase:
<code-example format="typescript" language="typescript">
&commat;Component({
selector: 'YOUR_STRING',
&hellip;
})
</code-example>
Ensure that each component has a unique CSS selector. This will guarantee that Angular renders the component you expect.
If you're having trouble finding multiple components with this selector tag name, check for components from imported component libraries, such as Angular Material. Make sure you're following the [best practices](guide/styleguide#component-selectors) for your selectors to prevent collisions.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
-40
View File
@@ -1,40 +0,0 @@
@name Export Not Found
@category runtime
@videoUrl https://www.youtube.com/embed/fUSAg4kp2WQ
@shortDescription Export not found!
@description
Angular can't find a directive with `{{ PLACEHOLDER }}` export name. The export name is specified in the `exportAs` property of the directive decorator. This is common when using FormsModule or Material modules in templates and you've forgotten to [import the corresponding modules](guide/sharing-ngmodules).
<div class="alert is-helpful">
This is the runtime equivalent of a common compiler error [NG8003: No directive found with export](errors/NG8003).
</div>
@debugging
Use the export name to trace the templates or modules using this export.
Ensure that all dependencies are [properly imported and declared in your NgModules](guide/sharing-ngmodules). For example, if the export not found is `ngForm`, we need to import `FormsModule` and declare it in the list of imports in `*.module.ts` to resolve the error.
<code-example format="typescript" language="typescript">
import { FormsModule } from '&commat;angular/forms';
&commat;NgModule({
&hellip;
imports: [
FormsModule,
&hellip;
</code-example>
If you recently added an import, you may need to restart your server to see these changes.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
-32
View File
@@ -1,32 +0,0 @@
@name Pipe Not Found
@category runtime
@videoUrl https://www.youtube.com/embed/maI2u6Sxk9M
@videoCaption Note: The video predates standalone pipes, please refer to additional instructions below if you use standalone pipes.
@shortDescription Pipe not found!
@description
Angular can't find a pipe with this name.
The [pipe](guide/pipes-overview) referenced in the template has not been named or declared properly.
To use the pipe:
- Ensure the name used in a template matches the name defined in the pipe decorator.
- Either mark it as standalone by adding the `standalone: true` flag to the pipe's decorator or declare it as a part of an `NgModule` by adding to that module's declarations array.
- Import it in the standalone components and/or the `NgModules` where it is needed.
@debugging
Use the pipe name to trace where the pipe is declared and used.
To resolve this error:
- If the pipe is local to the `NgModule`, give it a unique name in the pipe's decorator and declared it in the `NgModule`.
- If the pipe is standalone or is declared in another `NgModule`, add it to the `imports` field of the standalone component or the current `NgModule`.
If you recently added an import or declaration, you may need to restart your server to see these changes.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-05-22
-42
View File
@@ -1,42 +0,0 @@
@name Bootstrapped NgModule doesn't specify which component to initialize
@category runtime
@shortDescription An NgModule that was used for bootstrapping does not specify which component should be initialized.
@description
This error means that an NgModule that was used for bootstrapping an application is missing key information for Angular to proceed with the bootstrap process.
The error happens when the NgModule `bootstrap` property is missing (or is an empty array) in the `@NgModule` annotation and there is no `ngDoBootstrap` lifecycle hook defined on that NgModule class.
More information about the bootstrapping process can be found in [this guide](guide/bootstrapping).
The following examples will trigger the error.
```typescript
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, AppRoutingModule],
providers: [],
})
export class AppModule {}
// The `AppModule` is used for bootstrapping, but the `@NgModule.bootstrap` field is missing.
platformBrowser().bootstrapModule(AppModule);
```
```typescript
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, AppRoutingModule],
providers: [],
bootstrap: [],
})
export class AppModule {}
// The `AppModule` is used for bootstrapping, but the `@NgModule.bootstrap` field contains an empty array.
platformBrowser().bootstrapModule(AppModule);
```
@debugging
Please make sure that the NgModule that is used for bootstrapping is setup correctly:
- either the `bootstrap` property exists (and contains a non-empty array) in the `@NgModule` annotation
- or the `ngDoBootstrap` method exists on the NgModule class
-44
View File
@@ -1,44 +0,0 @@
@name Hydration Node Mismatch
@category runtime
@shortDescription During hydration, Angular expected a DOM node, but either the actual DOM was different or was not found.
@description
This error means that during the hydration process, Angular expected a DOM structure as rendered and annotated during server side rendering. However, on the client, the DOM tree was different than the server rendered DOM tree.
This error typically happens due to direct DOM manipulation using native browser APIs that alter the DOM structure outside of what Angular produced. It will also occur if you use `innerHTML` or `outerHTML` to set HTML content, which similarly alters the DOM structure outside of what Angular produced. You can resolve this by refactoring the component to use native Angular APIs instead of native APIs. If that's not possible, you can add the `ngSkipHydration` attribute to your component's host node, which will disable hydration for the component and its children. `ngSkipHydration` should only be used as a last resort and should be considered a bug that needs to be fixed.
More information about hydration can be found in [this guide](guide/hydration).
The following example will trigger the error.
```typescript
@Component({
standalone: true,
selector: 'example-cmp',
template: '<div><span>world</span></div>',
})
export class ExampleCmp {
hostElement = inject(ElementRef).nativeElement;
ngOnInit() {
// Create a new <p> element with the `Hello` text inside
const newNode = document.createElement('p');
newNode.innerHTML = 'Hello';
// Insert the <p> before the first element. Since Angular has no information
// about the <p> element, it will be looking for the <div> element at the first
// element position instead. As a result, a hydration mismatch error would be
// thrown. Instead, update component's template to create the <p> element.
this.hostElement.insertBefore(newNode, this.hostElement.firstChild);
}
}
```
@debugging
The error message in the developer console should contain information on a specific part of the application's DOM structure that is causing the problem. Review that part of the application for hydration-related errors, such as direct DOM manipulation using native APIs.
Check that your template has valid HTML structure. See more information in the [hydration guide](guide/hydration#valid-html-structure).
You can add the `ngSkipHydration` attribute to your component host node as a possible workaround.
If your application works in development environment, but you see hydration errors in production builds, make sure that the generated HTML that is delivered to a browser contains comment nodes produced by Angular during the rendering on the server. Those comment nodes are used by Angular runtime as anchors for view containers (with and without hydration) and hydration process expects them to be present at their original locations. If you have a custom logic to remove comment nodes from the HTML generated by the server-side rendering or you've configured your CDN to remove them before serving the content - disable the comment nodes removal and check if hydration errors are gone.
-9
View File
@@ -1,9 +0,0 @@
@name Hydration Missing Siblings
@category runtime
@shortDescription During hydration, Angular expected more sibling DOM nodes to be present than what was found.
@description
This error is similar to the [error NG0500](errors/NG0500), but it indicates that Angular hydration process expected more siblings present in the DOM structure at a particular location. Please refer to the [error NG0500](errors/NG0500) page for additional information.
@debugging
See the [error NG0500](errors/NG0500) for more information on how to debug this error.
-9
View File
@@ -1,9 +0,0 @@
@name Hydration Missing Node
@category runtime
@shortDescription During hydration, Angular expected to find a DOM node, but it did not exist.
@description
This error is similar to the [error NG0500](errors/NG0500), but it indicates that Angular hydration process expected a node to be present in the DOM structure at a particular location and none was found. Please refer to the [error NG0500](errors/NG0500) page for additional information.
@debugging
See the [error NG0500](errors/NG0500) for more information on how to debug this error.
-49
View File
@@ -1,49 +0,0 @@
@name Hydration Unsupported Projection of DOM Nodes
@category runtime
@shortDescription During serialization, Angular detected DOM nodes that were created outside of Angular's context and used for content projection.
@description
This error means that during the server side serialization process, Angular encountered nodes that were created outside of Angular's context (i.e. using native DOM APIs) and found those nodes were provided as projectible nodes. They were likely provided using `ViewContainerRef.createComponent` or `createComponent` APIs. Angular hydration does not support this use case.
More information about hydration can be found in [this guide](guide/hydration).
The following examples will trigger the error.
```typescript
@Component({
standalone: true,
selector: 'dynamic',
template: `
<ng-content />
`,
})
class DynamicComponent {
}
@Component({
standalone: true,
selector: 'app',
template: `<div #target></div>`,
})
class SimpleComponent {
@ViewChild('target', {read: ViewContainerRef}) vcr!: ViewContainerRef;
envInjector = inject(EnvironmentInjector);
ngAfterViewInit() {
const div = document.createElement('div');
const p = document.createElement('p');
// In this test we create DOM nodes outside of Angular context
// (i.e. not using Angular APIs) and try to content-project them.
// This is an unsupported pattern and an exception will be thrown.
const compRef = createComponent(DynamicComponent, {
environmentInjector: this.envInjector,
projectableNodes: [[div, p]]
});
}
}
```
@debugging
The error message in the developer console should contain information on a specific part of the application's DOM structure that is causing the problem. Review that part of the application for hydration-related errors, such as direct DOM manipulation using native APIs.
You can add the `ngSkipHydration` attribute to your component host node as a possible workaround.
-55
View File
@@ -1,55 +0,0 @@
@name Skip hydration flag is applied to an invalid node
@category runtime
@shortDescription The ngSkipHydration attribute was added to an element that is not a component host.
@description
This error occurs when the `ngSkipHydration` attribute was added to an inappropriate DOM node. The `ngSkipHydration` attribute can only be applied to component host nodes either directly in the template or via a host binding. It cannot be applied to other DOM nodes and will have no effect if done so other than causing this error.
More information about hydration can be found in [this guide](guide/hydration).
The following examples will trigger the error.
**Example 1**
In this example, the `ngSkipHydration` attribute is applied to a `<div>` using host bindings of a directive. Since the `<div>` doesn't act as a component host node, Angular will throw an error.
```typescript
@Directive({
standalone: true,
selector: '[dir]',
host: {ngSkipHydration: 'true'},
})
class Dir {
}
@Component({
standalone: true,
selector: 'app',
imports: [Dir],
template: `
<div dir></div>
`,
})
class SimpleComponent {
}
```
**Example 2**
In this example, the `ngSkipHydration` is applied to a `<div>` as an attribute via a template.
Since the `<div>` doesn't act as a component host node, Angular will throw an error.
```typescript
@Component({
standalone: true,
selector: 'app',
template: `
<div ngSkipHydration></div>
`,
})
class SimpleComponent {
}
```
@debugging
Remove the `ngSkipHydration` attribute from any invalid DOM nodes. Alternatively, move the `ngSkipHydration` attribute to the component host node either in a template or via a host binding.
-26
View File
@@ -1,26 +0,0 @@
@name No hydration info in server response
@category runtime
@shortDescription No hydration info is present in server response.
@description
This error occurs when hydration is enabled on the client, but the server response
doesn't contain special serialized information about the application that hydration
logic relies on.
This can happen when the `provideClientHydration()` function is included in the client
part of the application configuration, but is missing in the server part of the configuration.
In applications with the default project structure (generated by the `ng new`),
the `provideClientHydration()` call is added either into the `providers` array of
the main `AppModule` (which is imported into the server module) or into a set of
providers that are included into both client and server configurations.
If you have a custom setup where client and server configuration are independent
and do not share common set of providers, make sure that the `provideClientHydration()`
is also included into the set of providers used to bootstrap an application on the server.
More information about hydration can be found in [this guide](guide/hydration).
@debugging
Verify that the `provideClientHydration()` call is included into a set of providers
that is used to bootstrap an application on the server.
-53
View File
@@ -1,53 +0,0 @@
@name NgZone remains unstable
@category runtime
@shortDescription NgZone remains unstable after a long period of time
@description
This warning occurs when hydration is enabled on the client but the NgZone remains unstable for a long period of time.
The {@link ApplicationRef#isStable} API uses NgZone to report when an application becomes `stable` and `unstable`. An application is considered stable when there are no pending microtasks or macrotasks.
Angular Hydration relies on a signal from Zone.js when it becomes stable inside an application:
* during the server-side rendering (SSR) to start the serialization process
* in a browser this signal is used to start the post-hydration cleanup to remove DOM nodes that remained unclaimed
This warning is displayed when the `ApplicationRef.isStable()` doesn't emit `true` within 10 seconds. If this is intentional and your application becomes stable later, you can ignore this warning.
**Macrotasks**
Macrotasks include functions like `setInterval`, `setTimeout`, `requestAnimationFrame` etc.
If one of these functions is called in the initialization phase of the app or the bootstrapped components, the application will remain unstable.
```typescript
@Component({
standalone: true,
selector: 'app',
template: ``,
})
class SimpleComponent {
constructor() {
setInterval(() => { ... }, 1000)
// or
setTimeout(() => { ... }, 10_000)
}
}
```
If these functions need to be called in the initialization phase, invoking them outside the angular zone solves the issue.
```typescript
class SimpleComponent {
constructor() {
inject(NgZone).runOutsideAngular(() => {
setInterval(() => {}, 1000);
})
}
}
```
@debugging
Verify that you don't have any long standing microtask or macrotasks.
-12
View File
@@ -1,12 +0,0 @@
@name HTML content was altered after server-side rendering
@category runtime
@shortDescription HTML content was altered after server-side rendering
@description
Angular throws this error when it detects that the content generated by server-side rendering (SSR) was altered after the rendering. The process of hydration relies on the content to be untouched after SSR, which also includes whitespaces and comment nodes. Those whitespaces and comment nodes must be retained in the HTML generated by the SSR process. Learn more in the [Hydration guide](guide/hydration#constraints).
@debugging
Typically this happens in the following cases:
* Some CDN providers have a built-in feature to remove whitespaces and comment nodes from HTML as an optimization. Please verify if there is such an option in CDN configuration and turn it off.
* If you use custom post-processing of HTML generated by SSR (as a build step), make sure that this process doesn't remove whitespaces and comment nodes.
-33
View File
@@ -1,33 +0,0 @@
@name Root element was not found.
@category runtime
@shortDescription Root element was not found during bootstrap.
@description
Bootstrapped components are defined in the `bootstrap` property of an `@NgModule` decorator or as the first parameter of `bootstrapApplication` for standalone components.
This error happens when Angular tries to bootstrap one of these components but cannot find its corresponding node in the DOM.
@debugging
This issue occurs when the selector mismatches the tag
```typescript
@Component({
selector: 'my-app',
...
})
class AppComponent {}
```
```html
<html>
<app-root></app-root> <!-- Doesn't match the selector -->
</html>
```
Replace the tag with the correct one:
```html
<html>
<my-app></my-app> <!-- OK -->
</html>
```
-62
View File
@@ -1,62 +0,0 @@
@name Disallowed function call inside reactive context
@category runtime
@shortDescription A disallowed function is called inside a reactive context
@description
A function that is not allowed to run inside a reactive context was called from within a reactive context.
For example, an `effect` cannot be scheduled from within a `computed` or an actively executing effect.
Avoid calling functions like `effect` as part of template expressions, as those execute in their own reactive context.
Computed expressions are expected to be pure.
Pure means that expression do not trigger any side effects.
Side effects are operations like scheduling `afterRender`, creating a new `effect`, or subscribing to observables.
Some operations are explicitly banned inside reactive contexts in order to avoid common pitfalls.
As an example, using `afterRender` inside a `computed` will schedule new render hooks every time the computed expression evaluates.
This is likely not intended and could degrade application performance.
### Fixing the error
This error guide is non-exhaustive.
It captures a few common scenarios and how to address the error.
#### `afterRender`
Move the call for `afterRender` outside of the reactive context.
A good place to schedule the after render hook is in the component's class constructor.
Alternatively, use `untracked` to leave the reactive context and explicitly opt-out of this error.
#### `effect`
Move the call for `effect` outside of the reactive context.
A good place to schedule an effect is in a `@Component`'s class constructor.
#### `toSignal`
Move the call for `toSignal` outside of the reactive context.
```typescript
result = computed(() => {
const dataSignal = toSignal(dataObservable$);
return doSomething(dataSignal());
});
```
can be refactored into:
```typescript
dataSignal = toSignal(dataObservable$);
result = computed(() => doSomething(dataSignal()));
```
Alternatively, if this is not possible, consider manually subscribing to the observable.
As a last resort, use `untracked` to leave the reactive context.
Be careful as leaving the reactive context can result in signal reads to be ignored inside `untracked`.
@debugging
The error message mentions the function that was unexpectedly called.
Look for this function call in your application code.
Alternatively, the stack trace in your browser will show where the function was invoked and where it's located.
-71
View File
@@ -1,71 +0,0 @@
@name Unsafe bindings on an iframe element
@category runtime
@shortDescription Unsafe bindings on an iframe element
@description
You see this error when Angular detects an attribute binding or a property binding on an `<iframe>` element using the following property names:
* sandbox
* allow
* allowFullscreen
* referrerPolicy
* csp
* fetchPriority
The mentioned attributes affect the security model setup for `<iframe>`s
and it's important to apply them before setting the `src` or `srcdoc` attributes.
To enforce that, Angular requires these attributes to be set on `<iframe>`s as
static attributes, so the values are set at the element creation time and they
remain the same throughout the lifetime of an `<iframe>` instance.
The error is thrown when a property binding with one of the mentioned attribute names is used:
```html
<iframe [sandbox]="'allow-scripts'" src="..."></iframe>
```
or when it's an attribute bindings:
```html
<iframe [attr.sandbox]="'allow-scripts'" src="..."></iframe>
```
Also, the error is thrown when a similar pattern is used in Directive's host bindings:
```typescript
@Directive({
selector: 'iframe',
host: {
'[sandbox]': `'allow-scripts'`,
'[attr.sandbox]': `'allow-scripts'`,
}
})
class IframeDirective {}
```
@debugging
The error message includes the name of the component with the template where
an `<iframe>` element with unsafe bindings is located.
The recommended solution is to use the mentioned attributes as static ones, for example:
```html
<iframe sandbox="allow-scripts" src="..."></iframe>
```
If you need to have different values for these attributes (depending on various conditions),
you can use an `*ngIf` or an `*ngSwitch` on an `<iframe>` element:
```html
<iframe *ngIf="someConditionA" sandbox="allow-scripts" src="..."></iframe>
<iframe *ngIf="someConditionB" sandbox="allow-forms" src="..."></iframe>
<iframe *ngIf="someConditionC" sandbox="allow-popups" src="..."></iframe>
```
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-05-27
-65
View File
@@ -1,65 +0,0 @@
@name Component ID generation collision
@category runtime
@shortDescription Component ID generation collision detected
@description
When creating components, Angular generates a unique component ID for each component. This is generated using the Angular component metadata, including but not limited: selectors, the number of host bindings, class property names, view and content queries. When two components metadata are identical (often times sharing the same selector), an ID generation collision will occur.
Component IDs are used in Angular internally:
- for extra annotations of DOM nodes for style encapsulation
- during [hydration](guide/hydration) to restore an application state after [server-side rendering](guide/ssr).
To avoid issues that might be caused by the component ID collision, it's recommended to resolve them as described below.
** Example of a Component ID collision **
```typescript
@Component({
selector: 'my-component',
template: 'complex-template',
})
class SomeComponent {}
@Component({
selector: 'my-component',
template: 'empty-template',
})
class SomeMockedComponent {}
```
Having these two components defined will trigger an ID generation collision and during development a warning will be displayed.
@debugging
The warning message includes the class name of the two components whose IDs are colliding.
The problem can be resolved using one of the solutions below:
1. Change the selector of one of the two components. For example by using a pseudo-selector with no effect like `:not()` and a different tag name.
```typescript
@Component({
selector: 'my-component:not(p)',
template: 'empty-template',
})
class SomeMockedComponent {}
```
2. Add an extra host attribute to one of the components.
```typescript
@Component({
selector: 'my-component',
template: 'complex-template',
host: {'some-binding': 'some-value'},
})
class SomeComponent {}
```
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2023-04-25
-39
View File
@@ -1,39 +0,0 @@
@name Runtime Performance Warnings
@category runtime
@shortDescription Performance-harming image elements detected at runtime
@description
After an application is loaded, Angular checks included `<img>` elements for performance-harming misconfiguration. This warning can be triggered two ways:
### Oversized images
When images are loaded, the **intrinsic size** of the downloaded file is checked against the actual size of the image on the page. The actual size is calculated using the **rendered size** of the image with CSS applied, multiplied by the [pixel device ratio](https://web.dev/codelab-density-descriptors/#pixel-density). If the downloaded image is much larger (more than 1200px too large in either dimension), this warning is triggered. Downloading oversized images can slow down page loading and have a negative effect on [Core Web Vitals](https://web.dev/vitals/).
### Lazy-loaded LCP element
The largest contentful element on a page during load is considered the "LCP Element", which relates to [Largest Contentful Paint](https://web.dev/lcp/), one of the Core Web Vitals. Lazy loading an LCP element will have a strong negative effect on page performance. With this strategy, the browser has to complete layout calculations to determine whether the element is in the viewport before starting the image download. As a result, a warning is triggered when Angular detects that the LCP element has been given the `loading="lazy"` attribute.
@debugging
Use the image URL provided in the console warning to find the `<img>` element in question.
### Ways to fix oversized images
* Use a smaller source image
* Add a [`srcset`](https://web.dev/learn/design/responsive-images/#responsive-images-with-srcset) if multiple sizes are needed for different layouts.
* Switch to use Angular's built-in image directive ([`NgOptimizedImage`](https://angular.io/api/common/NgOptimizedImage)), which generates [srcsets automatically](https://angular.io/guide/image-directive#request-images-at-the-correct-size-with-automatic-srcset).
### Ways to fix lazy-loaded LCP element
* Change the `loading` attribute to a different value such as `"eager"`.
* Switch to use Angular's built-in image directive ([`NgOptimizedImage`](https://angular.io/api/common/NgOptimizedImage)), which allows for easily [prioritizing LCP images](https://angular.io/guide/image-directive#step-4-mark-images-as-priority).
### Disabling Image Performance Warnings
Both warnings can be disabled individually, site-wide, using a provider at the root of your application:
<code-example format="typescript" language="typescript">
providers: [
{
provide: IMAGE_CONFIG,
useValue: {
disableImageSizeWarning: true,
disableImageLazyLoadWarning: true
}
},
],
</code-example>
-18
View File
@@ -1,18 +0,0 @@
@name Input is required but no value is available yet.
@category runtime
@shortDescription A required input is accessed before a value is set.
@description
A required input was accessed but no value was bound.
This can happen when a required input is accessed too early in your directive or component.
This is commonly happening when the input is read as part of class construction.
Inputs are guaranteed to be available in the `ngOnInit` lifecycle hook and afterwards.
## Fixing the error
Access the required input in reactive contexts.
For example, in the template itself, inside a `computed`, or inside an effect.
Alternatively, access the input inside the `ngOnInit` lifecycle hook, or later.
-23
View File
@@ -1,23 +0,0 @@
@name Child query result is required but no value is available.
@category runtime
@shortDescription Required child query result was accessed before query results were calculated or query has no matches.
@description
Required child query (`contentChild.required` or `viewChild.required`) result was accessed before query results were calculated or query has no matches.
This can happen in two distinct situations:
* query results were accessed before a given query could collect results;
* a query was executed but didn't match any nodes and has no results as a consequence.
Content queries and view queries each calculate their results at different points in time:
* `contentChild` results are available after a _host_ view (template where a directive declaring a query is used) is created;
* `viewChild` results are available after a template of a component declaring a query is created.
Accessing query results before they're available results in the error described on this page. Most notably, query results are _never_ available in a constructor of the component or directive declaring a query.
## Fixing the error
`contentChild` query results can be accessed in the `AfterContentChecked` lifecycle hook, or later.
`viewChild` query results can be accessed in the `AfterViewChecked` lifecycle hook, or later.
Make sure that a required query matches at least one node and has results at all. You can verify this by accessing query results in the lifecycle hooks listed above.
-42
View File
@@ -1,42 +0,0 @@
@name Argument Not Literal
@category compiler
@shortDescription Decorator argument is not an object literal
@description
To make the metadata extraction in the Angular compiler faster, the decorators `@NgModule`, `@Pipe`, `@Component`, `@Directive`, and `@Injectable` accept only object literals as arguments.
This is an [intentional change in Ivy](https://github.com/angular/angular/issues/30840#issuecomment-498869540), which enforces stricter argument requirements for decorators than View Engine.
Ivy requires this approach because it compiles decorators by moving the expressions into other locations in the class output.
@debugging
Move all declarations:
<code-example format="typescript" language="typescript">
const moduleDefinition = {&hellip;}
&commat;NgModule(moduleDefinition)
export class AppModule {
constructor() {}
}
</code-example>
into the decorator:
<code-example format="typescript" language="typescript">
&commat;NgModule({&hellip;})
export class AppModule {
constructor() {}
}
</code-example>
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
-20
View File
@@ -1,20 +0,0 @@
@name Missing Token
@category compiler
@shortDescription No suitable injection token for parameter
@description
There is no injection token for a constructor parameter at compile time. [InjectionTokens](api/core/InjectionToken) are tokens that can be used in a Dependency Injection Provider.
@debugging
Look at the parameter that throws the error, and all uses of the class.
This error is commonly thrown when a constructor defines parameters with primitive types such as `string`, `number`, `boolean`, and `Object`.
Use the `@Injectable` method or `@Inject` decorator from `@angular/core` to ensure that the type you are injecting is reified \(has a runtime representation\). Make sure to add a provider to this decorator so that you do not throw [NG0201: No Provider Found](errors/NG0201).
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
-40
View File
@@ -1,40 +0,0 @@
@name Invalid Shadow DOM selector
@category compiler
@shortDescription Component selector does not match shadow DOM requirements
@description
The selector of a component using `ViewEncapsulation.ShadowDom` doesn't match the custom element tag name requirements.
In order for a tag name to be considered a valid custom element name, it has to:
* Be in lower case.
* Contain a hyphen.
* Start with a letter \(a-z\).
@debugging
Rename your component's selector so that it matches the requirements.
**Before:**
<code-example format="typescript" language="typescript">
&commat;Component({
selector: 'comp',
encapsulation: ViewEncapsulation.ShadowDom
&hellip;
})
</code-example>
**After:**
<code-example format="typescript" language="typescript">
&commat;Component({
selector: 'app-comp',
encapsulation: ViewEncapsulation.ShadowDom
&hellip;
})
</code-example>
-62
View File
@@ -1,62 +0,0 @@
@name Import Cycle Detected
@category compiler
@shortDescription Import cycles would need to be created to compile this component
@description
A component, directive, or pipe that is referenced by this component would require the compiler to add an import that would lead to a cycle of imports.
For example, consider a scenario where a `ParentComponent` references a `ChildComponent` in its template:
<code-example header="parent.component.ts" path="errors/cyclic-imports/parent.component.ts"></code-example>
<code-example header="child.component.ts" path="errors/cyclic-imports/child.component.ts"></code-example>
There is already an import from `child.component.ts` to `parent.component.ts` since the `ChildComponent` references the `ParentComponent` in its constructor.
<div class="alert is-helpful">
**NOTE**: <br />
The parent component's template contains `<child></child>`.
The generated code for this template must therefore contain a reference to the `ChildComponent` class.
In order to make this reference, the compiler would have to add an import from `parent.component.ts` to `child.component.ts`, which would cause an import cycle:
<code-example format="none" language="none">
parent.component.ts -&gt; child.component.ts -&gt; parent.component.ts
</code-example>
</div>
### Remote Scoping
If you are using NgModules, to avoid adding imports that create cycles, additional code is added to the `NgModule` class where the component that wires up the dependencies is declared.
This is known as "remote scoping".
### Libraries
Unfortunately, "remote scoping" code is side-effectful &mdash;which prevents tree shaking&mdash; and cannot be used in libraries.
So when building libraries using the `"compilationMode": "partial"` setting, any component that would require a cyclic import will cause this `NG3003` compiler error to be raised.
@debugging
The cycle that would be generated is shown as part of the error message.
For example:
<code-example hideCopy="true">
The component ChildComponent is used in the template but importing it would create a cycle:
/parent.component.ts -&gt; /child.component.ts -&gt; /parent.component.ts
</code-example>
Use this to identify how the referenced component, pipe, or directive has a dependency back to the component being compiled.
Here are some ideas for fixing the problem:
* Try to rearrange your dependencies to avoid the cycle.
For example, using an intermediate interface that is stored in an independent file that can be imported to both dependent files without causing an import cycle.
* Move the classes that reference each other into the same file, to avoid any imports between them.
* Convert import statements to type-only imports \(using `import type` syntax\) if the imported declarations are only used as types, as type-only imports do not contribute to cycles.
@reviewed 2023-08-30
-14
View File
@@ -1,14 +0,0 @@
@name Hydration with unsupported Zone.js instance.
@category runtime
@shortDescription Hydration was enabled with unsupported Zone.js instance.
@description
This warning means that the hydration was enabled for an application that was configured to use an unsupported version of Zone.js: either a custom or a "noop" one (see more info [here](api/core/BootstrapOptions#ngZone)).
Hydration relies on a signal from Zone.js when it becomes stable inside an application, so that Angular can start the serialization process on the server or post-hydration cleanup on the client (to remove DOM nodes that remained unclaimed).
Providing a custom or a "noop" Zone.js implementation may lead to a different timing of the "stable" event, thus triggering the serialization or the cleanup too early or too late. This is not yet a fully supported configuration.
If you use a custom Zone.js implementation, make sure that the "onStable" event is emitted at the right time and does not result in incorrect application behavior with hydration.
More information about hydration can be found in the [hydration guide](guide/hydration).
-26
View File
@@ -1,26 +0,0 @@
@name NgModule.id Set to module.id anti-pattern
@category compiler
@shortDescription Setting NgModule.id to module.id is a common anti-pattern
@description
Using `module.id` as an NgModule `id` is a common anti-pattern and is likely not serving a useful purpose in your code.
NgModules can be declared with an `id`:
```typescript
@NgModule({
id: 'my_module'
})
export class MyModule {}
```
Declaring an `id` makes the NgModule available for lookup via the `getNgModuleById()` operation. This functionality is rarely used, mainly in very specific bundling scenarios when lazily loading NgModules without obtaining direct references to them. In most Angular code, ES dynamic `import()` (`import('./path/to/module')`) should be used instead, as this provides a direct reference to the NgModule being loaded without the need for a global registration side effect.
If you are not using `getNgModuleById`, you do not need to provide `id`s for your NgModules. Providing one has a significant drawback: it makes the NgModule non-tree-shakable, which can have an impact on your bundle size.
In particular, the pattern of specifying `id: module.id` results from a misunderstanding of `@NgModule.id`. In earlier versions of Angular, it was sometimes necessary to include the property `moduleId: module.id` in `@Component` metadata.
Using `module.id` for `@NgModule.id` likely results from confusion between `@Component.moduleId` and `@NgModule.id`. `module.id` would not typically be useful for `getNgModuleById()` operations as the `id` needs to be a well-known string, and `module.id` is usually opaque to consumers.
@debugging
You can remove the `id: module.id` declaration from your NgModules. The compiler ignores this declaration and issues this warning instead.
-31
View File
@@ -1,31 +0,0 @@
@name Invalid Element
@category compiler
@shortDescription Unknown HTML element or component
@description
One or more elements cannot be resolved during compilation because the element is not defined by the HTML spec, or there is no component or directive with such element selector.
<div class="alert is-helpful">
This is the compiler equivalent of a common runtime error `NG0304: '${tagName}' is not a known element: ...`.
</div>
@debugging
Use the element name in the error to find the file(s) where the element is being used.
Check that the name and selector are correct.
Make sure that the component is correctly imported inside your NgModule or standalone component, by checking its presence in the `imports` field. If the component is declared in an NgModule (meaning that it is not standalone) make sure that it is exported correctly from it, by checking its presence in the `exports` field.
When using custom elements or web components, ensure that you add [`CUSTOM_ELEMENTS_SCHEMA`](api/core/CUSTOM_ELEMENTS_SCHEMA) to the application module.
If this does not resolve the error, check the imported libraries for any recent changes to the exports and properties you are using, and restart your server.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
-27
View File
@@ -1,27 +0,0 @@
@name Invalid Attribute
@category compiler
@videoUrl https://www.youtube.com/embed/wfLkB3RsSJM
@shortDescription Unknown attribute or input
@description
An attribute or property cannot be resolved during compilation.
This error arises when attempting to bind to a property that does not exist.
Any property binding must correspond to either:
* A native property on the HTML element, or
* An `@Input()` property of a component or directive applied to the element.
The runtime error for this is `NG0304: '${tagName}' is not a known element: &hellip;'`.
@debugging
Look at documentation for the specific [binding syntax](guide/binding-syntax) used. This is usually a typo or incorrect import.
There may also be a missing direction with property selector 'name' or missing input.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
-42
View File
@@ -1,42 +0,0 @@
@name Missing Reference Target
@category compiler
@videoUrl https://www.youtube.com/embed/fUSAg4kp2WQ
@shortDescription No directive found with export
@description
Angular can't find a directive with `{{ PLACEHOLDER }}` export name.
This is common with a missing import or a missing [`exportAs`](api/core/Directive#exportAs) on a directive.
<div class="alert is-helpful">
This is the compiler equivalent of a common runtime error [NG0301: Export Not Found](errors/NG0301).
</div>
@debugging
Use the string name of the export not found to trace the templates or modules using this export.
Ensure that all dependencies are properly imported and declared in our Modules.
For example, if the export not found is `ngForm`, we will need to import `FormsModule` and declare it in our list of imports in `*.module.ts` to resolve the missing export error.
<code-example format="typescript" language="typescript">
import { FormsModule } from '&commat;angular/forms';
&commat;NgModule({
&hellip;
imports: [
FormsModule,
&hellip;
</code-example>
If you recently added an import, you will need to restart your server to see these changes.
<!-- links -->
<!-- external links -->
<!-- end links -->
@reviewed 2022-02-28
-1
View File
@@ -1 +0,0 @@
# Errors List
-212
View File
@@ -1,212 +0,0 @@
{
"root": true,
"ignorePatterns": ["*.js", "styleguide/**/*.avoid.ts"],
"overrides": [
{
"files": ["*.html"],
"extends": ["plugin:@angular-eslint/template/recommended"],
"rules": {
"@angular-eslint/template/alt-text": "error",
"@angular-eslint/template/elements-content": "error",
"@angular-eslint/template/label-has-associated-control": "error",
"@angular-eslint/template/table-scope": "error",
"@angular-eslint/template/valid-aria": "error",
"@angular-eslint/template/click-events-have-key-events": "error",
"@angular-eslint/template/eqeqeq": "off",
"@angular-eslint/template/mouse-events-have-key-events": "error",
"@angular-eslint/template/no-autofocus": "error",
"@angular-eslint/template/no-distracting-elements": "error",
"@angular-eslint/template/no-positive-tabindex": "error"
}
},
{
"files": ["*.ts"],
"extends": [
"plugin:@angular-eslint/template/process-inline-templates"
],
"parserOptions": {
"createDefaultProgram": false,
"project": "content/examples/tsconfig.eslint.json"
},
"plugins": [
"@typescript-eslint",
"@angular-eslint", "eslint-plugin-import", "eslint-plugin-jsdoc", "eslint-plugin-prefer-arrow"],
"rules": {
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/explicit-member-accessibility": "off",
"sort-keys": "off",
"@angular-eslint/component-class-suffix": "error",
"@angular-eslint/contextual-lifecycle": "error",
"@angular-eslint/directive-class-suffix": "error",
"@angular-eslint/no-conflicting-lifecycle": "error",
"@angular-eslint/no-host-metadata-property": "error",
"@angular-eslint/no-input-rename": "error",
"@angular-eslint/no-inputs-metadata-property": "error",
"@angular-eslint/no-output-native": "error",
"@angular-eslint/no-output-on-prefix": "error",
"@angular-eslint/no-output-rename": "error",
"@angular-eslint/no-outputs-metadata-property": "error",
"@angular-eslint/use-lifecycle-interface": "error",
"@angular-eslint/use-pipe-transform-interface": "error",
"@typescript-eslint/adjacent-overload-signatures": "error",
"@typescript-eslint/array-type": "off",
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-inferrable-types": [
"error",
{
"ignoreParameters": true
}
],
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-parameter-properties": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/prefer-for-of": "error",
"@typescript-eslint/prefer-function-type": "error",
"@typescript-eslint/prefer-namespace-keyword": "error",
"@typescript-eslint/triple-slash-reference": [
"error",
{
"path": "always",
"types": "prefer-import",
"lib": "always"
}
],
"@typescript-eslint/unified-signatures": "error",
"complexity": "off",
"constructor-super": "error",
"eqeqeq": ["error", "smart"],
"guard-for-in": "error",
"id-blacklist": [
"error",
"any",
"Number",
"number",
"String",
"string",
"Boolean",
"boolean",
"Undefined",
"undefined"
],
"id-match": "error",
"import/no-deprecated": "warn",
"jsdoc/no-types": "error",
"max-classes-per-file": "off",
"no-bitwise": "error",
"no-caller": "error",
"no-cond-assign": "error",
"no-debugger": "error",
"no-empty": "off",
"no-eval": "error",
"no-fallthrough": "error",
"no-invalid-this": "off",
"no-new-wrappers": "error",
"no-restricted-imports": [
"error",
{
"name": "rxjs/Rx",
"message": "Please import directly from 'rxjs' instead"
}
],
"no-throw-literal": "error",
"no-undef-init": "error",
"no-unsafe-finally": "error",
"no-unused-labels": "error",
"no-var": "error",
"object-shorthand": "error",
"one-var": ["error", "never"],
"prefer-const": "error",
"radix": "error",
"use-isnan": "error",
"valid-typeof": "off",
"arrow-body-style": "error",
"arrow-parens": "off",
"comma-dangle": "off",
"curly": "error",
"eol-last": "error",
"jsdoc/check-alignment": "error",
"new-parens": "error",
"no-multiple-empty-lines": "off",
"no-trailing-spaces": "error",
"quote-props": ["error", "as-needed"],
"space-before-function-paren": [
"error",
{
"anonymous": "never",
"asyncArrow": "always",
"named": "never"
}
],
"@typescript-eslint/semi": ["error", "always"],
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/ban-types": "error",
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "", // TODO: Fix the code and change the prefix to `"app"` (or whatever makes sense).
"style": "kebab-case"
}
],
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": ["app", "toh"],
"style": "camelCase"
}
],
"dot-notation": "off",
"@typescript-eslint/dot-notation": ["error", {"allowIndexSignaturePropertyAccess": true}],
"indent": "off",
"max-len": ["error", {"code": 120, "ignoreUrls": true}],
"@typescript-eslint/member-delimiter-style": [
"error",
{
"singleline": {
"delimiter": "comma",
"requireLast": false
}
}
],
"@typescript-eslint/member-ordering": "off",
"@typescript-eslint/naming-convention": "off",
"no-console": ["error", {"allow": ["log", "warn", "error"]}],
"no-empty-function": "off",
"@typescript-eslint/no-non-null-assertion": "off", // TODO: Fix the code violating this rule and enable it.
"no-restricted-syntax": [
"error",
{
"selector": "CallExpression[callee.name=/^(fdescribe|fit)$/]",
"message": "Don't keep jasmine focus methods."
}
],
"no-shadow": "off",
"@typescript-eslint/no-shadow": "error",
"no-tabs": "error",
"no-underscore-dangle": "off",
"no-unused-expressions": "off",
"@typescript-eslint/no-unused-expressions": "error",
"no-use-before-define": "off",
"prefer-arrow/prefer-arrow-functions": "off",
"quotes": "off",
"@typescript-eslint/quotes": [
"error",
"single",
{"avoidEscape": true, "allowTemplateLiterals": true}
],
"semi": "error"
}
}
]
}
-21
View File
@@ -1,21 +0,0 @@
load("//aio/content/examples:examples.bzl", "EXAMPLES")
package(default_visibility = ["//visibility:public"])
filegroup(
name = "examples",
srcs = glob(
["**"],
exclude = ["BUILD.bazel"],
) + ["//aio/content/examples/%s:files" % example for example in EXAMPLES.keys()],
)
filegroup(
name = "all-stackblitz",
srcs = ["//aio/content/examples/%s:stackblitz" % example for example in EXAMPLES.keys() if EXAMPLES[example]["stackblitz"]],
)
filegroup(
name = "all-example-zips",
srcs = ["//aio/content/examples/%s:example-zip" % example for example in EXAMPLES.keys() if EXAMPLES[example]["zip"]],
)
@@ -1,7 +0,0 @@
load("//aio/content/examples:examples.bzl", "docs_example")
package(default_visibility = ["//visibility:public"])
docs_example(
name = "accessibility",
)
@@ -1,17 +0,0 @@
import { browser, element, by } from 'protractor';
describe('Accessibility example e2e tests', () => {
beforeEach(() => browser.get(''));
it('should display Accessibility Example', async () => {
expect(await element(by.css('h1')).getText()).toEqual('Accessibility Example');
});
it('should take a number and change progressbar width', async () => {
await element(by.css('input')).sendKeys('16');
expect(await element(by.css('input')).getAttribute('value')).toEqual('16');
expect(await element(by.css('app-example-progressbar div')).getCssValue('width')).toBe('48px');
});
});
@@ -1,13 +0,0 @@
<h1>Accessibility Example</h1>
<!-- #docregion template -->
<label for="progress-value">
Enter an example progress value
<input id="progress-value" type="number" min="0" max="100"
[value]="progress" (input)="setProgress($event)">
</label>
<!-- The user of the progressbar sets an aria-label to communicate what the progress means. -->
<app-example-progressbar [value]="progress" aria-label="Example of a progress bar">
</app-example-progressbar>
<!-- #enddocregion template -->
@@ -1,17 +0,0 @@
import {Component} from '@angular/core';
import {ExampleProgressbarComponent} from './progress-bar.component';
@Component({
standalone: true,
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
imports: [ExampleProgressbarComponent],
})
export class AppComponent {
progress = 0;
setProgress($event: Event) {
this.progress = +($event.target as HTMLInputElement).value;
}
}
@@ -1,12 +0,0 @@
:host {
display: block;
width: 300px;
height: 25px;
border: 1px solid black;
margin-top: 16px;
}
.bar {
background: blue;
height: 100%;
}
@@ -1,30 +0,0 @@
/* eslint-disable @angular-eslint/no-host-metadata-property */
// #docregion progressbar-component
import {Component, Input} from '@angular/core';
/**
* Example progressbar component.
*/
@Component({
standalone: true,
selector: 'app-example-progressbar',
template: '<div class="bar" [style.width.%]="value"></div>',
styleUrls: ['./progress-bar.component.css'],
host: {
// Sets the role for this component to "progressbar"
role: 'progressbar',
// Sets the minimum and maximum values for the progressbar role.
'aria-valuemin': '0',
'aria-valuemax': '100',
// Binding that updates the current value of the progressbar.
'[attr.aria-valuenow]': 'value',
},
})
export class ExampleProgressbarComponent {
/** Current value of the progressbar. */
@Input() value = 0;
}
// #enddocregion progressbar-component
@@ -1,13 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Accessibility Example</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root>Loading...</app-root>
</body>
</html>
@@ -1,7 +0,0 @@
import {bootstrapApplication, provideProtractorTestingSupport} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
bootstrapApplication(AppComponent, {
providers: [provideProtractorTestingSupport()],
}).catch((err) => console.error(err));
@@ -1,9 +0,0 @@
{
"description": "Accessibility",
"files": [
"!**/*.d.ts",
"!**/*.js",
"!**/*.[1,2].*"
],
"tags": ["Accessibility"]
}
@@ -1,62 +0,0 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "angular.io-example"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
// #docregion styles
"styles": [
"styles.css"
],
// #enddocregion styles
"scripts": [],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json",
"exclude": "**/node_modules/**"
},
{
"project": "src/tsconfig.spec.json",
"exclude": "**/node_modules/**"
},
{
"project": "e2e/tsconfig.e2e.json",
"exclude": "**/node_modules/**"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "css",
"component": {}
}
}
@@ -1,7 +0,0 @@
load("//aio/content/examples:examples.bzl", "docs_example")
package(default_visibility = ["//visibility:public"])
docs_example(
name = "ajs-quick-reference",
)
@@ -1,109 +0,0 @@
import { browser, element, by } from 'protractor';
describe('AngularJS to Angular Quick Reference Tests', () => {
beforeAll(() => browser.get(''));
it('should display no poster images after bootstrap', async () => {
await testImagesAreDisplayed(false);
});
it('should display proper movie data', async () => {
// We check only a few samples
const expectedSamples: any[] = [
{row: 0, column: 0, element: 'img', attr: 'src', value: 'images/hero.svg', contains: true},
{row: 0, column: 2, value: 'Celeritas'},
{row: 1, column: 3, matches: /Dec 1[678], 2015/}, // absorb timezone dif; we care about date format
{row: 1, column: 5, value: '$14.95'},
{row: 2, column: 4, value: 'PG-13'},
{row: 2, column: 7, value: '100%'},
{row: 2, column: 0, element: 'img', attr: 'src', value: 'images/ng-logo.svg', contains: true},
];
// Go through the samples
const movieRows = getMovieRows();
for (const sample of expectedSamples) {
const tableCell = movieRows.get(sample.row)
.all(by.tagName('td')).get(sample.column);
// Check the cell or its nested element
const elementToCheck = sample.element
? tableCell.element(by.tagName(sample.element))
: tableCell;
// Check element attribute or text
const valueToCheck = sample.attr
? await elementToCheck.getAttribute(sample.attr)
: await elementToCheck.getText();
// Test for equals/contains/match
if (sample.contains) {
expect(valueToCheck).toContain(sample.value);
} else if (sample.matches) {
expect(valueToCheck).toMatch(sample.matches);
} else {
expect(valueToCheck).toEqual(sample.value);
}
}
});
it('should display images after Show Poster', async () => {
await testPosterButtonClick('Show Poster', true);
});
it('should hide images after Hide Poster', async () => {
await testPosterButtonClick('Hide Poster', false);
});
it('should display no movie when no favorite hero is specified', async () => {
await testFavoriteHero(null, 'Please enter your favorite hero.');
});
it('should display no movie for Magneta', async () => {
await testFavoriteHero('Magneta', 'No movie, sorry!');
});
it('should display a movie for Dr Nice', async () => {
await testFavoriteHero('Dr Nice', 'Excellent choice!');
});
async function testImagesAreDisplayed(isDisplayed: boolean) {
const expectedMovieCount = 3;
const movieRows = getMovieRows();
expect(await movieRows.count()).toBe(expectedMovieCount);
for (let i = 0; i < expectedMovieCount; i++) {
const movieImage = movieRows.get(i).element(by.css('td > img'));
expect(await movieImage.isDisplayed()).toBe(isDisplayed);
}
}
async function testPosterButtonClick(expectedButtonText: string, isDisplayed: boolean) {
const posterButton = element(by.css('app-movie-list tr > th > button'));
expect(await posterButton.getText()).toBe(expectedButtonText);
await posterButton.click();
await testImagesAreDisplayed(isDisplayed);
}
function getMovieRows() {
return element.all(by.css('app-movie-list tbody > tr'));
}
async function testFavoriteHero(heroName: string | null, expectedLabel: string) {
const movieListComp = element(by.tagName('app-movie-list'));
const heroInput = movieListComp.element(by.tagName('input'));
const favoriteHeroLabel = movieListComp.element(by.tagName('h3'));
const resultLabel = movieListComp.element(by.css('span > p'));
await heroInput.clear();
await heroInput.sendKeys(heroName || '');
expect(await resultLabel.getText()).toBe(expectedLabel);
if (heroName) {
expect(await favoriteHeroLabel.isDisplayed()).toBe(true);
expect(await favoriteHeroLabel.getText()).toContain(heroName);
} else {
expect(await favoriteHeroLabel.isDisplayed()).toBe(false);
}
}
});
@@ -1,9 +0,0 @@
.active {font-style: italic;}
.shazam {font-weight: bold;}
img {height: 100px;}
table td {
padding: 4px;
border: 1px solid #e0e0e0;
}
@@ -1,112 +0,0 @@
<!-- #docplaster -->
<h1>{{title}}</h1>
<h3>Routed Movies</h3>
<nav>
<!-- #docregion router-link -->
<a [routerLink]="['/movies']">Movies</a>
<!-- #enddocregion router-link -->
</nav>
<router-outlet></router-outlet>
<hr>
<h1>Example Snippets</h1>
<!-- #docregion ngClass -->
<div [ngClass]="{'active': isActive}">
<!-- #enddocregion ngClass -->
[ngClass] active
</div>
<!-- #docregion ngClass -->
<div [ngClass]="{'active': isActive,
'shazam': isImportant}">
<!-- #enddocregion ngClass -->
[ngClass] active and boldly important
</div>
<!-- #docregion ngClass -->
<div [class.active]="isActive">
<!-- #enddocregion ngClass -->
[class.active]
</div>
<p></p>
<!-- #docregion href -->
<a [href]="angularDocsUrl">Angular Docs</a>
<!-- #enddocregion href -->
<p></p>
<div>
<!-- #docregion event-binding -->
<button type="button" (click)="toggleImage()">
<!-- #enddocregion event-binding -->
Image Toggle #1</button>
<!-- #docregion event-binding -->
<button type="button" (click)="toggleImage($event)">
<!-- #enddocregion event-binding -->
Image Toggle #2</button>
<p>Image toggle event type was {{eventType}}</p>
</div>
<p></p>
<div *ngIf="showImage">
<!-- #docregion src -->
<img [src]="movie.imageurl" [alt]="movie.title">
<!-- #enddocregion src -->
</div>
<p></p>
<!-- #docregion ngStyle -->
<div [ngStyle]="{'color': colorPreference}">
<!-- #enddocregion ngStyle -->
color preference #1
</div>
<!-- #docregion ngStyle -->
<div [style.color]="colorPreference">
<!-- #enddocregion ngStyle -->
color preference #2
</div>
<h3>Movie as JSON</h3>
<!-- #docregion json -->
<pre>{{movie | json}}</pre>
<!-- #enddocregion json -->
<h3>Movie Titles via local variable</h3>
<table>
<!-- #docregion local -->
<tr *ngFor="let movie of movies">
<td>{{movie.title}}</td>
</tr>
<!-- #enddocregion local -->
</table>
<h3>Sliced Movies with pipes</h3>
<table>
<!-- #docregion slice -->
<tr *ngFor="let movie of movies | slice:0:2">
<!-- #enddocregion slice -->
<!-- #docregion uppercase -->
<td>{{movie.title | uppercase}}</td>
<!-- #enddocregion uppercase -->
<!-- #docregion lowercase -->
<td>{{movie.title | lowercase}}</td>
<!-- #enddocregion lowercase -->
<!-- #docregion date -->
<td>{{movie.releaseDate | date}}</td>
<!-- #enddocregion date -->
<!-- #docregion currency -->
<td>{{movie.price | currency:'USD':true}}</td>
<!-- #enddocregion currency -->
<!-- #docregion number -->
<td>{{movie.starRating | number}}</td>
<td>{{movie.starRating | number:'1.1-2'}}</td>
<td>{{movie.approvalRating | percent: '1.0-2'}}</td>
<!-- #enddocregion number -->
</tr></table>
@@ -1,44 +0,0 @@
import { Component } from '@angular/core';
import {
NgFor, NgIf, NgClass, NgStyle,
CurrencyPipe, DatePipe, DecimalPipe, JsonPipe, LowerCasePipe, PercentPipe, SlicePipe, UpperCasePipe
} from '@angular/common';
import { FormsModule } from '@angular/forms';
import { RouterLink, RouterOutlet} from '@angular/router';
import { MovieService } from './movie.service';
import { IMovie } from './movie';
@Component({
standalone: true,
selector: 'app-root',
templateUrl: './app.component.html',
imports: [
FormsModule,
NgFor, NgIf, NgClass, NgStyle,
CurrencyPipe, DatePipe, DecimalPipe, JsonPipe, LowerCasePipe, PercentPipe, SlicePipe, UpperCasePipe,
RouterLink, RouterOutlet
],
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
angularDocsUrl = 'https://angular.io/';
colorPreference = 'red';
eventType = '<not clicked yet>';
isActive = true;
isImportant = true;
movie: IMovie;
movies: IMovie[] = [];
showImage = true;
title = 'AngularJS to Angular Quick Ref Cookbook';
toggleImage(event?: UIEvent) {
this.showImage = !this.showImage;
this.eventType = (event && event.type) || 'not provided';
}
constructor(movieService: MovieService) {
this.movies = movieService.getMovies();
this.movie = this.movies[0];
}
}
@@ -1,17 +0,0 @@
import { ApplicationConfig } from '@angular/core';
import { provideRouter, Routes } from '@angular/router';
import { provideProtractorTestingSupport } from '@angular/platform-browser';
import { MovieListComponent } from './movie-list.component';
const routes: Routes = [
{ path: '', redirectTo: '/movies', pathMatch: 'full' },
{ path: 'movies', component: MovieListComponent }
];
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideProtractorTestingSupport(), // essential for e2e testing
],
};
@@ -1,51 +0,0 @@
div {
font-family:Arial, Helvetica, sans-serif;
margin:20px;
}
table {
font-family:Arial, Helvetica, sans-serif;
color:#666;
font-size:14px;
text-shadow: 1px 1px 0 #fff;
margin:20px;
border:#ccc 1px solid;
border-radius:3px;
}
table th {
padding:21px 25px 22px 25px;
border-top:1px solid #fafafa;
border-bottom:1px solid #e0e0e0;
border-left: 1px solid #e0e0e0;
font-weight: bold;
}
table th:first-child {
text-align: left;
padding-left:20px;
border-left: 0;
}
table tr {
text-align: center;
padding-left:20px;
}
table td:first-child {
text-align: left;
padding-left:20px;
border-left: 0;
}
table td {
padding:18px;
border-top: 1px solid #ffffff;
border-bottom:1px solid #e0e0e0;
border-left: 1px solid #e0e0e0;
}
table tr:last-child td {
border-bottom:0;
}
table tr:last-child td:first-child {
border-bottom-left-radius:3px;
}
table tr:last-child td:last-child {
border-bottom-right-radius:3px;
}
@@ -1,77 +0,0 @@
<!-- Filter the Movie Title -->
<div>
<h2>Movie List</h2>
<div>Who is your favorite hero?</div>
<div>
<!-- #docregion ngModel -->
<input [(ngModel)]="favoriteHero" />
<!-- #enddocregion ngModel -->
<!-- #docregion ngSwitch-->
<span [ngSwitch]="favoriteHero &&
checkMovieHero(favoriteHero)">
<p *ngSwitchCase="true">
Excellent choice!
</p>
<p *ngSwitchCase="false">
No movie, sorry!
</p>
<p *ngSwitchDefault>
Please enter your favorite hero.
</p>
</span>
<!-- #enddocregion ngSwitch-->
</div>
</div>
<!-- #docregion hidden -->
<h3 [hidden]="!favoriteHero">
<!-- #docregion interpolation -->
Your favorite hero is: {{favoriteHero}}
<!-- #enddocregion interpolation -->
</h3>
<!-- #enddocregion hidden -->
<div>
<!-- #docregion ngIf -->
<table *ngIf="movies.length">
<!-- #enddocregion ngIf -->
<thead>
<tr>
<th>
<button type="button" (click)="toggleImage()">
{{showImage ? "Hide" : "Show"}} Poster
</button>
</th>
<th>Title</th>
<th>Hero</th>
<th>Release Date</th>
<th>Rating</th>
<th>Price</th>
<th>Star rating</th>
<th>Approval rating</th>
</tr>
</thead>
<tbody>
<!-- #docregion ngFor -->
<tr *ngFor="let movie of movies">
<!-- #enddocregion ngFor -->
<td>
<img [hidden]="!showImage || !movie.imageurl"
[style.height.px]="50"
[style.margin.px]="2"
[src]="movie.imageurl"
[alt]="movie.title"
[title]="movie.title">
</td>
<td>{{movie.title}}</td>
<td>{{movie.hero}}</td>
<td>{{movie.releaseDate | date}}</td>
<td>{{movie.mpaa | uppercase}}</td>
<td>{{movie.price | currency:'USD':true}}</td>
<td>{{movie.starRating | number:'1.1-2'}}</td>
<td>{{movie.approvalRating | percent: '1.0-0'}}</td>
</tr>
</tbody>
</table>
</div>
@@ -1,51 +0,0 @@
// #docplaster
import { Component } from '@angular/core';
import {
NgFor, NgIf, NgSwitch, NgSwitchCase, NgSwitchDefault,
CurrencyPipe, DatePipe, DecimalPipe, PercentPipe, UpperCasePipe
} from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IMovie } from './movie';
import { MovieService } from './movie.service';
// #docregion component
@Component({
standalone: true,
selector: 'app-movie-list',
templateUrl: './movie-list.component.html',
imports: [
FormsModule,
NgFor, NgIf, NgSwitch, NgSwitchCase, NgSwitchDefault,
CurrencyPipe, DatePipe, DecimalPipe, PercentPipe, UpperCasePipe
],
// #docregion style-url
styleUrls: [ './movie-list.component.css' ],
// #enddocregion style-url
})
// #enddocregion component
// #docregion class
export class MovieListComponent {
// #enddocregion class
favoriteHero: string | undefined;
showImage = false;
movies: IMovie[];
// #docregion di
constructor(movieService: MovieService) {
// #enddocregion di
this.movies = movieService.getMovies();
// #docregion di
}
// #enddocregion di
toggleImage(): void {
this.showImage = !this.showImage;
}
checkMovieHero(value: string): boolean {
return this.movies.filter(movie => movie.hero === value).length > 0 ;
}
// #docregion class
}
// #enddocregion class

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